示例#1
0
int monster::turns_to_reach(int x, int y)
{
    std::vector<point> path = g->m.route(posx(), posy(), x, y, has_flag(MF_BASHES));
    if (path.size() == 0)
        return 999;

    double turns = 0.;
    for (int i = 0; i < path.size(); i++) {
        if (g->m.move_cost(path[i].x, path[i].y) == 0) // We have to bash through
            turns += 5;
        else if (i == 0)
            turns += double(calc_movecost(posx(), posy(), path[i].x, path[i].y)) / speed;
        else
            turns += double(calc_movecost(path[i-1].x, path[i-1].y, path[i].x, path[i].y)) / speed;
    }
    return int(turns + .9); // Round up
}
示例#2
0
void monster::move_to(game *g, int x, int y)
{
 int mondex = g->mon_at(x, y);
 if (mondex == -1) { //...assuming there's no monster there
  if (has_effect(ME_BEARTRAP)) {
   moves = 0;
   return;
  }
  
  if (plans.size() > 0)
   plans.erase(plans.begin());

  moves -= calc_movecost(g, posx, posy, x, y);

  if (has_flag(MF_SLUDGETRAIL)){
   g->m.add_field(g, posx, posy, fd_sludge, 3);
   g->m.add_field(g, posx+1, posy, fd_sludge, 2);
   g->m.add_field(g, posx, posy+1, fd_sludge, 2);
   g->m.add_field(g, posx-1, posy, fd_sludge, 2);
   g->m.add_field(g, posx, posy-1, fd_sludge, 2);
  }

  posx = x;
  posy = y;
  footsteps(g, x, y);
  if (type->size != MS_TINY && g->m.has_flag(sharp, posx, posy) && !one_in(4))
     hurt(rng(2, 3));
  if (type->size != MS_TINY && g->m.has_flag(rough, posx, posy) && one_in(6))
     hurt(rng(1, 2));
  if (!has_flag(MF_DIGS) && !has_flag(MF_FLIES) &&
      g->m.tr_at(posx, posy) != tr_null) { // Monster stepped on a trap!
   trap* tr = g->traps[g->m.tr_at(posx, posy)];
   if (dice(3, type->sk_dodge + 1) < dice(3, tr->avoidance)) {
    trapfuncm f;
    (f.*(tr->actm))(g, this, posx, posy);
   }
  }
// Diggers turn the dirt into dirtmound
  if (has_flag(MF_DIGS)){
   g->m.ter_set(posx, posy, t_dirtmound);
  }
// Acid trail monsters leave... a trail of acid
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx, posy, fd_acid, 1);
  }
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx, posy, fd_acid, 1);
  }
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx, posy, fd_acid, 1);
  }

 } else if (has_flag(MF_ATTACKMON) || g->z[mondex].friendly != 0)
// If there IS a monster there, and we fight monsters, fight it!
  hit_monster(g, mondex);
}
示例#3
0
int monster::turns_to_reach(int x, int y)
{
    std::vector<point> path = g->m.route(posx(), posy(), x, y, false);
    if (path.empty())
        return 999;

    double turns = 0.;
    for (size_t i = 0; i < path.size(); i++) {
        if (g->m.move_cost(path[i].x, path[i].y) == 0) {
            // We have to bash through
            turns += 5;
        } else if (i == 0) {
            turns += double(calc_movecost(posx(), posy(), path[i].x, path[i].y)) / get_speed();
        } else {
            turns += double(calc_movecost(path[i-1].x, path[i-1].y, path[i].x, path[i].y)) / get_speed();
        }
    }
    return int(turns + .9); // Round up
}
示例#4
0
/* Random walking even when we've moved
 * To simulate zombie stumbling and ineffective movement
 * Note that this is sub-optimal; stumbling may INCREASE a zombie's speed.
 * Most of the time (out in the open) this effect is insignificant compared to
 * the negative effects, but in a hallway it's perfectly even
 */
