Ejemplo n.º 1
0
void Entity::attack(Entity* target)
{
  if (!target) {
    debugmsg("'%s' attempted attack() on a null target.");
    return;
  }

  Attack att = std_attack();

  action_points -= att.speed;

  bool you_see = GAME.player->can_sense(GAME.map, posx, posy);
  bool attacker_is_you = is_you();

  std::string miss_verb = (attacker_is_you ? "miss" : "misses");

  if (hit_roll(att.to_hit) < target->dodge_roll()) {
    if (you_see) {
      std::stringstream msg;
      msg << get_name_to_player() << " " << miss_verb << " " <<
             target->get_name_to_player() << "!";
      GAME.add_msg( msg.str().c_str() );
    }
// TODO: action_point penalty for missing?
    return;
  }

  Body_part bp_hit = (target->is_player() ? random_body_part_to_hit() :
                                            BODYPART_NULL);

// TODO: Should total_damage be reduced by damage absorbed by armor?
  Damage_set damage = att.roll_damage();
  for (int i = 0; i < DAMAGE_MAX; i++) {
    int dam = damage.get_damage(i);
    target->take_damage(Damage_type(i), dam, get_name_to_player(), bp_hit);
  }

  if (you_see) {
    std::stringstream damage_ss;
    damage_ss << get_name_to_player() << " ";
    if (attacker_is_you) {
      damage_ss << att.verb_first;
    } else {
      damage_ss << att.verb_third;
    }
    damage_ss << " ";
    if (bp_hit == BODYPART_NULL) {
      damage_ss << target->get_name_to_player();
    } else {
      damage_ss << target->get_possessive() << " " << body_part_name(bp_hit);
    }
    if (target->is_you()) {
      damage_ss << " for " << damage.total_damage() << " damage";
    }
    damage_ss << "!";
    GAME.add_msg( damage_ss.str().c_str() );
  }
}
Ejemplo n.º 2
0
void Game::launch_projectile(Item it, Ranged_attack attack,
                             Point origin, Point target)
{
  int range = rl_dist(origin, target);
  int angle_missed_by = attack.roll_variance();
// Use 1800 since attack.variance is measured in 10ths of a degree
  double distance_missed_by = range * tan(angle_missed_by * PI / 1800);
  int tiles_off = int(distance_missed_by);
  if (tiles_off >= 1) {
    target.x += rng(0 - tiles_off, tiles_off);
    target.y += rng(0 - tiles_off, tiles_off);
  }
// fine_distance is used later to see if we hit the target or "barely missed"
  int fine_distance = 100 * (distance_missed_by - tiles_off);
  debugmsg("angle %d, missed %f, tiles %d, fine %d", angle_missed_by, distance_missed_by, tiles_off, fine_distance);

  std::vector<Point> path = map->line_of_sight(origin, target);
  if (path.empty()) { // Lost line of sight at some point
    path = line_to(origin, target);
  }

  for (int i = 0; i < path.size(); i++) {
    if (map->move_cost(path[i].x, path[i].y) == 0) {
// It's a solid tile, so let's try to smash through it!
      map->smash(path[i].x, path[i].y, attack.roll_damage(), false);
      if (map->move_cost(path[i].x, path[i].y) == 0) {
        return; // We didn't make it!
      }
    } else {
      Entity* entity_hit = entities.entity_at(path[i].x, path[i].y);
      if (entity_hit) {
        bool hit;
// TODO: Incorporate the size of the monster
        if (i == path.size() - 1) {
          hit = rng(0, 100) >= fine_distance;
        } else {
          hit = one_in(3);
        }
        if (hit) {
          add_msg("You shoot %s!", entity_hit->get_name_to_player().c_str());
          Damage_set dam = attack.roll_damage();
          entity_hit->take_damage(DAMAGE_PIERCE, dam.get_damage(DAMAGE_PIERCE),
                                  "you");
          return;
        } else if (i == path.size() - 1) {
          add_msg("You barely miss %s.",
                  entity_hit->get_name_to_player().c_str());
        }
      }
    }
  }
}