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 ); }
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 ); } }
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 ); } }