예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #5
0
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 ) );
}
예제 #6
0
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;
}
예제 #7
0
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 );
}
예제 #8
0
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 );
        }
    }
}
예제 #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;
}