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::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::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 ); }
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; }
void overmapbuffer::despawn_monster(const monster &critter) { // Get absolute coordinates of the monster in map squares, translate to submap position point sm = ms_to_sm_copy( g->m.getabs( critter.posx(), critter.posy() ) ); // Get the overmap coordinates and get the overmap, sm is now local to that overmap const point omp = sm_to_om_remain( sm ); overmap &om = get( omp.x, omp.y ); // Store the monster using coordinates local to the overmap. // TODO: with Z-levels this should probably be taken from the critter om.monster_map.insert( std::make_pair( tripoint(sm.x, sm.y, g->levz), critter ) ); }
bool Creature_tracker::update_pos(const monster &critter, const int new_x_pos, const int new_y_pos) { if (critter.posx() == new_x_pos && critter.posy() == new_y_pos) { return true; // success? } bool success = false; const int dead_critter_id = dead_mon_at(point(critter.posx(), critter.posy())); const int live_critter_id = mon_at(point(critter.posx(), critter.posy())); const int critter_id = critter.dead ? dead_critter_id : live_critter_id; const int new_critter_id = mon_at(new_x_pos, new_y_pos); if (new_critter_id >= 0 && !_old_monsters_list[new_critter_id]->dead) { debugmsg("update_zombie_pos: new location %d,%d already has zombie %d", new_x_pos, new_y_pos, new_critter_id); } else if (critter_id >= 0) { if (&critter == _old_monsters_list[critter_id]) { _old_monsters_by_location.erase(point(critter.posx(), critter.posy())); _old_monsters_by_location[point(new_x_pos, new_y_pos)] = critter_id; success = true; } else { debugmsg("update_zombie_pos: old location %d,%d had zombie %d instead", critter.posx(), critter.posy(), critter_id); } } else { // We're changing the x/y coordinates of a zombie that hasn't been added // to the game yet. add_zombie() will update _old_monsters_by_location for us. debugmsg("update_zombie_pos: no such zombie at %d,%d (moving to %d,%d)", critter.posx(), critter.posy(), new_x_pos, new_y_pos); } return success; }
void overmapbuffer::despawn_monster(const monster &critter) { overmap::monster_data mdata; // Get absolute coordinates of the monster in map squares, translate to submap position point sm = ms_to_sm_copy( g->m.getabs( critter.posx(), critter.posy() ) ); // Get the overmap coordinates and get the overmap, sm is now local to that overmap const point omp = sm_to_om_remain( sm ); overmap &om = get( omp.x, omp.y ); mdata.x = sm.x; // Local to the overmap mdata.y = sm.y; mdata.z = g->levz; // TODO: with Z-levels this should probably be taken from the critter mdata.mon = critter; // the exact position is retained in here om.monsters.push_back( mdata ); }
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 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; }