void mdeath::focused_beam( monster &z ) { for( int k = g->m.i_at( z.pos() ).size() - 1; k >= 0; k-- ) { if( g->m.i_at( z.pos() )[k].typeId() == "processor" ) { g->m.i_rem( z.pos(), k ); } } if( !z.inv.empty() ) { if( g->u.sees( z ) ) { add_msg( m_warning, _( "As the final light is destroyed, it erupts in a blinding flare!" ) ); } item &settings = z.inv[0]; int x = z.posx() + settings.get_var( "SL_SPOT_X", 0 ); int y = z.posy() + settings.get_var( "SL_SPOT_Y", 0 ); tripoint p( x, y, z.posz() ); std::vector <tripoint> traj = line_to( z.pos(), p, 0, 0 ); for( auto &elem : traj ) { if( !g->m.trans( elem ) ) { break; } g->m.add_field( elem, fd_dazzling, 2 ); } } z.inv.clear(); explosion_handler::explosion( z.pos(), 8 ); }
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(); } } }
void mdeath::blobsplit( monster &z ) { int speed = z.get_speed() - rng( 30, 50 ); g->m.spawn_item( z.pos(), "slime_scrap", 1, 0, calendar::turn ); if( z.get_speed() <= 0 ) { if( g->u.sees( z ) ) { // TODO: Add vermin-tagged tiny versions of the splattered blob :) add_msg( m_good, _( "The %s splatters apart." ), z.name() ); } return; } if( g->u.sees( z ) ) { if( z.type->dies.size() == 1 ) { add_msg( m_good, _( "The %s splits in two!" ), z.name() ); } else { add_msg( m_bad, _( "Two small blobs slither out of the corpse." ) ); } } std::vector <tripoint> valid; for( auto &&dest : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* if( g->is_empty( dest ) && z.can_move_to( dest ) ) { valid.push_back( dest ); } } for( int s = 0; s < 2 && !valid.empty(); s++ ) { const tripoint target = random_entry_removed( valid ); if( monster *const blob = g->summon_mon( speed < 50 ? mon_blob_small : mon_blob, target ) ) { blob->make_ally( z ); blob->set_speed_base( speed ); blob->set_hp( speed ); } } }
bool Creature_tracker::add( monster &critter ) { if( critter.type->id.is_null() ) { // Don't want to spawn null monsters o.O return false; } if( critter.type->has_flag( MF_VERMIN ) ) { // Don't spawn vermin, they aren't implemented yet return false; } if( const std::shared_ptr<monster> existing_mon_ptr = find( critter.pos() ) ) { // We can spawn stuff on hallucinations, but we need to kill them first if( existing_mon_ptr->is_hallucination() ) { existing_mon_ptr->die( nullptr ); // But don't remove - that would change the monster order and could segfault } else if( critter.is_hallucination() ) { return false; } else { debugmsg( "add_zombie: there's already a monster at %d,%d,%d", critter.posx(), critter.posy(), critter.posz() ); return false; } } if( MonsterGroupManager::monster_is_blacklisted( critter.type->id ) ) { return false; } monsters_list.emplace_back( std::make_shared<monster>( critter ) ); monsters_by_location[critter.pos()] = monsters_list.back(); return true; }
bool Creature_tracker::add( monster &critter ) { if( critter.type->id.is_null() ) { // Don't wanna spawn null monsters o.O return false; } if( critter.type->has_flag( MF_VERMIN ) ) { // Don't spawn vermin, they aren't implemented yet return false; } const int critter_id = mon_at( critter.pos() ); if( critter_id != -1 ) { // We can spawn stuff on hallucinations, but we need to kill them first if( monsters_list[critter_id]->is_hallucination() ) { monsters_list[critter_id]->die( nullptr ); // But don't remove - that would change the monster order and could segfault } else if( critter.is_hallucination() ) { return false; } else { debugmsg( "add_zombie: there's already a monster at %d,%d,%d", critter.posx(), critter.posy(), critter.posz() ); return false; } } if( MonsterGroupManager::monster_is_blacklisted( critter.type->id ) ) { return false; } monsters_by_location[critter.pos()] = monsters_list.size(); monsters_list.push_back( new monster( critter ) ); return true; }
void mdeath::boomer_glow( monster &z ) { std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); for( auto &&dest : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* g->m.bash( dest, 10 ); if( monster *const z = g->critter_at<monster>( dest ) ) { z->stumble(); z->moves -= 250; } if( Creature *const critter = g->critter_at( dest ) ) { critter->add_env_effect( effect_boomered, bp_eyes, 5, 25_turns ); for( int i = 0; i < rng( 2, 4 ); i++ ) { body_part bp = random_body_part(); critter->add_env_effect( effect_glowing, bp, 4, 4_minutes ); if( critter != nullptr && critter->has_effect( effect_glowing ) ) { break; } } } } g->m.propagate_field( z.pos(), fd_bile, 30, 2 ); }
void mdefense::acidsplash( monster &m, Creature *const source, dealt_projectile_attack const *const proj ) { // Would be useful to have the attack data here, for cutting vs. bashing etc. if( proj != nullptr && proj->dealt_dam.total_damage() <= 0 ) { // Projectile didn't penetrate the target, no acid will splash out of it. return; } if( proj != nullptr && !one_in( 3 ) ) { return; //Less likely for a projectile to deliver enough force } size_t num_drops = rng( 4, 6 ); player const *const foe = dynamic_cast<player *>( source ); if( proj == nullptr && foe != nullptr ) { if( foe->weapon.is_melee( DT_CUT ) || foe->weapon.is_melee( DT_STAB ) ) { num_drops += rng( 3, 4 ); } if( foe->unarmed_attack() ) { damage_instance const burn { DT_ACID, static_cast<float>( rng( 1, 5 ) ) }; if( one_in( 2 ) ) { source->deal_damage( &m, bp_hand_l, burn ); } else { source->deal_damage( &m, bp_hand_r, burn ); } source->add_msg_if_player( m_bad, _( "Acid covering %s burns your hand!" ), m.disp_name().c_str() ); } } tripoint initial_target = source == nullptr ? m.pos() : source->pos(); // Don't splatter directly on the `m`, that doesn't work well auto pts = closest_tripoints_first( 1, initial_target ); pts.erase( std::remove( pts.begin(), pts.end(), m.pos() ), pts.end() ); projectile prj; prj.speed = 10; prj.range = 4; prj.proj_effects.insert( "DRAW_AS_LINE" ); prj.proj_effects.insert( "NO_DAMAGE_SCALING" ); prj.impact.add_damage( DT_ACID, rng( 1, 3 ) ); for( size_t i = 0; i < num_drops; i++ ) { const tripoint &target = random_entry( pts ); projectile_attack( prj, m.pos(), target, { 1200 } ); } if( g->u.sees( m.pos() ) ) { add_msg( m_warning, _( "Acid sprays out of %s as it is hit!" ), m.disp_name().c_str() ); } }
void mdeath::conflagration( monster &z ) { for( const auto &dest : g->m.points_in_radius( z.pos(), 1 ) ) { g->m.propagate_field( dest, fd_fire, 18, 3 ); } const std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); }
void mdeath::fireball( monster &z ) { if( one_in( 10 ) ) { g->m.propagate_field( z.pos(), fd_fire, 15, 3 ); std::string explode = string_format( _( "an explosion of tank of the %s's flamethrower!" ), z.name().c_str() ); sounds::sound( z.pos(), 24, explode ); add_msg( m_good, _( "I love the smell of burning zed in the morning." ) ); } else { normal( z ); } }
bool melee_actor::call( monster &z ) const { Creature *target = find_target( z ); if( target == nullptr ) { return false; } z.mod_moves( -move_cost ); add_msg( m_debug, "%s attempting to melee_attack %s", z.name().c_str(), target->disp_name().c_str() ); const int acc = accuracy >= 0 ? accuracy : z.type->melee_skill; int hitspread = target->deal_melee_attack( &z, dice( acc, 10 ) ); if( hitspread < 0 ) { auto msg_type = target == &g->u ? m_warning : m_info; sfx::play_variant_sound( "mon_bite", "bite_miss", sfx::get_heard_volume( z.pos() ), sfx::get_heard_angle( z.pos() ) ); target->add_msg_player_or_npc( msg_type, miss_msg_u.c_str(), miss_msg_npc.c_str(), z.name().c_str() ); return true; } damage_instance damage = damage_max_instance; double multiplier = rng_float( min_mul, max_mul ); damage.mult_damage( multiplier ); body_part bp_hit = body_parts.empty() ? target->select_body_part( &z, hitspread ) : *body_parts.pick(); target->on_hit( &z, bp_hit ); dealt_damage_instance dealt_damage = target->deal_damage( &z, bp_hit, damage ); dealt_damage.bp_hit = bp_hit; int damage_total = dealt_damage.total_damage(); add_msg( m_debug, "%s's melee_attack did %d damage", z.name().c_str(), damage_total ); if( damage_total > 0 ) { on_damage( z, *target, dealt_damage ); } else { sfx::play_variant_sound( "mon_bite", "bite_miss", sfx::get_heard_volume( z.pos() ), sfx::get_heard_angle( z.pos() ) ); target->add_msg_player_or_npc( no_dmg_msg_u.c_str(), no_dmg_msg_npc.c_str(), z.name().c_str(), body_part_name_accusative( bp_hit ).c_str() ); } return true; }
void mdefense::zapback( monster &m, Creature *const source, dealt_projectile_attack const *const proj ) { // Not a melee attack, attacker lucked out or out of range if( source == nullptr || proj != nullptr || rng( 0, 100 ) > m.def_chance || rl_dist( m.pos(), source->pos() ) > 1 ) { return; } if( source->is_elec_immune() ) { return; } // Players/NPCs can avoid the shock by using non-conductive weapons player const *const foe = dynamic_cast<player *>( source ); if( foe != nullptr && !foe->weapon.conductive() && !foe->unarmed_attack() ) { return; } damage_instance const shock { DT_ELECTRIC, static_cast<float>( rng( 1, 5 ) ) }; source->deal_damage( &m, bp_arm_l, shock ); source->deal_damage( &m, bp_arm_r, shock ); if( g->u.sees( source->pos() ) ) { auto const msg_type = ( source == &g->u ) ? m_bad : m_info; add_msg( msg_type, _( "Striking the %1$s shocks %2$s!" ), m.name().c_str(), source->disp_name().c_str() ); } source->check_dead_state(); }
void mdeath::broken( monster &z ) { // Bail out if flagged (simulates eyebot flying away) if( z.no_corpse_quiet ) { return; } std::string item_id = z.type->id.str(); if (item_id.compare(0, 4, "mon_") == 0) { item_id.erase(0, 4); } // make "broken_manhack", or "broken_eyebot", ... item_id.insert(0, "broken_"); g->m.spawn_item( z.pos(), item_id, 1, 0, calendar::turn ); if( g->u.sees( z.pos() ) ) { add_msg( m_good, _( "The %s collapses!" ), z.name().c_str() ); } }
void mdeath::worm( monster &z ) { if( g->u.sees( z ) ) { if( z.type->dies.size() == 1 ) { add_msg( m_good, _( "The %s splits in two!" ), z.name() ); } else { add_msg( m_warning, _( "Two worms crawl out of the %s's corpse." ), z.name() ); } } std::vector <tripoint> wormspots; for( auto &&wormp : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* if( g->m.has_flag( "DIGGABLE", wormp ) && g->is_empty( wormp ) ) { wormspots.push_back( wormp ); } } int worms = 0; while( worms < 2 && !wormspots.empty() ) { const tripoint target = random_entry_removed( wormspots ); if( !g->critter_at( target ) ) { g->summon_mon( mon_halfworm, target ); worms++; } } }
bool gun_actor::call( monster &z ) const { Creature *target; if( z.friendly != 0 ) { // Attacking monsters, not the player! int boo_hoo; target = z.auto_find_hostile_target( range, boo_hoo ); if( target == nullptr ) { // Couldn't find any targets! if( boo_hoo > 0 && g->u.sees( z ) ) { // because that stupid oaf was in the way! add_msg( m_warning, ngettext( "Pointed in your direction, the %s emits an IFF warning beep.", "Pointed in your direction, the %s emits %d annoyed sounding beeps.", boo_hoo ), z.name().c_str(), boo_hoo ); } return false; } shoot( z, *target ); return true; } // Not friendly; hence, firing at the player too target = z.attack_target(); if( target == nullptr || rl_dist( z.pos(), target->pos() ) > range || !z.sees( *target ) ) { return false; } shoot( z, *target ); return true; }
// Simplified version of the function in monattack.cpp bool is_adjacent( const monster &z, const Creature &target ) { if( rl_dist( z.pos(), target.pos() ) != 1 ) { return false; } return z.posz() == target.posz(); }
void mdeath::boomer( monster &z ) { std::string explode = string_format( _( "a %s explode!" ), z.name() ); sounds::sound( z.pos(), 24, sounds::sound_t::combat, explode, false, "explosion", "small" ); for( auto &&dest : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* g->m.bash( dest, 10 ); if( monster *const z = g->critter_at<monster>( dest ) ) { z->stumble(); z->moves -= 250; } } if( rl_dist( z.pos(), g->u.pos() ) == 1 ) { g->u.add_env_effect( effect_boomered, bp_eyes, 2, 24_turns ); } g->m.propagate_field( z.pos(), fd_bile, 15, 1 ); }
void mdeath::broken_ammo( monster &z ) { if( g->u.sees( z.pos() ) ) { //~ %s is the possessive form of the monster's name add_msg( m_info, _( "The %s's interior compartment sizzles with destructive energy." ), z.name() ); } mdeath::broken( z ); }
void Creature_tracker::remove_from_location_map( const monster &critter ) { const tripoint &loc = critter.pos(); const auto pos_iter = monsters_by_location.find( loc ); if( pos_iter != monsters_by_location.end() ) { if( pos_iter->second.get() == &critter ) { monsters_by_location.erase( pos_iter ); } } }
void overmapbuffer::despawn_monster(const monster &critter) { // Get absolute coordinates of the monster in map squares, translate to submap position tripoint sm = ms_to_sm_copy( g->m.getabs( critter.pos() ) ); // Get the overmap coordinates and get the overmap, sm is now local to that overmap const point omp = sm_to_om_remain( sm.x, sm.y ); overmap &om = get( omp.x, omp.y ); // Store the monster using coordinates local to the overmap. om.monster_map.insert( std::make_pair( sm, critter ) ); }
void melee_actor::on_damage( monster &z, Creature &target, dealt_damage_instance &dealt ) const { if( target.is_player() ) { sfx::play_variant_sound( "mon_bite", "bite_hit", sfx::get_heard_volume( z.pos() ), sfx::get_heard_angle( z.pos() ) ); sfx::do_player_death_hurt( dynamic_cast<player &>( target ), false ); } auto msg_type = target.attitude_to( g->u ) == Creature::A_FRIENDLY ? m_bad : m_neutral; const body_part bp = dealt.bp_hit; target.add_msg_player_or_npc( msg_type, hit_dmg_u, hit_dmg_npc, z.name(), body_part_name_accusative( bp ) ); for( const auto &eff : effects ) { if( x_in_y( eff.chance, 100 ) ) { const body_part affected_bp = eff.affect_hit_bp ? bp : eff.bp; target.add_effect( eff.id, time_duration::from_turns( eff.duration ), affected_bp, eff.permanent ); } } }
void mdeath::fungus( monster &z ) { // If the fungus died from anti-fungal poison, don't pouf if( g->m.get_field_strength( z.pos(), fd_fungicidal_gas ) ) { return; } //~ the sound of a fungus dying sounds::sound( z.pos(), 10, sounds::sound_t::combat, _( "Pouf!" ), false, "misc", "puff" ); fungal_effects fe( *g, g->m ); for( auto &&sporep : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* if( g->m.impassable( sporep ) ) { continue; } // z is dead, don't credit it with the kill // Maybe credit z's killer? fe.fungalize( sporep, nullptr, 0.25 ); } }
void scatter_chunks( const std::string &chunk_name, int chunk_amt, monster &z, int distance, int pile_size = 1 ) { // can't have less than one item in a pile or it would cause an infinite loop pile_size = std::max( pile_size, 1 ); // can't have more items in a pile than total items pile_size = std::min( chunk_amt, pile_size ); distance = abs( distance ); const item chunk( chunk_name, calendar::turn, pile_size ); for( int i = 0; i < chunk_amt; i += pile_size ) { bool drop_chunks = true; tripoint tarp( z.pos() + point( rng( -distance, distance ), rng( -distance, distance ) ) ); const auto traj = line_to( z.pos(), tarp ); for( size_t j = 0; j < traj.size(); j++ ) { tarp = traj[j]; if( one_in( 2 ) && z.bloodType() != fd_null ) { g->m.add_splatter( z.bloodType(), tarp ); } else { g->m.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); } if( g->m.impassable( tarp ) ) { g->m.bash( tarp, distance ); if( g->m.impassable( tarp ) ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster), don't drop anything on it if( j > 0 ) { tarp = traj[j - 1]; } else { drop_chunks = false; } break; } } } if( drop_chunks ) { g->m.add_item_or_charges( tarp, chunk ); } } }
bool Creature_tracker::update_pos( const monster &critter, const tripoint &new_pos ) { if( critter.is_dead() ) { // find ignores dead critters anyway, changing their position in the // monsters_by_location map is useless. remove_from_location_map( critter ); return true; } if( const std::shared_ptr<monster> new_critter_ptr = find( new_pos ) ) { auto &othermon = *new_critter_ptr; if( othermon.is_hallucination() ) { othermon.die( nullptr ); } else { debugmsg( "update_zombie_pos: wanted to move %s to %d,%d,%d, but new location already has %s", critter.disp_name(), new_pos.x, new_pos.y, new_pos.z, othermon.disp_name() ); return false; } } const auto iter = std::find_if( monsters_list.begin(), monsters_list.end(), [&]( const std::shared_ptr<monster> &ptr ) { return ptr.get() == &critter; } ); if( iter != monsters_list.end() ) { monsters_by_location.erase( critter.pos() ); monsters_by_location[new_pos] = *iter; return true; } else { const tripoint &old_pos = critter.pos(); // We're changing the x/y/z coordinates of a zombie that hasn't been added // to the game yet. add_zombie() will update monsters_by_location for us. debugmsg( "update_zombie_pos: no %s at %d,%d,%d (moving to %d,%d,%d)", critter.disp_name(), old_pos.x, old_pos.y, old_pos.z, new_pos.x, new_pos.y, new_pos.z ); // Rebuild cache in case the monster actually IS in the game, just bugged rebuild_cache(); return false; } }
void mdeath::acid( monster &z ) { if( g->u.sees( z ) ) { if( z.type->dies.size() == 1 ) { //If this death function is the only function. The corpse gets dissolved. add_msg( m_mixed, _( "The %s's body dissolves into acid." ), z.name() ); } else { add_msg( m_warning, _( "The %s's body leaks acid." ), z.name() ); } } g->m.add_field( z.pos(), fd_acid, 3 ); }
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 ); }
bool Creature_tracker::add(monster &critter) { if (critter.type->id == "mon_null") { // Don't wanna spawn null monsters o.O return false; } if (-1 != mon_at(critter.pos())) { debugmsg("add_zombie: there's already a monster at %d,%d", critter.posx(), critter.posy()); return false; } _old_monsters_by_location[point(critter.posx(), critter.posy())] = _old_monsters_list.size(); _old_monsters_list.push_back(new monster(critter)); return true; }
bool Creature_tracker::update_pos( const monster &critter, const tripoint &new_pos ) { const auto old_pos = critter.pos(); if( critter.is_dead() ) { // mon_at ignores dead critters anyway, changing their position in the // monsters_by_location map is useless. remove_from_location_map( critter ); return true; } const int critter_id = mon_at( old_pos ); const int new_critter_id = mon_at( new_pos ); if( new_critter_id >= 0 ) { auto &othermon = *monsters_list[new_critter_id]; if( othermon.is_hallucination() ) { othermon.die( nullptr ); } else { debugmsg( "update_zombie_pos: wanted to move %s to %d,%d,%d, but new location already has %s", critter.disp_name().c_str(), new_pos.x, new_pos.y, new_pos.z, othermon.disp_name().c_str() ); return false; } } if( critter_id >= 0 ) { if( &critter == monsters_list[critter_id] ) { monsters_by_location.erase( old_pos ); monsters_by_location[new_pos] = critter_id; return true; } else { const auto &othermon = *monsters_list[critter_id]; debugmsg( "update_zombie_pos: wanted to move %s from old location %d,%d,%d, but it had %s instead", critter.disp_name().c_str(), old_pos.x, old_pos.y, old_pos.z, othermon.disp_name().c_str() ); return false; } } else { // We're changing the x/y/z coordinates of a zombie that hasn't been added // to the game yet. add_zombie() will update monsters_by_location for us. debugmsg( "update_zombie_pos: no %s at %d,%d,%d (moving to %d,%d,%d)", critter.disp_name().c_str(), old_pos.x, old_pos.y, old_pos.z, new_pos.x, new_pos.y, new_pos.z ); // Rebuild cache in case the monster actually IS in the game, just bugged rebuild_cache(); return false; } return false; }
void mdeath::vine_cut( monster &z ) { std::vector<monster *> vines; for( const tripoint &tmp : g->m.points_in_radius( z.pos(), 1 ) ) { if( tmp == z.pos() ) { continue; // Skip ourselves } if( monster *const z = g->critter_at<monster>( tmp ) ) { if( z->type->id == mon_creeper_vine ) { vines.push_back( z ); } } } for( auto &vine : vines ) { bool found_neighbor = false; tripoint tmp = vine->pos(); int &x = tmp.x; int &y = tmp.y; for( x = vine->posx() - 1; x <= vine->posx() + 1 && !found_neighbor; x++ ) { for( y = vine->posy() - 1; y <= vine->posy() + 1 && !found_neighbor; y++ ) { if( x != z.posx() || y != z.posy() ) { // Not the dying vine if( monster *const v = g->critter_at<monster>( { x, y, z.posz() } ) ) { if( v->type->id == mon_creeper_hub || v->type->id == mon_creeper_vine ) { found_neighbor = true; } } } } } if( !found_neighbor ) { vine->die( &z ); } } }
void mdeath::ratking( monster &z ) { g->u.remove_effect( effect_rat ); if( g->u.sees( z ) ) { add_msg( m_warning, _( "Rats suddenly swarm into view." ) ); } std::vector <tripoint> ratspots; for( auto &&ratp : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* if( g->is_empty( ratp ) ) { ratspots.push_back( ratp ); } } for( int rats = 0; rats < 7 && !ratspots.empty(); rats++ ) { g->summon_mon( mon_sewer_rat, random_entry_removed( ratspots ) ); } }
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 ); }