예제 #1
0
void give_and_activate( player &p, bionic_id const &bioid )
{
    INFO( "bionic " + bioid.str() + " is valid" );
    REQUIRE( bioid.is_valid() );

    p.add_bionic( bioid );
    INFO( "dummy has gotten " + bioid.str() + " bionic " );
    REQUIRE( p.has_bionic( bioid ) );

    // get bionic's index - might not be "last added" due to "integrated" ones
    int bioindex = -1;
    for( size_t i = 0; i < p.my_bionics->size(); i++ ) {
        const auto &bio = ( *p.my_bionics )[ i ];
        if( bio.id == bioid ) {
            bioindex = i;
        }
    }
    REQUIRE( bioindex != -1 );

    const bionic &bio = p.bionic_at_index( bioindex );
    REQUIRE( bio.id == bioid );

    // turn on if possible
    if( bio.id->toggled && !bio.powered ) {
        p.activate_bionic( bioindex );
        INFO( "bionic " + bio.id.str() + " with index " + std::to_string( bioindex ) + " is active " );
        REQUIRE( p.has_active_bionic( bioid ) );
    }
}
예제 #2
0
bool ma_requirements::is_valid_player(player &u)
{
    for( auto buff_id : req_buffs ) {

        if (!u.has_mabuff(buff_id)) {
            return false;
        }
    }

    //A technique is valid if it applies to unarmed strikes, if it applies generally
    //to all weapons (such as Ninjutsu sneak attacks or innate weapon techniques like RAPID)
    //or if the weapon is flagged as being compatible with the style. Some techniques have
    //further restrictions on required weapon properties (is_valid_weapon).
    bool cqb = u.has_active_bionic("bio_cqb");
    bool valid = ((unarmed_allowed && u.unarmed_attack()) ||
                  (melee_allowed && !u.unarmed_attack() && is_valid_weapon(u.weapon)) ||
                  (u.has_weapon() && martialarts[u.style_selected].has_weapon(u.weapon.type->id) &&
                   is_valid_weapon(u.weapon))) &&
                 ((u.skillLevel("melee") >= min_melee &&
                   u.skillLevel("unarmed") >= min_unarmed &&
                   u.skillLevel("bashing") >= min_bashing &&
                   u.skillLevel("cutting") >= min_cutting &&
                   u.skillLevel("stabbing") >= min_stabbing) || cqb);

    return valid;
}
예제 #3
0
bool ma_requirements::is_valid_player( const player &u ) const
{
    for( const auto &buff_id : req_buffs ) {
        if (!u.has_mabuff(buff_id)) {
            return false;
        }
    }

    //A technique is valid if it applies to unarmed strikes, if it applies generally
    //to all weapons (such as Ninjutsu sneak attacks or innate weapon techniques like RAPID)
    //or if the weapon is flagged as being compatible with the style. Some techniques have
    //further restrictions on required weapon properties (is_valid_weapon).
    bool cqb = u.has_active_bionic( bionic_id( "bio_cqb" ) );
    // There are 4 different cases of "armedness":
    // Truly unarmed, unarmed weapon, style-allowed weapon, generic weapon
    bool valid_weapon =
        ( unarmed_allowed && u.unarmed_attack() &&
            ( !strictly_unarmed || !u.is_armed() ) ) ||
        ( is_valid_weapon( u.weapon ) &&
            ( melee_allowed || u.style_selected.obj().has_weapon( u.weapon.typeId() ) ) );
    if( !valid_weapon ) {
        return false;
    }

    for( const auto &pr : min_skill ) {
        if( ( cqb ? 5 : (int)u.get_skill_level( pr.first ) ) < pr.second ) {
            return false;
        }
    }

    return true;
}
예제 #4
0
void monster::hit_player(game *g, player &p, bool can_grab)
{
    moves -= 100;

    if (type->melee_dice == 0) // We don't attack, so just return
    {
        return;
    }
    add_effect(ME_HIT_BY_PLAYER, 3); // Make us a valid target for a few turns
    if (has_flag(MF_HIT_AND_RUN))
    {
        add_effect(ME_RUN, 4);
    }
    bool is_npc = p.is_npc();
    bool u_see = (!is_npc || g->u_see(p.posx, p.posy));
    std::string you  = (is_npc ? p.name : "you");
    std::string You  = (is_npc ? p.name : "You");
    std::string your = (is_npc ? p.name + "'s" : "your");
    std::string Your = (is_npc ? p.name + "'s" : "Your");
    body_part bphit;
    int side = rng(0, 1);
    int dam = hit(g, p, bphit), cut = type->melee_cut, stab = 0;
    technique_id tech = p.pick_defensive_technique(g, this, NULL);
    p.perform_defensive_technique(tech, g, this, NULL, bphit, side, dam, cut, stab);

    //110*e^(-.3*[melee skill of monster]) = % chance to miss. *100 to track .01%'s
    //Returns ~80% at 1, drops quickly to 33% at 4, then slowly to 5% at 10 and 1% at 16
    if (rng(0, 10000) < 11000 * exp(-.3 * type->melee_skill))
    {
        g->add_msg("The %s misses.", name().c_str());
    }
    else
    {
        //Reduce player's ability to dodge by monster's ability to hit
        int dodge_ii = p.dodge(g) - rng(0, type->melee_skill);
        if (dodge_ii < 0)
        {
            dodge_ii = 0;
        }

        // 100/(1+99*e^(-.6*[dodge() return modified by monster's skill])) = % chance to dodge
        // *100 to track .01%'s
        // 1% minimum, scales slowly to 16% at 5, then rapidly to 80% at 10,
        // then returns less with each additional point, reaching 99% at 16
        if (rng(0, 10000) < 10000/(1 + 99 * exp(-.6 * dodge_ii)))
        {
            g->add_msg("%s dodge the %s.", You.c_str(), name().c_str());
            p.practice(g->turn, "dodge", type->melee_skill * 2); //Better monster = more skill gained
        }

        //Successful hit with damage
        else if (dam > 0)
        {
            p.practice(g->turn, "dodge", type->melee_skill);
            if (u_see && tech != TEC_BLOCK)
            {
                g->add_msg("The %s hits %s %s.", name().c_str(), your.c_str(),
                           body_part_name(bphit, side).c_str());
            }

            // Attempt defensive moves
            if (!is_npc)
            {
                if (g->u.activity.type == ACT_RELOAD)
                {
                    g->add_msg("You stop reloading.");
                }
                else if (g->u.activity.type == ACT_READ)
                {
                    g->add_msg("You stop reading.");
                }
                else if (g->u.activity.type == ACT_CRAFT || g->u.activity.type == ACT_LONGCRAFT)
                {
                    g->add_msg("You stop crafting.");
                    g->u.activity.type = ACT_NULL;
                }
            }
            if (p.has_active_bionic("bio_ods"))
            {
                if (u_see)
                {
                    g->add_msg("%s offensive defense system shocks it!", Your.c_str());
                }
                if (hurt(rng(10, 40)))
                    die(g);
            }
            if (p.encumb(bphit) == 0 &&(p.has_trait(PF_SPINES) || p.has_trait(PF_QUILLS)))
            {
                int spine = rng(1, (p.has_trait(PF_QUILLS) ? 20 : 8));
                g->add_msg("%s %s puncture it!", Your.c_str(),
                           (g->u.has_trait(PF_QUILLS) ? "quills" : "spines"));
                if (hurt(spine))
                    die(g);
            }

            if (dam + cut <= 0)
            {
                return; // Defensive technique canceled damage.
            }

            //Hurt the player
            dam = p.hit(g, bphit, side, dam, cut);

            //Monster effects
            if (dam > 0 && has_flag(MF_VENOM))
            {
                if (!is_npc)
                {
                    g->add_msg("You're poisoned!");
                }
                p.add_disease("poison", 30);
            }
            else if (dam > 0 && has_flag(MF_BADVENOM))
            {
                if (!is_npc)
                {
                    g->add_msg("You feel poison flood your body, wracking you with pain...");
                }
                p.add_disease("badpoison", 40);
            }
            if (has_flag(MF_BLEED) && dam > 6 && cut > 0)
            {
                if (!is_npc)
                {
                    g->add_msg("You're Bleeding!");
                }
                p.add_disease("bleed", 60);
            }

            //Same as monster's chance to not miss
            if (can_grab && has_flag(MF_GRABS) && (rng(0, 10000) > 11000 * exp(-.3 * type->melee_skill)))
            {
                if (!is_npc)
                {
                    g->add_msg("The %s grabs you!", name().c_str());
                }
                if (p.weapon.has_technique(TEC_BREAK, &p) &&
                    dice(p.dex_cur + p.skillLevel("melee"), 12) > dice(type->melee_dice, 10))
                {
                    if (!is_npc)
                    {
                        g->add_msg("You break the grab!");
                    }
                }
                else
                    hit_player(g, p, false); //We grabed, so hit them again
            }

            //Counter-attack?
            if (tech == TEC_COUNTER && !is_npc)
            {
                g->add_msg("Counter-attack!");
                // A counterattack is a free action to avoid stunlocking the player.
                int player_moves = p.moves;
                hurt( p.hit_mon(g, this) );
                p.moves = player_moves;
            }
        }
    }

    // if dam > 0
    if (is_npc)
    {
        if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0)
        {
            npc* tmp = dynamic_cast<npc*>(&p);
            tmp->die(g);
            int index = g->npc_at(p.posx, p.posy);
            if (index != -1 && index < g->active_npc.size())
            {
                g->active_npc.erase(g->active_npc.begin() + index);
            }
            plans.clear();
        }
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    for (int i = 0; i < type->anger.size(); i++)
    {
        if (type->anger[i] == MTRIG_FRIEND_ATTACKED)
        {
            anger_adjust += 15;
        }
    }
    for (int i = 0; i < type->placate.size(); i++)
    {
        if (type->placate[i] == MTRIG_FRIEND_ATTACKED)
        {
            anger_adjust -= 15;
        }
    }
    for (int i = 0; i < type->fear.size(); i++)
    {
        if (type->fear[i] == MTRIG_FRIEND_ATTACKED)
        {
            morale_adjust -= 15;
        }
    }
    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (int i = 0; i < g->z.size(); i++)
        {
            g->z[i].morale += morale_adjust;
            g->z[i].anger += anger_adjust;
        }
    }
}
예제 #5
0
void monster::hit_player(game *g, player &p, bool can_grab)
{
    moves -= 100;

    if (type->melee_dice == 0) // We don't attack, so just return
    {
        return;
    }
    add_effect(ME_HIT_BY_PLAYER, 3); // Make us a valid target for a few turns
    if (has_flag(MF_HIT_AND_RUN))
    {
        add_effect(ME_RUN, 4);
    }
    bool is_npc = p.is_npc();
    bool u_see = (!is_npc || g->u_see(p.posx, p.posy));
    std::string you  = (is_npc ? p.name : "you");
    std::string You  = (is_npc ? p.name : "You");
    std::string your = (is_npc ? p.name + "'s" : "your");
    std::string Your = (is_npc ? p.name + "'s" : "Your");
    body_part bphit;
    int dam = hit(g, p, bphit), cut = type->melee_cut, stab = 0;
    int side = random_side(bphit);

    //110*e^(-.3*[melee skill of monster]) = % chance to miss. *100 to track .01%'s
    //Returns ~80% at 1, drops quickly to 33% at 4, then slowly to 5% at 10 and 1% at 16
    if (rng(0, 10000) < 11000 * exp(-.3 * type->melee_skill))
    {
        if (u_see) {
            g->add_msg(_("The %s misses."), name().c_str());
        }
    }
    else
    {
        if (!g->u.uncanny_dodge())
        {
            //Reduce player's ability to dodge by monster's ability to hit
            int dodge_ii = p.dodge(g) - rng(0, type->melee_skill);
            if (dodge_ii < 0)
            {
                dodge_ii = 0;
            }

            // 100/(1+99*e^(-.6*[dodge() return modified by monster's skill])) = % chance to dodge
            // *100 to track .01%'s
            // 1% minimum, scales slowly to 16% at 5, then rapidly to 80% at 10,
            // then returns less with each additional point, reaching 99% at 16
            if (rng(0, 10000) < 10000/(1 + 99 * exp(-.6 * dodge_ii)))
            {
                if (is_npc) {
                    if(u_see) {
                        g->add_msg(_("%1$s dodges the %2$s."), p.name.c_str(), name().c_str());
                    }
                } else {
                    g->add_msg(_("You dodge the %s."), name().c_str());
                }
                p.practice(g->turn, "dodge", type->melee_skill * 2); //Better monster = more skill gained
            }

            //Successful hit with damage
            else if (dam > 0)
            {
                p.practice(g->turn, "dodge", type->melee_skill);

                if(!p.block_hit(g, this, NULL, bphit, side, dam, cut, stab) && u_see) {
                    if (is_npc) {
                        if( u_see ) {
                            g->add_msg(_("The %1$s hits %2$s's %3$s."), name().c_str(),
                                       p.name.c_str(), body_part_name(bphit, side).c_str());
                        }
                    } else {
                        g->add_msg(_("The %1$s hits your %2$s."), name().c_str(),
                                   body_part_name(bphit, side).c_str());
                    }
                }

                // Attempt defensive moves
                if (!is_npc)
                {
                    if (g->u.activity.type == ACT_RELOAD)
                    {
                        g->add_msg(_("You stop reloading."));
                    }
                    else if (g->u.activity.type == ACT_READ)
                    {
                        g->add_msg(_("You stop reading."));
                    }
                    else if (g->u.activity.type == ACT_CRAFT || g->u.activity.type == ACT_LONGCRAFT)
                    {
                        g->add_msg(_("You stop crafting."));
                        g->u.activity.type = ACT_NULL;
                    }
                }

                if (p.has_active_bionic("bio_ods"))
                {
                    if (!is_npc) {
                        g->add_msg(_("Your offensive defense system shocks it!"),
                                   p.name.c_str());
                    } else if (u_see) {
                        g->add_msg(_("%s's offensive defense system shocks it!"),
                                   p.name.c_str());
                    }
                    hurt(rng(10, 40));
                }
                if (p.encumb(bphit) == 0 &&(p.has_trait("SPINES") || p.has_trait("QUILLS")))
                {
                    int spine = rng(1, (p.has_trait("QUILLS") ? 20 : 8));
                    if (is_npc) {
                        if( u_see ) {
                            g->add_msg(_("%1$s's %2$s puncture it!"), p.name.c_str(),
                                       (g->u.has_trait("QUILLS") ? _("quills") : _("spines")));
                        }
                    } else {
                        g->add_msg(_("Your %s puncture it!"),
                                   (g->u.has_trait("QUILLS") ? _("quills") : _("spines")));
                    }
                    hurt(spine);
                }

                if (dam + cut <= 0)
                {
                    return; // Defensive technique canceled damage.
                }

                //Hallucinations don't actually hurt the player, but do produce the message
                if(is_hallucination()) {

                    //~14% chance of vanishing after hitting the player
                    if(one_in(7)) {
                      die(g);
                      return;
                    }

                } else {

                    //Hurt the player
                    dam = p.hit(g, bphit, side, dam, cut);

                    //Monster effects
                    if (dam > 0 && has_flag(MF_VENOM)) {
                        g->add_msg_if_player(&p, _("You're poisoned!"));
                        p.add_disease("poison", 30);
                    } else if (dam > 0 && has_flag(MF_BADVENOM)) {
                        g->add_msg_if_player(&p, _("You feel poison flood your body, wracking you with pain..."));
                        p.add_disease("badpoison", 40);
                    } else if (dam > 0 && has_flag(MF_PARALYZE)) {
                        g->add_msg_if_player(&p, _("You feel poison enter your body!"));
                        p.add_disease("paralyzepoison", 100, false, 1, 20, 100);
                    }

                    if (has_flag(MF_BLEED) && dam > 6 && cut > 0) {
                        g->add_msg_if_player(&p, _("You're Bleeding!"));
                        p.add_disease("bleed", 60, false, 1, 3, 120, 1, bphit, side, true);
                    }

                    //Same as monster's chance to not miss
                    if (can_grab && has_flag(MF_GRABS) &&
                        (rng(0, 10000) > 11000 * exp(-.3 * type->melee_skill)))
                    {
                        g->add_msg(_("The %s grabs you!"), name().c_str());
                        if (p.has_grab_break_tec() &&
                            dice(p.dex_cur + p.skillLevel("melee"), 12) > dice(type->melee_dice, 10))
                        {
                            g->add_msg_if_player(&p, _("You break the grab!"));
                        } else {
                            hit_player(g, p, false); //We grabed, so hit them again
                        }
                    }

                }
                // TODO: readd with counter mechanic
            }
        }
    }

    // if dam > 0
    if (is_npc)
    {
        if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0)
        {
            npc* tmp = dynamic_cast<npc*>(&p);
            tmp->die(g);
            int index = g->npc_at(p.posx, p.posy);
            if (index != -1 && index < g->active_npc.size())
            {
                g->active_npc.erase(g->active_npc.begin() + index);
            }
            plans.clear();
        }
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    if (type->has_anger_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust += 15;
    }
    if (type->has_fear_trigger(MTRIG_FRIEND_ATTACKED)){
        morale_adjust -= 15;
    }
    if (type->has_placate_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust -= 15;
    }

    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (int i = 0; i < g->num_zombies(); i++)
        {
            g->zombie(i).morale += morale_adjust;
            g->zombie(i).anger += anger_adjust;
        }
    }
}
예제 #6
0
void game::throw_item(player &p, int tarx, int tary, item &thrown,
                      std::vector<point> &trajectory)
{
    int deviation = 0;
    int trange = 1.5 * rl_dist(p.posx, p.posy, tarx, tary);
    std::set<std::string> no_effects;

    // Throwing attempts below "Basic Competency" level are extra-bad
    int skillLevel = p.skillLevel("throw");

    if (skillLevel < 3)
        deviation += rng(0, 8 - skillLevel);

    if (skillLevel < 8)
        deviation += rng(0, 8 - skillLevel);
    else
        deviation -= skillLevel - 6;

    deviation += p.throw_dex_mod();

    if (p.per_cur < 6)
        deviation += rng(0, 8 - p.per_cur);
    else if (p.per_cur > 8)
        deviation -= p.per_cur - 8;

    deviation += rng(0, p.encumb(bp_hands) * 2 + p.encumb(bp_eyes) + 1);
    if (thrown.volume() > 5)
        deviation += rng(0, 1 + (thrown.volume() - 5) / 4);
    if (thrown.volume() == 0)
        deviation += rng(0, 3);

    deviation += rng(0, 1 + abs(p.str_cur - thrown.weight() / 113));

    double missed_by = .01 * deviation * trange;
    bool missed = false;
    int tart;

    if (missed_by >= 1)
    {
        // We missed D:
        // Shoot a random nearby space?
        if (missed_by > 9)
            missed_by = 9;
        tarx += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
        tary += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
        if (m.sees(p.posx, p.posy, tarx, tary, -1, tart))
            trajectory = line_to(p.posx, p.posy, tarx, tary, tart);
        else
            trajectory = line_to(p.posx, p.posy, tarx, tary, 0);
        missed = true;
        add_msg_if_player(&p,_("You miss!"));
    }
    else if (missed_by >= .6)
    {
        // Hit the space, but not necessarily the monster there
        missed = true;
        add_msg_if_player(&p,_("You barely miss!"));
    }

    std::string message;
    int real_dam = (thrown.weight() / 452 + thrown.type->melee_dam / 2 + p.str_cur / 2) /
               double(2 + double(thrown.volume() / 4));
    if (real_dam > thrown.weight() / 40)
        real_dam = thrown.weight() / 40;
    if (p.has_active_bionic("bio_railgun") && (thrown.made_of("iron") || thrown.made_of("steel")))
    {
        real_dam *= 2;
    }
    int dam = real_dam;

    int i = 0, tx = 0, ty = 0;
    for (i = 0; i < trajectory.size() && dam >= 0; i++)
    {
        message = "";
        double goodhit = missed_by;
        tx = trajectory[i].x;
        ty = trajectory[i].y;

        // If there's a monster in the path of our item, and either our aim was true,
        //  OR it's not the monster we were aiming at and we were lucky enough to hit it
        if (mon_at(tx, ty) != -1 &&
           (!missed || one_in(7 - int(z[mon_at(tx, ty)].type->size))))
        {
            if (rng(0, 100) < 20 + skillLevel * 12 &&
                thrown.type->melee_cut > 0)
            {
                if (!p.is_npc())
                {
                    message += string_format(_(" You cut the %s!"), z[mon_at(tx, ty)].name().c_str());
                }
                if (thrown.type->melee_cut > z[mon_at(tx, ty)].armor_cut())
                    dam += (thrown.type->melee_cut - z[mon_at(tx, ty)].armor_cut());
            }
            if (thrown.made_of("glass") && !thrown.active && // active = molotov, etc.
                rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume())
            {
                if (u_see(tx, ty))
                    add_msg(_("The %s shatters!"), thrown.tname().c_str());
                for (int i = 0; i < thrown.contents.size(); i++)
                    m.add_item_or_charges(tx, ty, thrown.contents[i]);
                    sound(tx, ty, 16, _("glass breaking!"));
                    int glassdam = rng(0, thrown.volume() * 2);
                    if (glassdam > z[mon_at(tx, ty)].armor_cut())
                        dam += (glassdam - z[mon_at(tx, ty)].armor_cut());
            }
            else
                m.add_item_or_charges(tx, ty, thrown);
            if (i < trajectory.size() - 1)
                goodhit = double(double(rand() / RAND_MAX) / 2);
            if (goodhit < .1 && !z[mon_at(tx, ty)].has_flag(MF_NOHEAD))
            {
                message = _("Headshot!");
                dam = rng(dam, dam * 3);
                p.practice(turn, "throw", 5);
            }
            else if (goodhit < .2)
            {
                message = _("Critical!");
                dam = rng(dam, dam * 2);
                p.practice(turn, "throw", 2);
            }
            else if (goodhit < .4)
                dam = rng(int(dam / 2), int(dam * 1.5));
            else if (goodhit < .5)
            {
                message = _("Grazing hit.");
                dam = rng(0, dam);
            }
            if (u_see(tx, ty)) {
                g->add_msg_player_or_npc(&p,
                    _("%s You hit the %s for %d damage."),
                    _("%s <npcname> hits the %s for %d damage."),
                    message.c_str(), z[mon_at(tx, ty)].name().c_str(), dam);
            }
            if (z[mon_at(tx, ty)].hurt(dam, real_dam))
                kill_mon(mon_at(tx, ty), !p.is_npc());
            return;
        }
        else // No monster hit, but the terrain might be.
        {
            m.shoot(this, tx, ty, dam, false, no_effects);
        }
        if (m.move_cost(tx, ty) == 0)
        {
            if (i > 0)
            {
                tx = trajectory[i - 1].x;
                ty = trajectory[i - 1].y;
            }
            else
            {
                tx = u.posx;
                ty = u.posy;
            }
            i = trajectory.size();
        }
        if (p.has_active_bionic("bio_railgun") && (thrown.made_of("iron") || thrown.made_of("steel")))
        {
            m.add_field(this, tx, ty, fd_electricity, rng(2,3));
        }
    }
    if (m.move_cost(tx, ty) == 0)
    {
        if (i > 1)
        {
            tx = trajectory[i - 2].x;
            ty = trajectory[i - 2].y;
        }
        else
        {
            tx = u.posx;
            ty = u.posy;
        }
    }
    if (thrown.made_of("glass") && !thrown.active && // active means molotov, etc
        rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume())
    {
        if (u_see(tx, ty))
            add_msg(_("The %s shatters!"), thrown.tname().c_str());
        for (int i = 0; i < thrown.contents.size(); i++)
            m.add_item_or_charges(tx, ty, thrown.contents[i]);
        sound(tx, ty, 16, _("glass breaking!"));
    }
    else
    {
        sound(tx, ty, 8, _("thud."));
        m.add_item_or_charges(tx, ty, thrown);
    }
}
예제 #7
0
void monster::hit_player(game *g, player &p, bool can_grab)
{
 if (type->melee_dice == 0) // We don't attack, so just return
  return;
 add_effect(ME_HIT_BY_PLAYER, 3); // Make us a valid target for a few turns
 if (has_flag(MF_HIT_AND_RUN))
  add_effect(ME_RUN, 4);
 bool is_npc = p.is_npc();
 int  junk;
 bool u_see = (!is_npc || g->u_see(p.posx, p.posy, junk));
 std::string you  = (is_npc ? p.name : "you");
 std::string You  = (is_npc ? p.name : "You");
 std::string your = (is_npc ? p.name + "'s" : "your");
 std::string Your = (is_npc ? p.name + "'s" : "Your");
 body_part bphit;
 int side = rng(0, 1);
 int dam = hit(g, p, bphit), cut = type->melee_cut, stab = 0;
 technique_id tech = p.pick_defensive_technique(g, this, NULL);
 p.perform_defensive_technique(tech, g, this, NULL, bphit, side,
                               dam, cut, stab);
 if (dam == 0 && u_see)
  g->add_msg("The %s misses %s.", name().c_str(), you.c_str());
 else if (dam > 0) {
  if (u_see && tech != TEC_BLOCK)
   g->add_msg("The %s hits %s %s.", name().c_str(), your.c_str(),
              body_part_name(bphit, side).c_str());
// Attempt defensive moves

  if (!is_npc) {
   if (g->u.activity.type == ACT_RELOAD)
    g->add_msg("You stop reloading.");
   else if (g->u.activity.type == ACT_READ)
    g->add_msg("You stop reading.");
   else if (g->u.activity.type == ACT_CRAFT)
    g->add_msg("You stop crafting.");
   g->u.activity.type = ACT_NULL;
  }
  if (p.has_active_bionic(bio_ods)) {
   if (u_see)
    g->add_msg("%s offensive defense system shocks it!", Your.c_str());
   hurt(rng(10, 40));
  }
  if (p.encumb(bphit) == 0 &&
      (p.has_trait(PF_SPINES) || p.has_trait(PF_QUILLS))) {
   int spine = rng(1, (p.has_trait(PF_QUILLS) ? 20 : 8));
   g->add_msg("%s %s puncture it!", Your.c_str(),
              (g->u.has_trait(PF_QUILLS) ? "quills" : "spines"));
   hurt(spine);
  }

  if (dam + cut <= 0)
   return; // Defensive technique canceled damage.

  p.hit(g, bphit, side, dam, cut);
  if (has_flag(MF_VENOM)) {
   if (!is_npc)
    g->add_msg("You're poisoned!");
   p.add_disease(DI_POISON, 30, g);
  } else if (has_flag(MF_BADVENOM)) {
   if (!is_npc)
    g->add_msg("You feel poison flood your body, wracking you with pain...");
   p.add_disease(DI_BADPOISON, 40, g);
  }
  if (has_flag(MF_BLEED) && dam > 6 && cut > 0) {
   if (!is_npc)
    g->add_msg("You're Bleeding!");
   p.add_disease(DI_BLEED, 30, g);
  }
  if (can_grab && has_flag(MF_GRABS) &&
      dice(type->melee_dice, 10) > dice(p.dodge(g), 10)) {
   if (!is_npc)
    g->add_msg("The %s grabs you!", name().c_str());
   if (p.weapon.has_technique(TEC_BREAK, &p) &&
       dice(p.dex_cur + p.skillLevel("melee").level(), 12) > dice(type->melee_dice, 10)){
    if (!is_npc)
     g->add_msg("You break the grab!");
   } else
    hit_player(g, p, false);
  }

  if (tech == TEC_COUNTER && !is_npc) {
   g->add_msg("Counter-attack!");
   hurt( p.hit_mon(g, this) );
  }
 } // if dam > 0
 if (is_npc) {
  if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0) {
   npc* tmp = dynamic_cast<npc*>(&p);
   tmp->die(g);
   int index = g->npc_at(p.posx, p.posy);
   if (index != -1 && index < g->active_npc.size())
    g->active_npc.erase(g->active_npc.begin() + index);
   plans.clear();
  }
 }