void monster::stumble(bool moved)
{
// don't stumble every turn. every 3rd turn, or 8th when walking.
    if((moved && !one_in(8)) || !one_in(3))
    {
        return;
    }

    std::vector <point> valid_stumbles;
    for (int i = -1; i <= 1; i++) {
        for (int j = -1; j <= 1; j++) {
            const int nx = posx() + i;
            const int ny = posy() + j;
            if ((i || j) && can_move_to(nx, ny) &&
                    /* Don't ever stumble into impassable terrain, even if we normally could
                     * smash it, as this is uncoordinated movement (and is forced). */
                    g->m.move_cost(nx, ny) != 0 &&
                    //Stop zombies and other non-breathing monsters wandering INTO water
                    //(Unless they can swim/are aquatic)
                    //But let them wander OUT of water if they are there.
                    !(has_flag(MF_NO_BREATHE) && !has_flag(MF_SWIMS) && !has_flag(MF_AQUATIC)
                      && g->m.has_flag("SWIMMABLE", nx, ny)
                      && !g->m.has_flag("SWIMMABLE", posx(), posy())) &&
                    (g->u.posx != nx || g->u.posy != ny) &&
                    (g->mon_at(nx, ny) == -1)) {
                point tmp(nx, ny);
                valid_stumbles.push_back(tmp);
            }
        }
    }
    if (valid_stumbles.size() == 0) //nowhere to stumble?
    {
        return;
    }

    int choice = rng(0, valid_stumbles.size() - 1);
    int cx = valid_stumbles[choice].x;
    int cy = valid_stumbles[choice].y;

    moves -= calc_movecost(posx(), posy(), cx, cy);
    setpos(cx, cy);

// Here we have to fix our plans[] list,
// acquiring a new path to the previous target.
// target == either end of current plan, or the player.
    int tc;
    if (plans.size() > 0) {
        if (g->m.sees(posx(), posy(), plans.back().x, plans.back().y, -1, tc))
            set_dest(plans.back().x, plans.back().y, tc);
        else if (sees_player( tc ))
            set_dest(g->u.posx, g->u.posy, tc);
        else //durr, i'm suddenly calm. what was i doing?
            plans.clear();
    }
}
示例#5
0
int monster::turns_to_reach( int x, int y )
{
    // This function is a(n old) temporary hack that should soon be removed
    auto path = g->m.route( pos(), tripoint( x, y, posz() ), get_pathfinding_settings() );
    if( path.empty() ) {
        return 999;
    }

    double turns = 0.;
    for( size_t i = 0; i < path.size(); i++ ) {
        const tripoint &next = path[i];
        if( g->m.impassable( next ) ) {
            // No bashing through, it looks stupid when you go back and find
            // the doors intact.
            return 999;
        } else if( i == 0 ) {
            turns += double( calc_movecost( pos(), next ) ) / get_speed();
        } else {
            turns += double( calc_movecost( path[i - 1], next ) ) / get_speed();
        }
    }

    return int( turns + .9 ); // Halve (to get turns) and round up
}
示例#6
0
/* Random walking even when we've moved
 * To simulate zombie stumbling and ineffective movement
 * Note that this is sub-optimal; stumbling may INCREASE a zombie's speed.
 * Most of the time (out in the open) this effect is insignificant compared to
 * the negative effects, but in a hallway it's perfectly even
 */
