Example #1
0
// MATERIALS-TODO: use fire resistance
void game::hit_monster_with_flags(monster &z, const std::set<std::string> &effects)
{
 if (effects.count("FLAME")) {

  if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
   z.add_effect(ME_ONFIRE, rng(8, 20));
  else if (z.made_of("flesh"))
   z.add_effect(ME_ONFIRE, rng(5, 10));
 } else if (effects.count("INCENDIARY")) {

  if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
   z.add_effect(ME_ONFIRE, rng(2, 6));
  else if (z.made_of("flesh") && one_in(4))
   z.add_effect(ME_ONFIRE, rng(1, 4));

 } else if (effects.count("IGNITE")) {

   if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
      z.add_effect(ME_ONFIRE, rng(6, 6));
   else if (z.made_of("flesh"))
   z.add_effect(ME_ONFIRE, rng(10, 10));

 }
 if (effects.count("BOUNCE")) {
     z.add_effect(ME_BOUNCED, 1);
 }
 int stun_strength = 0;
 if (effects.count("BEANBAG")) {
     stun_strength = 4;
 }
 if (effects.count("LARGE_BEANBAG")) {
     stun_strength = 16;
 }
 if( stun_strength > 0 ) {
     switch( z.type->size )
     {
     case MS_TINY:
         stun_strength *= 4;
         break;
     case MS_SMALL:
         stun_strength *= 2;
         break;
     case MS_MEDIUM:
     default:
         break;
     case MS_LARGE:
         stun_strength /= 2;
         break;
     case MS_HUGE:
         stun_strength /= 4;
         break;
     }
     z.add_effect( ME_STUNNED, rng(stun_strength / 2, stun_strength) );
 }
}
void stash_on_pet( const std::list<item> &items, monster &pet )
{
    units::volume remaining_volume = pet.inv.empty() ? 0_ml : pet.inv.front().get_storage();
    units::mass remaining_weight = pet.weight_capacity();

    for( const auto &it : pet.inv ) {
        remaining_volume -= it.volume();
        remaining_weight -= it.weight();
    }

    for( auto &it : items ) {
        pet.add_effect( effect_controlled, 5_turns );
        if( it.volume() > remaining_volume ) {
            add_msg( m_bad, _( "%1$s did not fit and fell to the %2$s." ),
                     it.display_name(), g->m.name( pet.pos() ) );
            g->m.add_item_or_charges( pet.pos(), it );
        } else if( it.weight() > remaining_weight ) {
            add_msg( m_bad, _( "%1$s is too heavy and fell to the %2$s." ),
                     it.display_name(), g->m.name( pet.pos() ) );
            g->m.add_item_or_charges( pet.pos(), it );
        } else {
            pet.add_item( it );
            remaining_volume -= it.volume();
            remaining_weight -= it.weight();
        }
    }
}
Example #3
0
void bite_actor::on_damage( monster &z, Creature &target, dealt_damage_instance &dealt ) const
{
    melee_actor::on_damage( z, target, dealt );
    if( target.has_effect( effect_grabbed ) && one_in( no_infection_chance - dealt.total_damage() ) ) {
        const body_part hit = dealt.bp_hit;
        if( target.has_effect( effect_bite, hit ) ) {
            target.add_effect( effect_bite, 40_minutes, hit, true );
        } else if( target.has_effect( effect_infected, hit ) ) {
            target.add_effect( effect_infected, 25_minutes, hit, true );
        } else {
            target.add_effect( effect_bite, 1_turns, hit, true );
        }
    }
    if( target.has_trait( trait_id( "TOXICFLESH" ) ) ) {
        z.add_effect( effect_poison, 5_minutes );
        z.add_effect( effect_badpoison, 5_minutes );
    }
}
Example #4
0
void game::hit_monster_with_flags(monster &z, unsigned int effects)
{
 if (effects & mfb(AMMO_FLAME)) {

  if (z.made_of(VEGGY) || z.made_of(COTTON) || z.made_of(WOOL) ||
      z.made_of(PAPER) || z.made_of(WOOD))
   z.add_effect(ME_ONFIRE, rng(8, 20));
  else if (z.made_of(FLESH))
   z.add_effect(ME_ONFIRE, rng(5, 10));
 } else if (effects & mfb(AMMO_INCENDIARY)) {

  if (z.made_of(VEGGY) || z.made_of(COTTON) || z.made_of(WOOL) ||
      z.made_of(PAPER) || z.made_of(WOOD))
   z.add_effect(ME_ONFIRE, rng(2, 6));
  else if (z.made_of(FLESH) && one_in(4))
   z.add_effect(ME_ONFIRE, rng(1, 4));

 }
}
Example #5
0
// MATERIALS-TODO: use fire resistance
void game::hit_monster_with_flags(monster &z, unsigned int effects)
{
 if (effects & mfb(AMMO_FLAME)) {

  if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
   z.add_effect(ME_ONFIRE, rng(8, 20));
  else if (z.made_of("flesh"))
   z.add_effect(ME_ONFIRE, rng(5, 10));
 } else if (effects & mfb(AMMO_INCENDIARY)) {

  if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
   z.add_effect(ME_ONFIRE, rng(2, 6));
  else if (z.made_of("flesh") && one_in(4))
   z.add_effect(ME_ONFIRE, rng(1, 4));

 } else if (effects & mfb(AMMO_IGNITE)) {

   if (z.made_of("veggy") || z.made_of("cotton") || z.made_of("wool") ||
      z.made_of("paper") || z.made_of("wood"))
      z.add_effect(ME_ONFIRE, rng(6, 6));
   else if (z.made_of("flesh"))
   z.add_effect(ME_ONFIRE, rng(10, 10));

 }
}
void gun_actor::shoot( monster &z, Creature &target ) const
{
    // Make sure our ammo isn't weird.
    if( z.ammo[ammo_type] > max_ammo ) {
        debugmsg( "Generated too much ammo (%d) of type %s for %s in gun_actor::shoot",
                  z.ammo[ammo_type], ammo_type.c_str(), z.name().c_str() );
        z.ammo[ammo_type] = max_ammo;
    }

    const bool require_targeting = ( require_targeting_player && target.is_player() ) ||
                                   ( require_targeting_npc && target.is_npc() ) ||
                                   ( require_targeting_monster && target.is_monster() );
    const bool not_targeted = require_targeting && !z.has_effect( effect_targeted );
    const bool not_laser_locked = require_targeting && laser_lock &&
                                  !target.has_effect( effect_was_laserlocked );

    if( not_targeted || not_laser_locked ) {
        if( !targeting_sound.empty() ) {
            sounds::sound( z.pos(), targeting_volume, _( targeting_sound.c_str() ) );
        }
        if( not_targeted ) {
            z.add_effect( effect_targeted, targeting_timeout );
        }
        if( not_laser_locked ) {
            target.add_effect( effect_laserlocked, 5 );
            target.add_effect( effect_was_laserlocked, 5 );
            target.add_msg_if_player( m_warning,
                                      _( "You're not sure why you've got a laser dot on you..." ) );
        }

        z.moves -= targeting_cost;
        return;
    }

    // It takes a while
    z.moves -= move_cost;

    if( z.ammo[ammo_type] <= 0 && !no_ammo_sound.empty() ) {
        sounds::sound( z.pos(), 10, _( no_ammo_sound.c_str() ) );
        return;
    }

    if( g->u.sees( z ) ) {
        add_msg( m_warning, _( description.c_str() ) );
    }

    npc tmp;
    tmp.name = _( "The " ) + z.name();
    tmp.set_fake( true );
    tmp.recoil = 0;
    tmp.driving_recoil = 0;
    tmp.setpos( z.pos() );
    tmp.str_max = fake_str;
    tmp.dex_max = fake_dex;
    tmp.int_max = fake_int;
    tmp.per_max = fake_per;
    tmp.str_cur = fake_str;
    tmp.dex_cur = fake_dex;
    tmp.int_cur = fake_int;
    tmp.per_cur = fake_per;
    tmp.weapon = item( gun_type, 0 );
    tmp.weapon.set_curammo( ammo_type );
    tmp.weapon.charges = z.ammo[ammo_type];
    if( z.friendly != 0 ) {
        tmp.attitude = NPCATT_DEFEND;
    } else {
        tmp.attitude = NPCATT_KILL;
    }

    for( const auto &pr : fake_skills ) {
        tmp.skillLevel( pr.first ).level( pr.second );
    }

    const auto distance = rl_dist( z.pos(), target.pos() );
    int burst_size = std::min( burst_limit, tmp.weapon.burst_size() );
    if( distance > range_no_burst || burst_size < 1 ) {
        burst_size = 1;
    }

    tmp.fire_gun( target.pos(), burst_size );
    z.ammo[ammo_type] = tmp.weapon.charges;
    if( require_targeting ) {
        z.add_effect( effect_targeted, targeting_timeout_extend );
    }

    if( laser_lock ) {
        // To prevent spamming laser locks when the player can tank that stuff somehow
        target.add_effect( effect_was_laserlocked, 5 );
    }
}
Example #7
0
void mdeath::detonate( monster &z )
{
    weighted_int_list<std::string> amm_list;
    for( const auto &amm : z.ammo ) {
        amm_list.add( amm.first, amm.second );
    }

    std::vector<std::string> pre_dets;
    for( int i = 0; i < 3; i++ ) {
        if( amm_list.get_weight() <= 0 ) {
            break;
        }
        // Grab one item
        std::string tmp = *amm_list.pick();
        // and reduce its weight by 1
        amm_list.add_or_replace( tmp, amm_list.get_specific_weight( tmp ) - 1 );
        // and stash it for use
        pre_dets.push_back( tmp );
    }

    // Update any hardcoded explosion equivalencies
    std::vector<std::pair<std::string, long>> dets;
    for( const std::string &bomb_id : pre_dets ) {
        if( bomb_id == "bot_grenade_hack" ) {
            dets.push_back( std::make_pair( "grenade_act", 5 ) );
        } else if( bomb_id == "bot_flashbang_hack" ) {
            dets.push_back( std::make_pair( "flashbang_act", 5 ) );
        } else if( bomb_id == "bot_gasbomb_hack" ) {
            dets.push_back( std::make_pair( "gasbomb_act", 20 ) );
        } else if( bomb_id == "bot_c4_hack" ) {
            dets.push_back( std::make_pair( "c4armed", 10 ) );
        } else if( bomb_id == "bot_mininuke_hack" ) {
            dets.push_back( std::make_pair( "mininuke_act", 20 ) );
        } else {
            // Get the transformation item
            const iuse_transform *actor = dynamic_cast<const iuse_transform *>(
                                              item::find_type( bomb_id )->get_use( "transform" )->get_actor_ptr() );
            if( actor == nullptr ) {
                // Invalid bomb item, move to the next ammo item
                add_msg( m_debug, "Invalid bomb type in detonate mondeath for %s.", z.name() );
                continue;
            }
            dets.emplace_back( actor->target, actor->ammo_qty );
        }
    }

    if( g->u.sees( z ) ) {
        if( dets.empty() ) {
            //~ %s is the possessive form of the monster's name
            add_msg( m_info,
                     _( "The %s's hands fly to its pockets, but there's nothing left in them." ),
                     z.name() );
        } else {
            //~ %s is the possessive form of the monster's name
            add_msg( m_bad, _( "The %s's hands fly to its remaining pockets, opening them!" ),
                     z.name() );
        }
    }
    // HACK, used to stop them from having ammo on respawn
    z.add_effect( effect_no_ammo, 1_turns, num_bp, true );

    // First die normally
    mdeath::normal( z );
    // Then detonate our suicide bombs
    for( const auto &bombs : dets ) {
        item bomb_item( bombs.first, 0 );
        bomb_item.charges = bombs.second;
        bomb_item.active = true;
        g->m.add_item_or_charges( z.pos(), bomb_item );
    }
}
Example #8
0
void gun_actor::shoot( monster &z, Creature &target, const gun_mode_id &mode ) const
{
    if( require_sunlight && !g->is_in_sunlight( z.pos() ) ) {
        if( one_in( 3 ) && g->u.sees( z ) ) {
            add_msg( _( failure_msg ), z.name() );
        }
        return;
    }

    const bool require_targeting = ( require_targeting_player && target.is_player() ) ||
                                   ( require_targeting_npc && target.is_npc() ) ||
                                   ( require_targeting_monster && target.is_monster() );
    const bool not_targeted = require_targeting && !z.has_effect( effect_targeted );
    const bool not_laser_locked = require_targeting && laser_lock &&
                                  !target.has_effect( effect_was_laserlocked );

    if( not_targeted || not_laser_locked ) {
        if( targeting_volume > 0 && !targeting_sound.empty() ) {
            sounds::sound( z.pos(), targeting_volume, sounds::sound_t::alarm,
                           _( targeting_sound ) );
        }
        if( not_targeted ) {
            z.add_effect( effect_targeted, time_duration::from_turns( targeting_timeout ) );
        }
        if( not_laser_locked ) {
            target.add_effect( effect_laserlocked, 5_turns );
            target.add_effect( effect_was_laserlocked, 5_turns );
            target.add_msg_if_player( m_warning,
                                      _( "You're not sure why you've got a laser dot on you..." ) );
        }

        z.moves -= targeting_cost;
        return;
    }

    z.moves -= move_cost;

    item gun( gun_type );
    gun.gun_set_mode( mode );

    itype_id ammo = ( ammo_type != "null" ) ? ammo_type : gun.ammo_default();
    if( ammo != "null" ) {
        gun.ammo_set( ammo, z.ammo[ ammo ] );
    }

    if( !gun.ammo_sufficient() ) {
        if( !no_ammo_sound.empty() ) {
            sounds::sound( z.pos(), 10, sounds::sound_t::combat, _( no_ammo_sound ) );
        }
        return;
    }

    standard_npc tmp( _( "The " ) + z.name(), {}, 8, fake_str, fake_dex, fake_int, fake_per );
    tmp.set_fake( true );
    tmp.setpos( z.pos() );
    tmp.set_attitude( z.friendly ? NPCATT_FOLLOW : NPCATT_KILL );
    tmp.recoil = 0; // no need to aim

    for( const auto &pr : fake_skills ) {
        tmp.set_skill_level( pr.first, pr.second );
    }

    tmp.weapon = gun;
    tmp.i_add( item( "UPS_off", calendar::turn, 1000 ) );

    if( g->u.sees( z ) ) {
        add_msg( m_warning, _( description ), z.name(), tmp.weapon.tname() );
    }

    z.ammo[ammo] -= tmp.fire_gun( target.pos(), gun.gun_current_mode().qty );

    if( require_targeting ) {
        z.add_effect( effect_targeted, time_duration::from_turns( targeting_timeout_extend ) );
    }

    if( laser_lock ) {
        // To prevent spamming laser locks when the player can tank that stuff somehow
        target.add_effect( effect_was_laserlocked, 5_turns );
    }
}
Example #9
0
void shoot_monster(player &p, monster &mon, int &dam, double goodhit,
                   item* weapon, const std::set<std::string> &effects)
{
// Gunmods don't have a type, so use the player weapon type.
    it_gun* firing = dynamic_cast<it_gun*>(p.weapon.type);
    std::string message;
    bool u_see_mon = g->u_see(&(mon));
    int adjusted_damage = dam;
    if (mon.has_flag(MF_HARDTOSHOOT) && !one_in(10 - 10 * (.8 - goodhit)) && // Maxes out at 50% chance with perfect hit
    weapon->curammo->phase != LIQUID && !effects.count("SHOT") && !effects.count("BOUNCE")) {
        if (u_see_mon)
            g->add_msg(_("The shot passes through the %s without hitting."),
            mon.name().c_str());
    } else { // Not HARDTOSHOOT
        // Bounce applies whether it does damage or not.
        if (effects.count("BOUNCE")) {
            mon.add_effect("bounced", 1);
        }
        // Armor blocks BEFORE any critical effects.
        int zarm = mon.get_armor_cut(bp_torso);
        zarm -= weapon->gun_pierce();
        if (weapon->curammo->phase == LIQUID)
            zarm = 0;
        else if (effects.count("SHOT")) // Shot doesn't penetrate armor well
            zarm *= rng(2, 3);
        if (zarm > 0)
            adjusted_damage -= zarm;
        if (adjusted_damage <= 0) {
            if (u_see_mon)
                g->add_msg(_("The shot reflects off the %s!"),
                mon.name_with_armor().c_str());
            adjusted_damage = 0;
            goodhit = 1;
        }
        if (goodhit <= .1 && !mon.has_flag(MF_NOHEAD)) {
            message = _("Headshot!");
            adjusted_damage = rng(5 * adjusted_damage, 8 * adjusted_damage);
            p.practice(g->turn, firing->skill_used, 5);
            p.lifetime_stats()->headshots++;
        } else if (goodhit <= .2) {
            message = _("Critical!");
            adjusted_damage = rng(adjusted_damage * 2, adjusted_damage * 3);
            p.practice(g->turn, firing->skill_used, 3);
        } else if (goodhit <= .4) {
            message = _("Good hit!");
            adjusted_damage = rng(adjusted_damage , adjusted_damage * 2);
            p.practice(g->turn, firing->skill_used, 2);
        } else if (goodhit <= .6) {
            adjusted_damage = rng(adjusted_damage / 2, adjusted_damage);
            p.practice(g->turn, firing->skill_used, 1);
        } else if (goodhit <= .8) {
            message = _("Grazing hit.");
            adjusted_damage = rng(0, adjusted_damage);
        } else {
            adjusted_damage = 0;
        }

        if(item(weapon->curammo, 0).has_flag("NOGIB"))
        {
            adjusted_damage = std::min(adjusted_damage, mon.hp+10);
        }

// Find the zombie at (x, y) and hurt them, MAYBE kill them!
        if (adjusted_damage > 0) {
            switch (mon.type->size) {
            case MS_TINY:
                mon.moves -= rng(0, adjusted_damage * 5);
                break;
            case MS_SMALL:
                mon.moves -= rng(0, adjusted_damage * 3);
                break;
            case MS_MEDIUM:
                mon.moves -= rng(0, adjusted_damage);
                break;
            case MS_LARGE:
                mon.moves -= rng(0, adjusted_damage / 3);
                break;
            case MS_HUGE:
                mon.moves -= rng(0, adjusted_damage / 5);
                break;
            }

            if (&p == &(g->u) && u_see_mon) {
                g->add_msg(_("%s You hit the %s for %d damage."), message.c_str(), mon.name().c_str(), adjusted_damage);
            } else if (u_see_mon) {
                g->add_msg(_("%s %s shoots the %s."), message.c_str(), p.name.c_str(), mon.name().c_str());
            }
            g->hit_monster_with_flags(mon, effects);
            damage_instance d;
            d.add_damage(DT_CUT, adjusted_damage, weapon->gun_pierce(),
                    effects.count("SHOT")?rng(2,3):1); // Shot doesn't penetrate armor well
            mon.deal_damage(&p, bp_torso, -1, d);
            if( u_see_mon ) {
                g->draw_hit_mon(mon.posx(), mon.posy(), mon, mon.is_dead_state());
            }
        }
    }
    dam = adjusted_damage;
}