// Adjust anger/morale of same-species monsters, if appropriate
 int anger_adjust = 0, morale_adjust = 0;
 for (unsigned int i = 0; i < type->anger.size(); i++) {
  if (type->anger[i] == MTRIG_FRIEND_ATTACKED)
   anger_adjust += 15;
 }
 for (unsigned int i = 0; i < type->placate.size(); i++) {
  if (type->placate[i] == MTRIG_FRIEND_ATTACKED)
   anger_adjust -= 15;
 }
 for (unsigned int i = 0; i < type->fear.size(); i++) {
  if (type->fear[i] == MTRIG_FRIEND_ATTACKED)
   morale_adjust -= 15;
 }
 if (anger_adjust != 0 && morale_adjust != 0) {
  for (unsigned int i = 0; i < g->z.size(); i++) {
   g->z[i].morale += morale_adjust;
   g->z[i].anger += anger_adjust;
  }
 }
}
예제 #8
0
void monster::hit_player(game *g, player &p)
{
 if (type->melee_dice == 0) // We don't attack, so just return
  return;
 bool is_npc = p.is_npc();
 int  junk;
 bool u_see = (!is_npc || g->u_see(p.posx, p.posy, junk));
 std::string you  = (is_npc ? p.name : "you");
 std::string your = (is_npc ? p.name + "'s" : "your");
 std::string Your = (is_npc ? p.name + "'s" : "Your");
 body_part bphit;
 int side = rng(0, 1);
 int dam = hit(p, bphit);
 if (dam == 0 && u_see)
  g->add_msg("The %s misses %s.", name().c_str(), you.c_str());
 else if (dam > 0) {
  if (u_see)
   g->add_msg("The %s hits %s %s.", name().c_str(), your.c_str(),
              body_part_name(bphit, side).c_str());
  if (!is_npc) {
   if (g->u.activity.type == ACT_RELOAD)
    g->add_msg("You stop reloading.");
   else if (g->u.activity.type == ACT_READ)
    g->add_msg("You stop reading.");
   else if (g->u.activity.type == ACT_CRAFT)
    g->add_msg("You stop crafting.");
   g->u.activity.type = ACT_NULL;
  }
  if (p.has_active_bionic(bio_ods)) {
   if (u_see)
    g->add_msg("%s offensive defense system shocks it!", Your.c_str());
   hurt(rng(10, 40));
  }
  if (p.encumb(bphit) == 0 &&
      (p.has_trait(PF_SPINES) || p.has_trait(PF_QUILLS))) {
   int spine = rng(1, (p.has_trait(PF_QUILLS) ? 20 : 8));
   g->add_msg("%s %s puncture it!", Your.c_str(),
              (g->u.has_trait(PF_QUILLS) ? "quills" : "spines"));
   hurt(spine);
  }
  p.hit(g, bphit, side, dam, type->melee_cut);
  if (has_flag(MF_VENOM)) {
   if (!is_npc)
    g->add_msg("You're poisoned!");
   p.add_disease(DI_POISON, 30, g);
  } else if (has_flag(MF_BADVENOM)) {
   if (!is_npc)
    g->add_msg("You feel poison flood your body, wracking you with pain...");
   p.add_disease(DI_BADPOISON, 40, g);
  }
 }
 if (is_npc) {
  if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0) {
   npc* tmp = dynamic_cast<npc*>(&p);
   tmp->die(g);
   int index = g->npc_at(p.posx, p.posy);
   g->active_npc.erase(g->active_npc.begin() + index);
   plans.clear();
  }
 }
}
예제 #9
0
파일: map.cpp 프로젝트: Bdthemag/Cataclysm
void map::drawsq(WINDOW* w, player &u, int x, int y, bool invert,
                 bool show_items)
{
    if (!inbounds(x, y))
        return;	// Out of bounds
    int k = x + SEEX - u.posx;
    int j = y + SEEY - u.posy;
    nc_color tercol;
    char sym = terlist[ter(x, y)].sym;
    bool hi = false;
    if (u.has_disease(DI_BOOMERED))
        tercol = c_magenta;
    else if ((u.is_wearing(itm_goggles_nv) && u.has_active_item(itm_UPS_on)) ||
             u.has_active_bionic(bio_night_vision))
        tercol = c_ltgreen;
    else
        tercol = terlist[ter(x, y)].color;
    if (move_cost(x, y) == 0 && has_flag(swimmable, x, y) && !u.underwater)
        show_items = false;	// Can only see underwater items if WE are underwater
// If there's a trap here, and we have sufficient perception, draw that instead
    if (tr_at(x, y) != tr_null &&
            u.per_cur - u.encumb(bp_eyes) >= (*traps)[tr_at(x, y)]->visibility) {
        tercol = (*traps)[tr_at(x, y)]->color;
        if ((*traps)[tr_at(x, y)]->sym == '%') {
            switch(rng(1, 5)) {
            case 1:
                sym = '*';
                break;
            case 2:
                sym = '0';
                break;
            case 3:
                sym = '8';
                break;
            case 4:
                sym = '&';
                break;
            case 5:
                sym = '+';
                break;
            }
        } else
            sym = (*traps)[tr_at(x, y)]->sym;
    }
// If there's a field here, draw that instead (unless its symbol is %)
    if (field_at(x, y).type != fd_null) {
        tercol = fieldlist[field_at(x, y).type].color[field_at(x, y).density - 1];
        if (fieldlist[field_at(x, y).type].sym == '*') {
            switch (rng(1, 5)) {
            case 1:
                sym = '*';
                break;
            case 2:
                sym = '0';
                break;
            case 3:
                sym = '8';
                break;
            case 4:
                sym = '&';
                break;
            case 5:
                sym = '+';
                break;
            }
        } else if (fieldlist[field_at(x, y).type].sym != '%')
            sym = fieldlist[field_at(x, y).type].sym;
    }
// If there's items here, draw those instead
    if (show_items && i_at(x, y).size() > 0 && field_at(x, y).is_null()) {
        if ((terlist[ter(x, y)].sym != '.'))
            hi = true;
        else {
            tercol = i_at(x, y)[i_at(x, y).size() - 1].color();
            if (i_at(x, y).size() > 1)
                invert = !invert;
            sym = i_at(x, y)[i_at(x, y).size() - 1].symbol();
        }
    }
    if (invert)
        mvwputch_inv(w, j, k, tercol, sym);
    else if (hi)
        mvwputch_hi (w, j, k, tercol, sym);
    else
        mvwputch    (w, j, k, tercol, sym);
}