void make_mon_corpse( monster &z, int damageLvl )
{
    item corpse = item::make_corpse( z.type->id, calendar::turn, z.unique_name );
    corpse.set_damage( damageLvl );
    if( z.has_effect( effect_pacified ) && z.type->in_species( ZOMBIE ) ) {
        // Pacified corpses have a chance of becoming unpacified when regenerating.
        corpse.set_var( "zlave", one_in(2) ? "zlave" : "mutilated" );
    }
    if( z.has_effect( effect_no_ammo ) ) {
        corpse.set_var("no_ammo", "no_ammo");
    }
    g->m.add_item_or_charges( z.pos(), corpse );
}
Exemple #2
0
void make_mon_corpse( monster &z, int damageLvl )
{
    item corpse = item::make_corpse( z.type->id, calendar::turn, z.unique_name );
    // All corpses are at 37 C at time of death
    // This may not be true but anything better would be way too complicated
    if( z.is_warm() ) {
        corpse.set_item_temperature( 310.15 );
    }
    corpse.set_damage( damageLvl );
    if( z.has_effect( effect_pacified ) && z.type->in_species( ZOMBIE ) ) {
        // Pacified corpses have a chance of becoming unpacified when regenerating.
        corpse.set_var( "zlave", one_in( 2 ) ? "zlave" : "mutilated" );
    }
    if( z.has_effect( effect_no_ammo ) ) {
        corpse.set_var( "no_ammo", "no_ammo" );
    }
    g->m.add_item_or_charges( z.pos(), corpse );
}
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 );
    }
}
Exemple #4
0
void mdeath::splatter( monster &z )
{
    const bool gibbable = !z.type->has_flag( MF_NOGIB );

    const int max_hp = std::max( z.get_hp_max(), 1 );
    const float overflow_damage = std::max( -z.get_hp(), 0 );
    const float corpse_damage = 2.5 * overflow_damage / max_hp;
    bool pulverized = corpse_damage > 5 && overflow_damage > z.get_hp_max();
    // make sure that full splatter happens when this is a set death function, not part of normal
    for( const auto &deathfunction : z.type->dies ) {
        if( deathfunction == mdeath::splatter ) {
            pulverized = true;
        }
    }

    const field_id type_blood = z.bloodType();
    const field_id type_gib = z.gibType();

    if( gibbable ) {
        const auto area = g->m.points_in_radius( z.pos(), 1 );
        int number_of_gibs = std::min( std::floor( corpse_damage ) - 1, 1 + max_hp / 5.0f );

        if( pulverized && z.type->size >= MS_MEDIUM ) {
            number_of_gibs += rng( 1, 6 );
            sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume( z.pos() ) );
        }

        for( int i = 0; i < number_of_gibs; ++i ) {
            g->m.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) );
            g->m.add_splatter( type_blood, random_entry( area ) );
        }
    }
    // 1% of the weight of the monster is the base, with overflow damage as a multiplier
    int gibbed_weight = rng( 0, round( to_gram( z.get_weight() ) / 100 *
                                       ( overflow_damage / max_hp + 1 ) ) );
    // limit gibbing to 15%
    gibbed_weight = std::min( gibbed_weight, to_gram( z.get_weight() ) * 15 / 100 );

    if( pulverized && gibbable ) {
        float overflow_ratio = overflow_damage / max_hp + 1;
        int gib_distance = round( rng( 2, 4 ) );
        for( const auto &entry : *z.type->harvest ) {
            // only flesh and bones survive.
            if( entry.type == "flesh" || entry.type == "bone" ) {
                // the larger the overflow damage, the less you get
                const int chunk_amt = entry.mass_ratio / overflow_ratio / 10 * to_gram(
                                          z.get_weight() ) / to_gram( ( item::find_type( entry.drop ) )->weight );
                scatter_chunks( entry.drop, chunk_amt, z, gib_distance, chunk_amt / ( gib_distance - 1 ) );
                gibbed_weight -= entry.mass_ratio / overflow_ratio / 20 * to_gram( z.get_weight() );
            }
        }
        if( gibbed_weight > 0 ) {
            scatter_chunks( "ruined_chunks",
                            gibbed_weight / to_gram( ( item::find_type( "ruined_chunks" ) ) ->weight ), z, gib_distance,
                            gibbed_weight / to_gram( ( item::find_type( "ruined_chunks" ) )->weight ) / ( gib_distance + 1 ) );
        }
        // add corpse with gib flag
        item corpse = item::make_corpse( z.type->id, calendar::turn, z.unique_name );
        // Set corpse to damage that aligns with being pulped
        corpse.set_damage( 4000 );
        corpse.set_flag( "GIBBED" );
        if( z.has_effect( effect_no_ammo ) ) {
            corpse.set_var( "no_ammo", "no_ammo" );
        }
        g->m.add_item_or_charges( z.pos(), corpse );
    }
}
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 );
    }
}