Exemplo n.º 1
0
void monster::process_effects()
{
    for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) {
        std::string id = effect_it->second.get_id();
        if (id == "nasty_poisoned") {
            mod_speed_bonus( -rng(3, 5) );
            apply_damage( nullptr, bp_torso, rng( 3, 6 ) );
        } if (id == "poisoned") {
            mod_speed_bonus( -rng(0, 3) );
            apply_damage( nullptr, bp_torso, rng( 1, 3 ) );

        // MATERIALS-TODO: use fire resistance
        } else if (id == "onfire") {
            if (made_of("flesh") || made_of("iflesh"))
                apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
            if (made_of("veggy"))
                apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
            if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                made_of("wool"))
                apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
        }
    }

    Creature::process_effects();
}
Exemplo n.º 2
0
dealt_damage_instance Creature::deal_damage(Creature *source, body_part bp,
        const damage_instance &dam)
{
    if( is_dead_state() ) {
        return dealt_damage_instance();
    }
    int total_damage = 0;
    int total_pain = 0;
    damage_instance d = dam; // copy, since we will mutate in absorb_hit

    dealt_damage_instance dealt_dams;

    absorb_hit(bp, d);

    // Add up all the damage units dealt
    for( const auto &it : d.damage_units ) {
        int cur_damage = 0;
        deal_damage_handle_type( it, bp, cur_damage, total_pain );
        if( cur_damage > 0 ) {
            dealt_dams.dealt_dams[ it.type ] += cur_damage;
            total_damage += cur_damage;
        }
    }

    mod_pain(total_pain);

    apply_damage( source, bp, total_damage );
    return dealt_dams;
}
Exemplo n.º 3
0
dealt_damage_instance Creature::deal_damage(Creature *source, body_part bp, int side,
                                            const damage_instance &dam)
{
    int total_damage = 0;
    int total_pain = 0;
    damage_instance d = dam; // copy, since we will mutate in absorb_hit

    std::vector<int> dealt_dams(NUM_DT, 0);

    absorb_hit(bp, side, d);

    // add up all the damage units dealt
    int cur_damage;
    for (std::vector<damage_unit>::const_iterator it = d.damage_units.begin();
         it != d.damage_units.end(); ++it) {
        cur_damage = 0;
        deal_damage_handle_type(*it, bp, cur_damage, total_pain);
        if (cur_damage > 0) {
            dealt_dams[it->type] += cur_damage;
            total_damage += cur_damage;
        }
    }

    mod_pain(total_pain);
    apply_damage(source, bp, side, total_damage);
    return dealt_damage_instance(dealt_dams);
}
Exemplo n.º 4
0
bool Unit::interact(Unit *target)
{
    // Verify that the Unit hasn't interacted already.
    if(interacted)
    {
        return false;
    }

    // Verify second is within range of first.
    if(!is_within_range(target))
    {
        return false;
    }

    // If this Unit is a healer, calculate heals. First verify target is friendly.
    if(type == HEALER)
    {
        if(player_id != target->get_player_id())
        {
            return false;
        }
        target->apply_heal();
        interacted = true;
        moved = true;
        return true;
    }

    // If we're not healing, verify the unit we're attacking isn't friendly.
    if(player_id == target->get_player_id())
    {
        return false;
    }

    // Note that this Unit can no longer move or interact.
    interacted = true;
    moved = true;

    // Let's see if it hits. There's a 25% chance of missing.
    if(rand() % 4 == 0)
    {
        // Even though we aren't applying damage, this was still a valid outcome.
        return true;
    }

    // Time to attack the target!
    target->apply_damage(this, false);

    // There's also a chance that the defender can counterattack.
    if(target->is_within_range(this) && target->get_type() != HEALER)
    {
        apply_damage(this, true);
    }

    // If we've gotten here, everything was successful!
    return true;
}
Exemplo n.º 5
0
void monster::add_eff_effects(effect e, bool reduced)
{
    int val = e.get_amount("HURT", reduced);
    if (val > 0) {
        if(e.activated(calendar::turn, "HURT", val, reduced)) {
            apply_damage(nullptr, bp_torso, val);
        }
    }
    Creature::add_eff_effects(e, reduced);
}
Exemplo n.º 6
0
void monster::process_effects()
{
    for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) {
        std::string id = effect_it->second.get_id();
        if (id == "nasty_poisoned") {
            mod_speed_bonus( -rng(3, 5) );
            apply_damage( nullptr, bp_torso, rng( 3, 6 ) );
        } if (id == "poisoned") {
            mod_speed_bonus( -rng(0, 3) );
            apply_damage( nullptr, bp_torso, rng( 1, 3 ) );

        // MATERIALS-TODO: use fire resistance
        } else if (id == "onfire") {
            if (made_of("flesh") || made_of("iflesh"))
                apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
            if (made_of("veggy"))
                apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
            if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                made_of("wool"))
                apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
        }
    }

    //If this monster has the ability to heal in combat, do it now.
    if( has_flag( MF_REGENERATES_50 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( this ) ) {
                add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() );
            }
            hp += 50;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }
    if( has_flag( MF_REGENERATES_10 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( this ) ) {
                add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() );
            }
            hp += 10;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }

    //Monster will regen morale and aggression if it is on max HP
    //It regens more morale and aggression if is currently fleeing.
    if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) {
        if( is_fleeing( g->u ) ) {
            morale = type->morale;
            anger = type->agro;
        }
        if( morale <= type->morale ) {
            morale += 1;
        }
        if( anger <= type->agro ) {
            anger += 1;
        }
        if( morale < 0 ) {
            morale += 5;
        }
        if( anger < 0 ) {
            anger += 5;
        }
    }

    // If this critter dies in sunlight, check & assess damage.
    if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) {
        if( g->u.sees( this ) ) {
            add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() );
        }
        hp -= 100;
        if( hp < 0 ) {
            hp = 0;
        }
    }

    Creature::process_effects();
}
Exemplo n.º 7
0
void monster::knock_back_from(int x, int y)
{
 if (x == posx() && y == posy())
  return; // No effect
    if( is_hallucination() ) {
        die( nullptr );
        return;
    }
 point to(posx(), posy());
 if (x < posx())
  to.x++;
 if (x > posx())
  to.x--;
 if (y < posy())
  to.y++;
 if (y > posy())
  to.y--;

 bool u_see = g->u.sees( to );

// First, see if we hit another monster
 int mondex = g->mon_at(to.x, to.y);
    if( mondex != -1 && g->zombie( mondex ).is_hallucination() ) {
        // hallucinations should not affect real monsters. If they interfer, just remove them.
        g->zombie( mondex ).die( this );
        mondex = -1;
    }
 if (mondex != -1) {
  monster *z = &(g->zombie(mondex));
  apply_damage( z, bp_torso, z->type->size );
  add_effect("stunned", 1);
  if (type->size > 1 + z->type->size) {
   z->knock_back_from(posx(), posy()); // Chain reaction!
   z->apply_damage( this, bp_torso, type->size );
   z->add_effect("stunned", 1);
  } else if (type->size > z->type->size) {
   z->apply_damage( this, bp_torso, type->size );
   z->add_effect("stunned", 1);
  }
  z->check_dead_state();

  if (u_see)
   add_msg(_("The %s bounces off a %s!"), name().c_str(), z->name().c_str());

  return;
 }

 int npcdex = g->npc_at(to.x, to.y);
 if (npcdex != -1) {
  npc *p = g->active_npc[npcdex];
  apply_damage( p, bp_torso, 3 );
  add_effect("stunned", 1);
  p->deal_damage( this, bp_torso, damage_instance( DT_BASH, type->size ) );
  if (u_see)
   add_msg(_("The %s bounces off %s!"), name().c_str(), p->name.c_str());

  p->check_dead_state();
  return;
 }

// If we're still in the function at this point, we're actually moving a tile!
 if (g->m.ter_at(to.x, to.y).has_flag(TFLAG_DEEP_WATER)) {
  if (g->m.has_flag("LIQUID", to.x, to.y) && can_drown()) {
   die( nullptr );
   if (u_see) {
    add_msg(_("The %s drowns!"), name().c_str());
   }

  } else if (has_flag(MF_AQUATIC)) { // We swim but we're NOT in water
   die( nullptr );
   if (u_see) {
    add_msg(_("The %s flops around and dies!"), name().c_str());
   }
  }
 }

 if (g->m.move_cost(to.x, to.y) == 0) {

   // It's some kind of wall.
   apply_damage( nullptr, bp_torso, type->size );
   add_effect("stunned", 2);
   if (u_see) {
    add_msg(_("The %s bounces off a %s."), name().c_str(),
               g->m.tername(to.x, to.y).c_str());
   }

 } else { // It's no wall
  setpos(to);
 }
    check_dead_state();
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
void monster::knock_back_from( const tripoint &p )
{
    if( p == pos() ) {
        return; // No effect
    }
    if( is_hallucination() ) {
        die( nullptr );
        return;
    }
    tripoint to = pos();;
    if( p.x < posx() ) {
        to.x++;
    }
    if( p.x > posx() ) {
        to.x--;
    }
    if( p.y < posy() ) {
        to.y++;
    }
    if( p.y > posy() ) {
        to.y--;
    }

    bool u_see = g->u.sees( to );

    // First, see if we hit another monster
    if( monster *const z = g->critter_at<monster>( to ) ) {
        apply_damage( z, bp_torso, z->type->size );
        add_effect( effect_stunned, 1 );
        if( type->size > 1 + z->type->size ) {
            z->knock_back_from( pos() ); // Chain reaction!
            z->apply_damage( this, bp_torso, type->size );
            z->add_effect( effect_stunned, 1 );
        } else if( type->size > z->type->size ) {
            z->apply_damage( this, bp_torso, type->size );
            z->add_effect( effect_stunned, 1 );
        }
        z->check_dead_state();

        if( u_see ) {
            add_msg( _( "The %1$s bounces off a %2$s!" ), name().c_str(), z->name().c_str() );
        }

        return;
    }

    if( npc *const p = g->critter_at<npc>( to ) ) {
        apply_damage( p, bp_torso, 3 );
        add_effect( effect_stunned, 1 );
        p->deal_damage( this, bp_torso, damage_instance( DT_BASH, type->size ) );
        if( u_see ) {
            add_msg( _( "The %1$s bounces off %2$s!" ), name().c_str(), p->name.c_str() );
        }

        p->check_dead_state();
        return;
    }

    // If we're still in the function at this point, we're actually moving a tile!
    if( g->m.has_flag_ter( TFLAG_DEEP_WATER, to ) ) {
        if( g->m.has_flag( "LIQUID", to ) && can_drown() ) {
            die( nullptr );
            if( u_see ) {
                add_msg( _( "The %s drowns!" ), name().c_str() );
            }

        } else if( has_flag( MF_AQUATIC ) ) { // We swim but we're NOT in water
            die( nullptr );
            if( u_see ) {
                add_msg( _( "The %s flops around and dies!" ), name().c_str() );
            }
        }
    }

    if( g->m.impassable( to ) ) {

        // It's some kind of wall.
        apply_damage( nullptr, bp_torso, type->size );
        add_effect( effect_stunned, 2 );
        if( u_see ) {
            add_msg( _( "The %1$s bounces off a %2$s." ), name().c_str(),
                     g->m.obstacle_name( to ).c_str() );
        }

    } else { // It's no wall
        setpos( to );
    }
    check_dead_state();
}
Exemplo n.º 11
0
void monster::process_effects()
{
    // Monster only effects
    int mod = 1;
    for( auto &elem : effects ) {
        for( auto &_effect_it : elem.second ) {
            auto &it = _effect_it.second;
            // Monsters don't get trait-based reduction, but they do get effect based reduction
            bool reduced = has_effect(it.get_resist_effect());

            mod_speed_bonus(it.get_mod("SPEED", reduced));

            int val = it.get_mod("HURT", reduced);
            if (val > 0) {
                if(it.activated(calendar::turn, "HURT", val, reduced, mod)) {
                    apply_damage(nullptr, bp_torso, val);
                }
            }

            std::string id = _effect_it.second.get_id();
            // MATERIALS-TODO: use fire resistance
            if (id == "onfire") {
                if (made_of("flesh") || made_of("iflesh"))
                    apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
                if (made_of("veggy"))
                    apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
                if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                    made_of("wool"))
                    apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
            }
        }
    }

    //If this monster has the ability to heal in combat, do it now.
    if( has_flag( MF_REGENERATES_50 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( *this ) ) {
                add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() );
            }
            hp += 50;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }
    if( has_flag( MF_REGENERATES_10 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( *this ) ) {
                add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() );
            }
            hp += 10;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }

    //Monster will regen morale and aggression if it is on max HP
    //It regens more morale and aggression if is currently fleeing.
    if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) {
        if( is_fleeing( g->u ) ) {
            morale = type->morale;
            anger = type->agro;
        }
        if( morale <= type->morale ) {
            morale += 1;
        }
        if( anger <= type->agro ) {
            anger += 1;
        }
        if( morale < 0 ) {
            morale += 5;
        }
        if( anger < 0 ) {
            anger += 5;
        }
    }

    // If this critter dies in sunlight, check & assess damage.
    if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) {
        if( g->u.sees( *this ) ) {
            add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() );
        }
        apply_damage( nullptr, bp_torso, 100 );
        if( hp < 0 ) {
            hp = 0;
        }
    }

    Creature::process_effects();
}
Exemplo n.º 12
0
// Why put this in a Big Switch?  Why not let bionics have pointers to
// functions, much like monsters and items?
//
// Well, because like diseases, which are also in a Big Switch, bionics don't
// share functions....
void player::activate_bionic(int b)
{
    bionic bio = my_bionics[b];
    int power_cost = bionics[bio.id]->power_cost;
    if ((weapon.type->id == "bio_claws_weapon" && bio.id == "bio_claws_weapon") ||
        (weapon.type->id == "bio_blade_weapon" && bio.id == "bio_blade_weapon")) {
        power_cost = 0;
    }
    if (power_level < power_cost) {
        if (my_bionics[b].powered) {
            add_msg(m_neutral, _("Your %s powers down."), bionics[bio.id]->name.c_str());
            my_bionics[b].powered = false;
        } else {
            add_msg(m_info, _("You cannot power your %s"), bionics[bio.id]->name.c_str());
        }
        return;
    }

    if (my_bionics[b].powered && my_bionics[b].charge > 0) {
        // Already-on units just lose a bit of charge
        my_bionics[b].charge--;
    } else {
        // Not-on units, or those with zero charge, have to pay the power cost
        if (bionics[bio.id]->charge_time > 0) {
            my_bionics[b].powered = true;
            my_bionics[b].charge = bionics[bio.id]->charge_time - 1;
        }
        power_level -= power_cost;
    }

    std::vector<point> traj;
    std::vector<std::string> good;
    std::vector<std::string> bad;
    int dirx, diry;
    item tmp_item;

    if(bio.id == "bio_painkiller") {
        pkill += 6;
        pain -= 2;
        if (pkill > pain) {
            pkill = pain;
        }
    } else if (bio.id == "bio_nanobots") {
        rem_disease("bleed");
        healall(4);
    } else if (bio.id == "bio_night") {
        if (calendar::turn % 5) {
            add_msg(m_neutral, _("Artificial night generator active!"));
        }
    } else if (bio.id == "bio_resonator") {
        g->sound(posx, posy, 30, _("VRRRRMP!"));
        for (int i = posx - 1; i <= posx + 1; i++) {
            for (int j = posy - 1; j <= posy + 1; j++) {
                g->m.bash( i, j, 40 );
                g->m.bash( i, j, 40 ); // Multibash effect, so that doors &c will fall
                g->m.bash( i, j, 40 );
                if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) {
                    g->m.ter_set(i, j, t_rubble);
                }
            }
        }
    } else if (bio.id == "bio_time_freeze") {
        moves += power_level;
        power_level = 0;
        add_msg(m_good, _("Your speed suddenly increases!"));
        if (one_in(3)) {
            add_msg(m_bad, _("Your muscles tear with the strain."));
            apply_damage( nullptr, bp_arm_l, rng( 5, 10 ) );
            apply_damage( nullptr, bp_arm_r, rng( 5, 10 ) );
            apply_damage( nullptr, bp_leg_l, rng( 7, 12 ) );
            apply_damage( nullptr, bp_leg_r, rng( 7, 12 ) );
            apply_damage( nullptr, bp_torso, rng( 5, 15 ) );
        }
        if (one_in(5)) {
            add_disease("teleglow", rng(50, 400));
        }
    } else if (bio.id == "bio_teleport") {
        g->teleport();
        add_disease("teleglow", 300);
    }
    // TODO: More stuff here (and bio_blood_filter)
    else if(bio.id == "bio_blood_anal") {
        WINDOW *w = newwin(20, 40, 3 + ((TERMY > 25) ? (TERMY - 25) / 2 : 0),
                           10 + ((TERMX > 80) ? (TERMX - 80) / 2 : 0));
        draw_border(w);
        if (has_disease("fungus")) {
            bad.push_back(_("Fungal Parasite"));
        }
        if (has_disease("dermatik")) {
            bad.push_back(_("Insect Parasite"));
        }
        if (has_effect("stung")) {
            bad.push_back(_("Stung"));
        }
        if (has_effect("poison")) {
            bad.push_back(_("Poison"));
        }
        if (radiation > 0) {
            bad.push_back(_("Irradiated"));
        }
        if (has_disease("pkill1")) {
            good.push_back(_("Minor Painkiller"));
        }
        if (has_disease("pkill2")) {
            good.push_back(_("Moderate Painkiller"));
        }
        if (has_disease("pkill3")) {
            good.push_back(_("Heavy Painkiller"));
        }
        if (has_disease("pkill_l")) {
            good.push_back(_("Slow-Release Painkiller"));
        }
        if (has_disease("drunk")) {
            good.push_back(_("Alcohol"));
        }
        if (has_disease("cig")) {
            good.push_back(_("Nicotine"));
        }
        if (has_disease("meth")) {
            good.push_back(_("Methamphetamines"));
        }
        if (has_disease("high")) {
            good.push_back(_("Intoxicant: Other"));
        }
        if (has_disease("weed_high")) {
            good.push_back(_("THC Intoxication"));
        }
        if (has_disease("hallu") || has_disease("visuals")) {
            bad.push_back(_("Magic Mushroom"));
        }
        if (has_disease("iodine")) {
            good.push_back(_("Iodine"));
        }
        if (has_disease("datura")) {
            good.push_back(_("Anticholinergic Tropane Alkaloids"));
        }
        if (has_disease("took_xanax")) {
            good.push_back(_("Xanax"));
        }
        if (has_disease("took_prozac")) {
            good.push_back(_("Prozac"));
        }
        if (has_disease("took_flumed")) {
            good.push_back(_("Antihistamines"));
        }
        if (has_disease("adrenaline")) {
            good.push_back(_("Adrenaline Spike"));
        }
        if (has_disease("tapeworm")) {  // This little guy is immune to the blood filter though, as he lives in your bowels.
            good.push_back(_("Intestinal Parasite"));
        }
        if (has_disease("bloodworms")) {
            good.push_back(_("Hemolytic Parasites"));
        }
        if (has_disease("brainworm")) {  // This little guy is immune to the blood filter too, as he lives in your brain.
            good.push_back(_("Intracranial Parasite"));
        }
        if (has_disease("paincysts")) {  // These little guys are immune to the blood filter too, as they live in your muscles.
            good.push_back(_("Intramuscular Parasites"));
        }
        if (has_disease("tetanus")) {  // Tetanus infection.
            good.push_back(_("Clostridium Tetani Infection"));
        }
        if (good.empty() && bad.empty()) {
            mvwprintz(w, 1, 1, c_white, _("No effects."));
        } else {
            for (unsigned line = 1; line < 39 && line <= good.size() + bad.size(); line++) {
                if (line <= bad.size()) {
                    mvwprintz(w, line, 1, c_red, "%s", bad[line - 1].c_str());
                } else {
                    mvwprintz(w, line, 1, c_green, "%s", good[line - 1 - bad.size()].c_str());
                }
            }
        }
        wrefresh(w);
        refresh();
        getch();
        delwin(w);
    } else if(bio.id == "bio_blood_filter") {
        add_msg(m_neutral, _("You activate your blood filtration system."));
        rem_disease("fungus");
        rem_disease("dermatik");
        rem_disease("bloodworms");
        rem_disease("tetanus");
        remove_effect("poison");
        remove_effect("stung");
        rem_disease("pkill1");
        rem_disease("pkill2");
        rem_disease("pkill3");
        rem_disease("pkill_l");
        rem_disease("drunk");
        rem_disease("cig");
        rem_disease("high");
        rem_disease("hallu");
        rem_disease("visuals");
        rem_disease("iodine");
        rem_disease("datura");
        rem_disease("took_xanax");
        rem_disease("took_prozac");
        rem_disease("took_flumed");
        rem_disease("adrenaline");
        rem_disease("meth");
        pkill = 0;
        stim = 0;
    } else if(bio.id == "bio_evap") {
        item water = item("water_clean", 0);
        int humidity = g->weatherGen.get_weather(pos(), calendar::turn).humidity;
        int water_charges = (humidity * 3.0) / 100.0 + 0.5;
        // At 50% relative humidity or more, the player will draw 2 units of water
        // At 16% relative humidity or less, the player will draw 0 units of water
        water.charges = water_charges;
        if (water_charges == 0) {
            add_msg_if_player(m_bad, _("There was not enough moisture in the air from which to draw water!"));
        }
        if (g->handle_liquid(water, true, false)) {
            moves -= 100;
        } else if (query_yn(_("Drink from your hands?"))) {
            inv.push_back(water);
            consume(inv.position_by_type(water.typeId()));
            moves -= 350;
        } else if (water.charges == water_charges && water_charges != 0) {
            power_level += bionics["bio_evap"]->power_cost;
        }
    } else if(bio.id == "bio_lighter") {
        if(!choose_adjacent(_("Start a fire where?"), dirx, diry) ||
           (!g->m.add_field(dirx, diry, fd_fire, 1))) {
            add_msg_if_player(m_info, _("You can't light a fire there."));
            power_level += bionics["bio_lighter"]->power_cost;
        }

    }
    if(bio.id == "bio_leukocyte") {
        add_msg(m_neutral, _("You activate your leukocyte breeder system."));
        g->u.set_healthy(std::min(100, g->u.get_healthy() + 2));
        g->u.mod_healthy_mod(20);
    }
    if(bio.id == "bio_geiger") {
        add_msg(m_info, _("Your radiation level: %d"), radiation);
    }
    if(bio.id == "bio_radscrubber") {
        add_msg(m_neutral, _("You activate your radiation scrubber system."));
        if (radiation > 4) {
            radiation -= 5;
        } else {
            radiation = 0;
        }
    }
    if(bio.id == "bio_adrenaline") {
        add_msg(m_neutral, _("You activate your adrenaline pump."));
        if (has_disease("adrenaline")) {
            add_disease("adrenaline", 50);
        } else {
            add_disease("adrenaline", 200);
        }
    } else if(bio.id == "bio_claws") {
        if (weapon.type->id == "bio_claws_weapon") {
            add_msg(m_neutral, _("You withdraw your claws."));
            weapon = ret_null;
        } else if (weapon.has_flag ("NO_UNWIELD")) {
            add_msg(m_info, _("Deactivate your %s first!"),
                    weapon.tname().c_str());
            power_level += bionics[bio.id]->power_cost;
            return;
        } else if(weapon.type->id != "null") {
            add_msg(m_warning, _("Your claws extend, forcing you to drop your %s."),
                    weapon.tname().c_str());
            g->m.add_item_or_charges(posx, posy, weapon);
            weapon = item("bio_claws_weapon", 0);
            weapon.invlet = '#';
        } else {
            add_msg(m_neutral, _("Your claws extend!"));
            weapon = item("bio_claws_weapon", 0);
            weapon.invlet = '#';
        }
    } else if(bio.id == "bio_blade") {
        if (weapon.type->id == "bio_blade_weapon") {
            add_msg(m_neutral, _("You retract your blade."));
            weapon = ret_null;
        } else if (weapon.has_flag ("NO_UNWIELD")) {
            add_msg(m_info, _("Deactivate your %s first!"),
                    weapon.tname().c_str());
            power_level += bionics[bio.id]->power_cost;
            return;
        } else if(weapon.type->id != "null") {
            add_msg(m_warning, _("Your blade extends, forcing you to drop your %s."),
                    weapon.tname().c_str());
            g->m.add_item_or_charges(posx, posy, weapon);
            weapon = item("bio_blade_weapon", 0);
            weapon.invlet = '#';
        } else {
            add_msg(m_neutral, _("You extend your blade!"));
            weapon = item("bio_blade_weapon", 0);
            weapon.invlet = '#';
        }
    } else if(bio.id == "bio_blaster") {
        tmp_item = weapon;
        weapon = item("bio_blaster_gun", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if (bio.id == "bio_laser") {
        tmp_item = weapon;
        weapon = item("bio_laser_gun", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if(bio.id == "bio_chain_lightning") {
        tmp_item = weapon;
        weapon = item("bio_lightning", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if (bio.id == "bio_emp") {
        if(choose_adjacent(_("Create an EMP where?"), dirx, diry)) {
            g->emp_blast(dirx, diry);
        } else {
            power_level += bionics["bio_emp"]->power_cost;
        }
    } else if (bio.id == "bio_hydraulics") {
        add_msg(m_good, _("Your muscles hiss as hydraulic strength fills them!"));
        // Sound of hissing hydraulic muscle! (not quite as loud as a car horn)
        g->sound(posx, posy, 19, _("HISISSS!"));
    } else if (bio.id == "bio_water_extractor") {
        bool extracted = false;
        for (std::vector<item>::iterator it = g->m.i_at(posx, posy).begin();
             it != g->m.i_at(posx, posy).end(); ++it) {
            if (it->type->id == "corpse" ) {
                int avail = 0;
                if ( it->item_vars.find("remaining_water") != it->item_vars.end() ) {
                    avail = atoi ( it->item_vars["remaining_water"].c_str() );
                } else {
                    avail = it->volume() / 2;
                }
                if(avail > 0 && query_yn(_("Extract water from the %s"), it->tname().c_str())) {
                    item water = item("water_clean", 0);
                    if (g->handle_liquid(water, true, true)) {
                        moves -= 100;
                    } else if (query_yn(_("Drink directly from the condenser?"))) {
                        inv.push_back(water);
                        consume(inv.position_by_type(water.typeId()));
                        moves -= 350;
                    }
                    extracted = true;
                    avail--;
                    it->item_vars["remaining_water"] = string_format("%d", avail);
                    break;
                }
            }
        }
        if (!extracted) {
            power_level += bionics["bio_water_extractor"]->power_cost;
        }
    } else if(bio.id == "bio_magnet") {
        for (int i = posx - 10; i <= posx + 10; i++) {
            for (int j = posy - 10; j <= posy + 10; j++) {
                if (g->m.i_at(i, j).size() > 0) {
                    int t; //not sure why map:sees really needs this, but w/e
                    if (g->m.sees(i, j, posx, posy, -1, t)) {
                        traj = line_to(i, j, posx, posy, t);
                    } else {
                        traj = line_to(i, j, posx, posy, 0);
                    }
                }
                traj.insert(traj.begin(), point(i, j));
                for (unsigned k = 0; k < g->m.i_at(i, j).size(); k++) {
                    if (g->m.i_at(i, j)[k].made_of("iron") || g->m.i_at(i, j)[k].made_of("steel")) {
                        tmp_item = g->m.i_at(i, j)[k];
                        g->m.i_rem(i, j, k);
                        std::vector<point>::iterator it;
                        for (it = traj.begin(); it != traj.end(); ++it) {
                            int index = g->mon_at(it->x, it->y);
                            if (index != -1) {
                                g->zombie(index).apply_damage( this, bp_torso, tmp_item.weight() / 225 );
                                g->m.add_item_or_charges(it->x, it->y, tmp_item);
                                break;
                            } else if (it != traj.begin() && g->m.move_cost(it->x, it->y) == 0) {
                                g->m.bash( it->x, it->y, tmp_item.weight() / 225 );
                                if (g->m.move_cost(it->x, it->y) == 0) {
                                    g->m.add_item_or_charges((it - 1)->x, (it - 1)->y, tmp_item);
                                    break;
                                }
                            }
                        }
                        if (it == traj.end()) {
                            g->m.add_item_or_charges(posx, posy, tmp_item);
                        }
                    }
                }
            }
        }
    } else if(bio.id == "bio_lockpick") {
        if(!choose_adjacent(_("Activate your bio lockpick where?"), dirx, diry)) {
            power_level += bionics["bio_lockpick"]->power_cost;
            return;
        }
        ter_id type = g->m.ter(dirx, diry);
        if (type  == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior ) {
            moves -= 40;
            std::string door_name = rm_prefix(_("<door_name>door"));
            add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."),
                              door_name.c_str());
            g->m.ter_set(dirx, diry, t_door_c);
            // Locked metal doors are the Lab and Bunker entries.  Those need to stay locked.
        } else if(type == t_door_bar_locked) {
            moves -= 40;
            std::string door_name = rm_prefix(_("<door_name>door"));
            add_msg_if_player(m_neutral, _("The %s swings open..."),
                              door_name.c_str()); //Could better copy the messages from lockpick....
            g->m.ter_set(dirx, diry, t_door_bar_o);
        } else if(type == t_chaingate_l) {
            moves -= 40;
            std::string gate_name = rm_prefix (_("<door_name>gate"));
            add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."),
                              gate_name.c_str());
            g->m.ter_set(dirx, diry, t_chaingate_c);
        } else if(type == t_door_c) {
            add_msg(m_info, _("That door isn't locked."));
        } else {
            add_msg_if_player(m_neutral, _("You can't unlock that %s."),
                              g->m.tername(dirx, diry).c_str());
        }
    } else if(bio.id == "bio_flashbang") {
        add_msg_if_player(m_neutral, _("You activate your integrated flashbang generator!"));
        g->flashbang(posx, posy, true);
    } else if(bio.id == "bio_shockwave") {
        g->shockwave(posx, posy, 3, 4, 2, 8, true);
        add_msg_if_player(m_neutral, _("You unleash a powerful shockwave!"));
    }
}
Exemplo n.º 13
0
void curr_attack() {
	// see if nv status allow for attack
	switch (CURR_POKEMON->nv.nvstatus) {
		case NON_S:
		case BRN_S:
		case PSN_S:
		case TXC_S:
			break;
		
		case FRZ_S:
			if (roll(.2)) {
				sprintf(msg, "%s thawed out!", CURR_PNAME); send();
				CURR_POKEMON->nv.nvstatus = NON_S;
				break;
			} else {
				sprintf(msg, "%s is frozen solid!", CURR_PNAME); send();
				return;
			}
		case PAR_S:
			if (roll(.25)) {
				sprintf(msg, "%s is fully paralyzed!", CURR_PNAME); send();
				return;
			} else {
				break;
			}
		case SLP_S:
			if (CURR_POKEMON->nv.nv_arg > 0) {
				sprintf(msg, "%s is fast asleep!", CURR_PNAME); send();
				CURR_POKEMON->nv.nv_arg--;
				return;
			} else {
				sprintf(msg, "%s woke up!", CURR_PNAME); send();
				CURR_POKEMON->nv.nvstatus = NON_S;
				break;
			}
		case FNT_S: // should never happen
		default:
			return;
	}

	// see if v status allows for attack
	if (CURR_POKEMON->v.is_flinch) {
		sprintf(msg, "%s flinched!", CURR_PNAME); send();
		CURR_POKEMON->v.is_flinch = false;
		return;
	}
	if (CURR_POKEMON->v.is_recharge) {
		sprintf(msg, "%s is recharging!", CURR_PNAME); send();
		CURR_POKEMON->v.is_recharge = false;
		return;
	}
	if (CURR_POKEMON->v.is_confuse) {
		sprintf(msg, "%s is confused!", CURR_PNAME); send();
		if (roll(.25)) { // this is not quite how it works in Pokemon
			sprintf(msg, "%s snapped out of confusion!", CURR_PNAME); send();
			CURR_POKEMON->v.is_confuse = false;
		} else {
			if (roll(.5)) {
				sprintf(msg, "%s hurt itself in confusion!", CURR_PNAME); send();
				int damage = calc_damage(CURR_POKEMON, CURR_POKEMON, 40, PHYSICAL_MT);
				// printf("[%s applied %i damage to himself]", CURR_PNAME, damage);
				apply_damage(CURR_POKEMON, damage);
				return;
			}
		}
	}

	move_s *move = curr_move();
	sprintf(msg, "%s used %s!", CURR_PNAME, move->name); send();

	// check if unique
	if (move->unique) {
		switch (move->unique) {
			default: // no unique moves at the moment
				return;
		}
	}

	// check accuracy
	if (is_aggressive(move)) {
		if (!roll(move->accuracy * calc_accuracy(CURR_POKEMON, OTHR_POKEMON))) { // swift support?
			sprintf(msg, "It missed!"); send();
			return;
		}

		if (move->movetype != STATUS_MT) {
			int damage = calc_damage(CURR_POKEMON, OTHR_POKEMON, move->damage, move->movetype);

			double stab_bonus = (has_type(CURR_POKEMON, move->type) ? 1.5 : 1); // STAB bonus
			double effective_bonus = calc_effective(move->type, OTHR_POKEMON); // type bonus

			double crit_chance = (move->effect == HIGH_CRIT_E2 ? .125 : .0625);
			double crit_bonus = (roll(crit_chance) ? 1.5 : 1.0); // this is not quite how it works in Pokemon

			double rndm = (rand() % 16 + 85) / 100.0;

			// printf("%i, %lf, %lf, %lf, %lf", damage, stab_bonus, effective_bonus, crit_bonus, rndm);
			int total_damage = (int)(damage * stab_bonus * effective_bonus * crit_bonus * rndm);

			// if burnt, physical damage output is halfed
			if (CURR_POKEMON->nv.nvstatus == BRN_S && move->movetype == PHYSICAL_MT) {
				total_damage /= 2;
			}

			if (effective_bonus > 1) {
				sprintf(msg, "It's super effective!"); send();
			} else if (effective_bonus == 0) {
				sprintf(msg, "It has no effect!"); send();
			} else if (effective_bonus < 1) {
				sprintf(msg, "It's not very effective!"); send();
			}

			if (crit_bonus > 1) {
				sprintf(msg, "Critical hit!"); send();
			}

			// printf("[%s applies %i damage to %s]", CURR_PNAME, total_damage, OTHR_PNAME);
			apply_damage(OTHR_POKEMON, total_damage);
		} else {
			if (calc_effective(move->type, OTHR_POKEMON) == 0) { // thunder wave can't work on ground
				sprintf(msg, "It has no effect!"); send();
				return;
			}
		}
	}

	int calculation; // can be used for some of the switch cases

	// check secondary effect
	if (move->effect != NON_E2) {
		if (roll(move->chance)) {
			switch (move->effect) {
				case APPLY_BRN_E2:
					apply_nvstatus(OTHR_POKEMON, BRN_S);
					break;
				case APPLY_FRZ_E2:
					apply_nvstatus(OTHR_POKEMON, FRZ_S);
					break;
				case APPLY_PAR_E2:
					apply_nvstatus(OTHR_POKEMON, PAR_S);
					break;
				case APPLY_PSN_E2:
					apply_nvstatus(OTHR_POKEMON, PSN_S);
					break;
				case APPLY_TXC_E2:
					apply_nvstatus(OTHR_POKEMON, TXC_S);
					break;
				case APPLY_SLP_E2:
					apply_nvstatus(OTHR_POKEMON, SLP_S);
					break;
				case APPLY_FLINCH_E2:
					OTHR_POKEMON->v.is_flinch = true;
					break;
				case APPLY_CONFUSE_E2:
					sprintf(msg, "%s became confused!", OTHR_PNAME); send();
					OTHR_POKEMON->v.is_confuse = true;
					break;
				case HIGH_CRIT_E2:
					break; // this doesn't happen here
				case SELF_KILL_E2:
					apply_nvstatus(CURR_POKEMON, FNT_S);
					break;
				case SELF_ATTACK_E2:
					apply_attackstage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_DEFENSE_E2:
					apply_defensestage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_SATTACK_E2:
					apply_sattackstage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_SDEFENSE_E2:
					apply_sdefensestage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_SPEED_E2:
					apply_speedstage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_ACCURACY_E2:
					apply_accuracystage(CURR_POKEMON, move->m_arg);
					break;
				case SELF_EVASION_E2:
					apply_evasionstage(CURR_POKEMON, move->m_arg);
					break;
				case OTHR_ATTACK_E2:
					apply_attackstage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_DEFENSE_E2:
					apply_defensestage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_SATTACK_E2:
					apply_sattackstage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_SDEFENSE_E2:
					apply_sdefensestage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_SPEED_E2:
					apply_speedstage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_ACCURACY_E2:
					apply_accuracystage(OTHR_POKEMON, move->m_arg);
					break;
				case OTHR_EVASION_E2:
					apply_evasionstage(OTHR_POKEMON, move->m_arg);
					break;
				case SELF_ATTACK_SATTACK_E2:
					apply_attackstage(CURR_POKEMON, move->m_arg);
					apply_sattackstage(CURR_POKEMON, move->m_arg);
					break;
				case HAZE_E2:
					reset_stages(CURR_POKEMON);
					reset_stages(OTHR_POKEMON);
					break;
				case RECOIL_E2:
					calculation = battle.last_dmg / move->m_arg; // pos is recoil, neg is heal
					if (calculation > 0) {
						sprintf(msg, "%s was hit with recoil!", CURR_PNAME); send();
						// printf("[%s took %i damage in recoil]", CURR_PNAME, calculation);
					} else if (calculation < 0) {
						sprintf(msg, "%s regained health!", CURR_PNAME); send();
						// printf("[%s restored %i damage]", CURR_PNAME, calculation);
					}
					apply_damage(CURR_POKEMON, calculation);
					break; // this doesn't happen here
				case RECHARGE_E2:
					CURR_POKEMON->v.is_recharge = true;
					break;
				case NON_E2: // shouldn't happen
					break;
			}
		}
	}
}