Logo Search packages:      
Sourcecode: wesnoth version File versions

bool unit_display::unit_attack ( display &  disp,
unit_map &  units,
const gamemap &  map,
const gamemap::location &  a,
const gamemap::location &  b,
int  damage,
const attack_type &  attack 
)

a function to make the unit on tile 'a' attack the unit on tile 'b'. the 'damage' will be subtracted from the unit's hitpoints, and a die effect will be displayed if the unit dies. true is returned if the defending unit is dead, and should be removed from the playing field.

Definition at line 629 of file unit_display.cpp.

References util::scoped_resource< T, ReleasePolicy >::assign(), image::get_image(), image::reverse_image(), and unit_die().

{
      const bool hide = disp.update_locked() || disp.fogged(a.x,a.y) && disp.fogged(b.x,b.y)
                        || preferences::show_combat() == false;

      if(!hide) {
            int xloc = disp.get_location_x(a);
            int yloc = disp.get_location_y(a);

            //we try to scroll the map if the unit is at the edge.
            //keep track of the old position, and if the map moves at all,
            //then recenter it on the unit
            adjust_map_position(disp, xloc, yloc, disp.hex_size(), disp.hex_size());

            if(xloc != disp.get_location_x(a) || yloc != disp.get_location_y(a)) {
                  disp.scroll_to_tile(a.x,a.y,display::WARP);
            }
      }

      log_scope("unit_attack");

      const unit_map::iterator att = units.find(a);
      wassert(att != units.end());

      unit& attacker = att->second;

      const unit_map::iterator def = units.find(b);
      wassert(def != units.end());

      if(b.x > a.x) {
            att->second.set_facing_left(true);
            def->second.set_facing_left(false);
      } else if(b.x < a.x) {
            att->second.set_facing_left(false);
            def->second.set_facing_left(true);
      }

      if(attack.range() == attack_type::LONG_RANGE) {
            return unit_attack_ranged(disp, units, a, b, damage, attack);
      }

      unit_animation attack_anim = attack.animation(get_adjacent_direction(a,b));

      const bool hits = damage > 0;
      const std::vector<unit_animation::sfx>& sounds = attack_anim.sound_effects();
      std::vector<unit_animation::sfx>::const_iterator sfx_it = sounds.begin();

      const std::string& hit_sound = def->second.type().get_hit_sound();
      bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
      const int play_hit_sound_at = 0;

      const int time_resolution = 20;
      const int acceleration = disp.turbo() ? 5 : 1;

      const gamemap::location leader_loc = under_leadership(units,a);
      unit_map::iterator leader = units.end();
      if(leader_loc.valid()){
            LOG_DP << "found leader at " << (leader_loc.x+1) << "," << (leader_loc.y+1) << "\n";
            leader = units.find(leader_loc);
            wassert(leader != units.end());
            leader->second.set_leading(true);
      }

      const int begin_at = minimum<int>(-200,attack_anim.get_first_frame_time());
      const int end_at = maximum<int>((damage+1)*time_resolution,
                                             maximum<int>(200,attack_anim.get_last_frame_time()));

      const double xsrc = disp.get_location_x(a);
      const double ysrc = disp.get_location_y(a);
      const double xdst = disp.get_location_x(b)*0.6 + xsrc*0.4;
      const double ydst = disp.get_location_y(b)*0.6 + ysrc*0.4;

      gamemap::location update_tiles[6];
      get_adjacent_tiles(b,update_tiles);

      bool dead = false;
      const int drain_speed = 1*acceleration;

      int flash_num = 0;

      int ticks = SDL_GetTicks();

      disp.hide_unit(a);

      const gamemap::TERRAIN src_terrain = map.get_terrain(a);
      const gamemap::TERRAIN dst_terrain = map.get_terrain(b);

      const double src_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_height_adjust() * disp.zoom();
      const double dst_height_adjust = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_height_adjust() * disp.zoom();

      const double src_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(src_terrain).unit_submerge();
      const double dst_submerge = attacker.is_flying() ? 0 : map.get_terrain_info(dst_terrain).unit_submerge();

      bool shown_label = false;

      util::scoped_resource<int,halo::remover> halo_effect(0);
      const std::string* halo_image = NULL;
      int halo_x = -1, halo_y = -1;

      attack_anim.start_animation(begin_at, unit_animation::UNIT_FRAME, acceleration);

      int animation_time = attack_anim.get_animation_time();

      def->second.set_defending(hits, attack_type::SHORT_RANGE, animation_time, acceleration);

      while(animation_time < end_at) {

            //this is a while instead of an if, because there might be multiple
            //sounds playing simultaneously or close together
            while(!hide && sfx_it != sounds.end() && animation_time >= sfx_it->time) {
                  const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
                  if(sfx.empty() == false) {
                        sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
                  }

                  ++sfx_it;
            }

            if(!hide && hits && !played_hit_sound && animation_time >= play_hit_sound_at) {
                  sound::play_sound(hit_sound);
                  played_hit_sound = true;
            }

            for(int j = 0; j != 6; ++j) {
                  disp.draw_tile(update_tiles[j].x,update_tiles[j].y);
            }

            Uint32 defender_colour = 0;
            fixed_t defender_alpha = ftofxp(1.0);

            if(damage > 0 && animation_time >= 0 && shown_label == false) {
                  shown_label = true;
                  disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
            }

            if(damage > 0 && animation_time >= 0) {
                  if(def->second.gets_hit(minimum<int>(drain_speed,damage))) {
                        dead = true;
                        damage = 0;
                  } else {
                        damage -= drain_speed;
                  }

                  if(flash_num == 0 || flash_num == 2) {
                        defender_alpha = ftofxp(0.0);
                        defender_colour = disp.rgb(200,0,0);
                  }

                  ++flash_num;
            }

            disp.draw_tile(b.x,b.y,NULL,defender_alpha,defender_colour);
            if(leader_loc.valid()) {
                  disp.draw_tile(leader_loc.x,leader_loc.y);
            }


            int xoffset = 0;

            const unit_animation::frame& unit_frame = attack_anim.get_current_frame(unit_animation::UNIT_FRAME);
            int new_halo_x = unit_frame.halo_x;
            int new_halo_y = unit_frame.halo_y;
            const std::string& unit_image = unit_frame.image.empty() ? attacker.image() : unit_frame.image;

            if(!attacker.facing_left()) {
                  xoffset *= -1;
                  new_halo_x *= -1;
            }

            new_halo_x = int(new_halo_x*disp.zoom());

            xoffset = int(double(xoffset)*disp.zoom());

            surface image(image::get_image(unit_image));
            if(attacker.facing_left() == false) {
                  image.assign(image::reverse_image(image));
            }

            const double pos = double(animation_time)/double(animation_time < 0 ? begin_at : end_at);
            const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
            const int posy = int(pos*ysrc + (1.0-pos)*ydst);

            const int halo_xpos = posx+disp.hex_size()/2;
            const int halo_ypos = posy+disp.hex_size()/2;

            if(&unit_frame.halo != halo_image ||
                        new_halo_x != halo_x ||
                        new_halo_y != halo_y) {
                  halo_image = &unit_frame.halo;
                  halo_x = new_halo_x;
                  halo_y = new_halo_y;

                  if(!unit_frame.halo.empty() && 
                              (!disp.fogged(b.x,b.y) || !disp.fogged(a.x,a.y))) {
                        halo_effect.assign(halo::add(halo_xpos,halo_ypos,*halo_image));
                  } else {
                        halo_effect.assign(0);
                  }
            }

            else if(halo_effect != 0) {
                  halo::set_location(halo_effect,halo_xpos,halo_ypos);
            }

            const int height_adjust = int(src_height_adjust*pos + dst_height_adjust*(1.0-pos));
            const double submerge = src_submerge*pos + dst_submerge*(1.0-pos);

            if(image != NULL && !hide) {
                  disp.draw_unit(posx, posy - height_adjust, image, false, ftofxp(1.0), 0, 0.0, submerge);
            }

            const int wait_time = ticks + time_resolution - SDL_GetTicks();
            if(wait_time > 0 && !hide) {
                  SDL_Delay(wait_time);
            }

            ticks = SDL_GetTicks();

            attack_anim.update_current_frames();
            def->second.update_defending_frame();
            animation_time = attack_anim.get_animation_time();
            events::pump();
            disp.update_display();
      }

      halo_effect.assign(0);

      if(damage > 0 && shown_label == false) {
            shown_label = true;
            disp.float_label(b,lexical_cast<std::string>(damage),255,0,0);
      }

      disp.hide_unit(gamemap::location());

      if(damage > 0 && def->second.gets_hit(damage)) {
            dead = true;
            damage = 0;
      }

      if(leader_loc.valid()){
            leader->second.set_leading(false);
      }

      disp.invalidate(a);
      disp.invalidate(b);
      if(leader_loc.valid()) {
            disp.draw_tile(leader_loc.x,leader_loc.y);
      }

      def->second.set_standing();

      if(dead) {
            unit_display::unit_die(disp,def->first,def->second,&attack);
      }

      return dead;
}


Generated by  Doxygen 1.6.0   Back to index