void monster::stumble(game *g, bool moved)
{
 // don't stumble every turn. every 3rd turn, or 8th when walking.
 if((moved && !one_in(8)) || !one_in(3))
 {
     return;
 }

 std::vector <point> valid_stumbles;
 for (int i = -1; i <= 1; i++) {
  for (int j = -1; j <= 1; j++) {
   if (can_move_to(g, posx + i, posy + j) &&
       (g->u.posx != posx + i || g->u.posy != posy + j) &&
       (g->mon_at(posx + i, posy + j) == -1 || (i == 0 && j == 0))) {
    point tmp(posx + i, posy + j);
    valid_stumbles.push_back(tmp);
   }
  }
 }
 if (valid_stumbles.size() == 0) //nowhere to stumble?
 {
     return;
 }

 int choice = rng(0, valid_stumbles.size() - 1);
 int cx = valid_stumbles[choice].x;
 int cy = valid_stumbles[choice].y;

 moves -= calc_movecost(g, posx, posy, cx, cy);
 posx = cx;
 posy = cy;

 // Here we have to fix our plans[] list,
 // acquiring a new path to the previous target.
 // target == either end of current plan, or the player.
 int tc;
 if (plans.size() > 0) {
  if (g->m.sees(posx, posy, plans.back().x, plans.back().y, -1, tc))
   set_dest(plans.back().x, plans.back().y, tc);
  else if (g->sees_u(posx, posy, tc))
   set_dest(g->u.posx, g->u.posy, tc);
  else //durr, i'm suddenly calm. what was i doing?
   plans.clear();
 }
}
示例#7
0
int monster::move_to(int x, int y, bool force)
{
    // Make sure that we can move there, unless force is true.
    if(!force) if(!g->is_empty(x, y) || !can_move_to(x, y)) {
            return 0;
        }

    if (has_effect("beartrap")) {
        moves = 0;
        return 0;
    }

    if (plans.size() > 0) {
        plans.erase(plans.begin());
    }

    if (!force) {
        moves -= calc_movecost(posx(), posy(), x, y);
    }

    //Check for moving into/out of water
    bool was_water = g->m.is_divable(posx(), posy());
    bool will_be_water = g->m.is_divable(x, y);

    if(was_water && !will_be_water && g->u_see(x, y)) {
        //Use more dramatic messages for swimming monsters
        g->add_msg(_("A %s %s from the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("leaps") : _("emerges"),
                   g->m.tername(posx(), posy()).c_str());
    } else if(!was_water && will_be_water && g->u_see(x, y)) {
        g->add_msg(_("A %s %s into the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("dives") : _("sinks"),
                   g->m.tername(x, y).c_str());
    }

    setpos(x, y);
    footsteps(x, y);
    if(is_hallucination()) {
        //Hallucinations don't do any of the stuff after this point
        return 1;
    }
    if (type->size != MS_TINY && g->m.has_flag("SHARP", posx(), posy()) && !one_in(4)) {
        hurt(rng(2, 3));
    }
    if (type->size != MS_TINY && g->m.has_flag("ROUGH", posx(), posy()) && one_in(6)) {
        hurt(rng(1, 2));
    }
    if (!digging() && !has_flag(MF_FLIES) &&
            g->m.tr_at(posx(), posy()) != tr_null) { // Monster stepped on a trap!
        trap* tr = g->traps[g->m.tr_at(posx(), posy())];
        if (dice(3, type->sk_dodge + 1) < dice(3, tr->avoidance)) {
            trapfuncm f;
            (f.*(tr->actm))(this, posx(), posy());
        }
    }
    // Diggers turn the dirt into dirtmound
    if (digging()) {
        int factor = 0;
        switch (type->size) {
        case MS_TINY:
            factor = 100;
            break;
        case MS_SMALL:
            factor = 30;
            break;
        case MS_MEDIUM:
            factor = 6;
            break;
        case MS_LARGE:
            factor = 3;
            break;
        case MS_HUGE:
            factor = 1;
            break;
        }
        if (has_flag(MF_VERMIN)) {
            factor *= 100;
        }
        if (one_in(factor)) {
            g->m.ter_set(posx(), posy(), t_dirtmound);
        }
    }
    // Acid trail monsters leave... a trail of acid
    if (has_flag(MF_ACIDTRAIL)) {
        g->m.add_field(posx(), posy(), fd_acid, 3);
    }

    if (has_flag(MF_SLUDGETRAIL)) {
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                const int fstr = 3 - (abs(dx) + abs(dy));
                if (fstr >= 2) {
                    g->m.add_field(posx() + dx, posy() + dy, fd_sludge, fstr);
                }
            }
        }
    }

    return 1;
}
示例#8
0
int monster::move_to(game *g, int x, int y, bool force)
{
  // Make sure that we can move there, unless force is true.
  if(!force) if(!g->is_empty(x, y) || !can_move_to(g, x, y)) {
      return 0;
  }

  if (has_effect(ME_BEARTRAP)) {
   moves = 0;
   return 0;
  }

  if (plans.size() > 0)
   plans.erase(plans.begin());

  moves -= calc_movecost(g, posx(), posy(), x, y);

  if (has_flag(MF_SLUDGETRAIL)) {
    for (int dx = -1; dx <= 1; dx++) {
      for (int dy = -1; dy <= 1; dy++) {
        const int fstr = 3 - (abs(dx) + abs(dy));
        if (fstr >= 2) {
          g->m.add_field(g, posx() + dx, posy() + dy, fd_sludge, fstr);
        }
      }
    }
  }

  //Check for moving into/out of water
  bool was_water = g->m.is_divable(posx(), posy());
  bool will_be_water = g->m.is_divable(x, y);

  if(was_water && !will_be_water && g->u_see(x, y)) {
    //Use more dramatic messages for swimming monsters
    g->add_msg(_("A %s %s from the %s!"), name().c_str(),
            has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("leaps") : _("emerges"),
            g->m.tername(posx(), posy()).c_str());
  } else if(!was_water && will_be_water && g->u_see(x, y)) {
    g->add_msg(_("A %s %s into the %s!"), name().c_str(),
            has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("dives") : _("sinks"),
            g->m.tername(x, y).c_str());
  }

  setpos(x, y);
  footsteps(g, x, y);
  if(is_hallucination()) {
    //Hallucinations don't do any of the stuff after this point
    return 1;
  }
  if (type->size != MS_TINY && g->m.has_flag(sharp, posx(), posy()) && !one_in(4))
     hurt(rng(2, 3));
  if (type->size != MS_TINY && g->m.has_flag(rough, posx(), posy()) && one_in(6))
     hurt(rng(1, 2));
  if (!has_flag(MF_DIGS) && !has_flag(MF_FLIES) &&
      g->m.tr_at(posx(), posy()) != tr_null) { // Monster stepped on a trap!
   trap* tr = g->traps[g->m.tr_at(posx(), posy())];
   if (dice(3, type->sk_dodge + 1) < dice(3, tr->avoidance)) {
    trapfuncm f;
    (f.*(tr->actm))(g, this, posx(), posy());
   }
  }
// Diggers turn the dirt into dirtmound
  if (has_flag(MF_DIGS)){
   g->m.ter_set(posx(), posy(), t_dirtmound);
  }
// Acid trail monsters leave... a trail of acid
  //Why is this being done three times?
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx(), posy(), fd_acid, 1);
  }
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx(), posy(), fd_acid, 1);
  }
  if (has_flag(MF_ACIDTRAIL)){
   g->m.add_field(g, posx(), posy(), fd_acid, 1);
  }

  return 1;
}
示例#9
0
int monster::move_to(int x, int y, bool force)
{
    // Make sure that we can move there, unless force is true.
    if(!force) if(!g->is_empty(x, y) || !can_move_to(x, y)) {
        return 0;
    }

    if (!plans.empty()) {
        plans.erase(plans.begin());
    }

    if (!force) {
        moves -= calc_movecost(posx(), posy(), x, y);
    }

    //Check for moving into/out of water
    bool was_water = g->m.is_divable(posx(), posy());
    bool will_be_water = !has_flag( MF_FLIES ) && can_submerge() && g->m.is_divable(x, y);

    if(was_water && !will_be_water && g->u.sees(x, y)) {
        //Use more dramatic messages for swimming monsters
        add_msg(m_warning, _("A %s %s from the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("leaps") : _("emerges"),
                   g->m.tername(posx(), posy()).c_str());
    } else if(!was_water && will_be_water && g->u.sees(x, y)) {
        add_msg(m_warning, _("A %s %s into the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("dives") : _("sinks"),
                   g->m.tername(x, y).c_str());
    }

    setpos(x, y);
    footsteps(x, y);
    underwater = will_be_water;
    if(is_hallucination()) {
        //Hallucinations don't do any of the stuff after this point
        return 1;
    }
    if (type->size != MS_TINY && g->m.has_flag("SHARP", posx(), posy()) && !one_in(4)) {
        apply_damage( nullptr, bp_torso, rng( 2, 3 ) );
    }
    if (type->size != MS_TINY && g->m.has_flag("ROUGH", posx(), posy()) && one_in(6)) {
        apply_damage( nullptr, bp_torso, rng( 1, 2 ) );
    }
    if (g->m.has_flag("UNSTABLE", x, y)) {
        add_effect("bouldering", 1, num_bp, true);
    } else if (has_effect("bouldering")) {
        remove_effect("bouldering");
    }
    if (!digging() && !has_flag(MF_FLIES) &&
          g->m.tr_at(posx(), posy()) != tr_null) { // Monster stepped on a trap!
        trap* tr = traplist[g->m.tr_at(posx(), posy())];
        if (dice(3, type->sk_dodge + 1) < dice(3, tr->get_avoidance())) {
            tr->trigger(this, posx(), posy());
        }
    }
    if( !will_be_water && ( has_flag(MF_DIGS) || has_flag(MF_CAN_DIG) ) ) {
        underwater = g->m.has_flag("DIGGABLE", posx(), posy() );
    }
    // Diggers turn the dirt into dirtmound
    if (digging()){
        int factor = 0;
        switch (type->size) {
        case MS_TINY:
            factor = 100;
            break;
        case MS_SMALL:
            factor = 30;
            break;
        case MS_MEDIUM:
            factor = 6;
            break;
        case MS_LARGE:
            factor = 3;
            break;
        case MS_HUGE:
            factor = 1;
            break;
        }
        if (has_flag(MF_VERMIN)) {
            factor *= 100;
        }
        if (one_in(factor)) {
            g->m.ter_set(posx(), posy(), t_dirtmound);
        }
    }
    // Acid trail monsters leave... a trail of acid
    if (has_flag(MF_ACIDTRAIL)){
        g->m.add_field(posx(), posy(), fd_acid, 3);
    }

    if (has_flag(MF_SLUDGETRAIL)) {
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                const int fstr = 3 - (abs(dx) + abs(dy));
                if (fstr >= 2) {
                    g->m.add_field(posx() + dx, posy() + dy, fd_sludge, fstr);
                }
            }
        }
    }
    if (has_flag(MF_LEAKSGAS)){
        if (one_in(6)){
        g->m.add_field(posx() + rng(-1,1), posy() + rng(-1, 1), fd_toxic_gas, 3);
        }
    }

    return 1;
}
示例#10
0
bool monster::move_to( const tripoint &p, bool force, const float stagger_adjustment )
{
    const bool digs = digging();
    const bool flies = has_flag( MF_FLIES );
    const bool on_ground = !digs && !flies;
    const bool climbs = has_flag( MF_CLIMBS ) && g->m.has_flag( TFLAG_NO_FLOOR, p );
    // Allows climbing monsters to move on terrain with movecost <= 0
    Creature *critter = g->critter_at( p, is_hallucination() );
    if( g->m.has_flag( "CLIMBABLE", p ) ) {
        if( g->m.impassable( p ) && critter == nullptr ) {
            if( flies ) {
                moves -= 100;
                force = true;
                if( g->u.sees( *this ) ) {
                    add_msg( _( "The %1$s flies over the %2$s." ), name().c_str(),
                             g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() :
                             g->m.tername( p ).c_str() );
                }
            } else if( has_flag( MF_CLIMBS ) ) {
                moves -= 150;
                force = true;
                if( g->u.sees( *this ) ) {
                    add_msg( _( "The %1$s climbs over the %2$s." ), name().c_str(),
                             g->m.has_flag_furn( "CLIMBABLE", p ) ? g->m.furnname( p ).c_str() :
                             g->m.tername( p ).c_str() );
                }
            }
        }
    }

    if( critter != nullptr && !force ) {
        return false;
    }

    // Make sure that we can move there, unless force is true.
    if( !force && !can_move_to( p ) ) {
        return false;
    }

    if( !force ) {
        // This adjustment is to make it so that monster movement speed relative to the player
        // is consistent even if the monster stumbles,
        // and the same regardless of the distance measurement mode.
        const int cost = stagger_adjustment *
                         ( float )( climbs ? calc_climb_cost( pos(), p ) :
                                    calc_movecost( pos(), p ) );

        if( cost > 0 ) {
            moves -= cost;
        } else {
            return false;
        }
    }

    //Check for moving into/out of water
    bool was_water = g->m.is_divable( pos() );
    bool will_be_water = on_ground && can_submerge() && g->m.is_divable( p );

    if( was_water && !will_be_water && g->u.sees( p ) ) {
        //Use more dramatic messages for swimming monsters
        add_msg( m_warning, _( "A %1$s %2$s from the %3$s!" ), name().c_str(),
                 has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "leaps" ) : _( "emerges" ),
                 g->m.tername( pos() ).c_str() );
    } else if( !was_water && will_be_water && g->u.sees( p ) ) {
        add_msg( m_warning, _( "A %1$s %2$s into the %3$s!" ), name().c_str(),
                 has_flag( MF_SWIMS ) || has_flag( MF_AQUATIC ) ? _( "dives" ) : _( "sinks" ),
                 g->m.tername( p ).c_str() );
    }

    setpos( p );
    footsteps( p );
    underwater = will_be_water;
    if( is_hallucination() ) {
        //Hallucinations don't do any of the stuff after this point
        return true;
    }
    // TODO: Make tanks stop taking damage from rubble, because it's just silly
    if( type->size != MS_TINY && on_ground ) {
        if( g->m.has_flag( "SHARP", pos() ) && !one_in( 4 ) ) {
            apply_damage( nullptr, bp_torso, rng( 1, 10 ) );
        }
        if( g->m.has_flag( "ROUGH", pos() ) && one_in( 6 ) ) {
            apply_damage( nullptr, bp_torso, rng( 1, 2 ) );
        }

    }

    if( g->m.has_flag( "UNSTABLE", p ) && on_ground ) {
        add_effect( effect_bouldering, 1, num_bp, true );
    } else if( has_effect( effect_bouldering ) ) {
        remove_effect( effect_bouldering );
    }
    g->m.creature_on_trap( *this );
    if( !will_be_water && ( has_flag( MF_DIGS ) || has_flag( MF_CAN_DIG ) ) ) {
        underwater = g->m.has_flag( "DIGGABLE", pos() );
    }
    // Diggers turn the dirt into dirtmound
    if( digging() ) {
        int factor = 0;
        switch( type->size ) {
            case MS_TINY:
                factor = 100;
                break;
            case MS_SMALL:
                factor = 30;
                break;
            case MS_MEDIUM:
                factor = 6;
                break;
            case MS_LARGE:
                factor = 3;
                break;
            case MS_HUGE:
                factor = 1;
                break;
        }
        if( one_in( factor ) ) {
            g->m.ter_set( pos(), t_dirtmound );
        }
    }
    // Acid trail monsters leave... a trail of acid
    if( has_flag( MF_ACIDTRAIL ) ) {
        g->m.add_field( pos(), fd_acid, 3, 0 );
    }

    if( has_flag( MF_SLUDGETRAIL ) ) {
        for( const tripoint &sludge_p : g->m.points_in_radius( pos(), 1 ) ) {
            const int fstr = 3 - ( abs( sludge_p.x - posx() ) + abs( sludge_p.y - posy() ) );
            if( fstr >= 2 ) {
                g->m.add_field( sludge_p, fd_sludge, fstr, 0 );
            }
        }
    }

    return true;
}