Beispiel #1
0
void trapfunc::shotgun(int x, int y)
{
 g->add_msg(_("You trigger a shotgun trap!"));
 g->u.add_memorial_log(_("Triggered a shotgun trap."));
 int shots = (one_in(8) || one_in(20 - g->u.str_max) ? 2 : 1);
 if (g->m.tr_at(x, y) == tr_shotgun_1)
  shots = 1;
 if (rng(5, 50) > g->u.dodge(g)) {
  body_part hit = num_bp;
  switch (rng(1, 10)) {
   case  1: hit = bp_feet; break;
   case  2:
   case  3:
   case  4: hit = bp_legs; break;
   case  5:
   case  6:
   case  7:
   case  8:
   case  9: hit = bp_torso; break;
   case 10: hit = bp_head; break;
  }
  int side = random_side(hit);
  g->add_msg(_("Your %s is hit!"), body_part_name(hit, side).c_str());
  g->u.hit(g, hit, side, 0, rng(40 * shots, 60 * shots));
 } else
  g->add_msg(_("You dodge the shot!"));
 if (shots == 2 || g->m.tr_at(x, y) == tr_shotgun_1) {
  g->m.spawn_item(x, y, "shotgun_sawn");
  g->m.spawn_item(x, y, "string_6");
  g->m.remove_trap(x, y);
 } else
  g->m.add_trap(x, y, tr_shotgun_1);
}
Beispiel #2
0
void trapfunc::crossbow(int x, int y)
{
 bool add_bolt = true;
 g->add_msg(_("You trigger a crossbow trap!"));
 g->u.add_memorial_log(_("Triggered a crossbow trap."));
 if (!one_in(4) && rng(8, 20) > g->u.dodge(g)) {
  body_part hit = num_bp;
  switch (rng(1, 10)) {
   case  1: hit = bp_feet; break;
   case  2:
   case  3:
   case  4: hit = bp_legs; break;
   case  5:
   case  6:
   case  7:
   case  8:
   case  9: hit = bp_torso; break;
   case 10: hit = bp_head; break;
  }
  int side = random_side(hit);
  g->add_msg(_("Your %s is hit!"), body_part_name(hit, side).c_str());
  g->u.hit(g, hit, side, 0, rng(20, 30));
  add_bolt = !one_in(10);
 } else
  g->add_msg(_("You dodge the shot!"));
 g->m.remove_trap(x, y);
 g->m.spawn_item(x, y, "crossbow");
 g->m.spawn_item(x, y, "string_6");
 if (add_bolt)
  g->m.spawn_item(x, y, "bolt_steel", 1, 1);
}
Beispiel #3
0
void trapfunc::beartrap(int x, int y)
{
    g->add_msg(_("A bear trap closes on your foot!"));
    g->u.add_memorial_log(_("Caught by a beartrap."));
    g->sound(x, y, 8, _("SNAP!"));
    g->u.hit(g, bp_legs, random_side(bp_legs), 10, 16);
    g->u.add_disease("beartrap", 1, true);
    g->m.remove_trap(x, y);
    g->m.spawn_item(x, y, "beartrap");
}
Beispiel #4
0
void trapfunc::pit_spikes(int x, int y)
{
    g->add_msg(_("You fall in a pit!"));
    g->u.add_memorial_log(pgettext("memorial_male", "Fell into a spiked pit."),
                          pgettext("memorial_female", "Fell into a spiked pit."));
    int dodge = g->u.get_dodge();
    int damage = pit_effectiveness(x, y) * rng(20, 50);
    if (g->u.has_trait("WINGS_BIRD")) {
        g->add_msg(_("You flap your wings and flutter down gracefully."));
    } else if (0 == damage || rng(5, 30) < dodge) {
        g->add_msg(_("You avoid the spikes within."));
    } else {
        body_part hit = num_bp;
        switch (rng(1, 10)) {
            case  1:
            case  2: hit = bp_legs; break;
            case  3:
            case  4: hit = bp_arms; break;
            case  5:
            case  6:
            case  7:
            case  8:
            case  9:
            case 10: hit = bp_torso; break;
        }
        int side = random_side(hit);
        g->add_msg(_("The spikes impale your %s!"), body_part_name(hit, side).c_str());
        g->u.hit(NULL, hit, side, 0, damage);
        if (one_in(4)) {
            g->add_msg(_("The spears break!"));
            g->m.ter_set(x, y, t_pit);
            g->m.add_trap(x, y, tr_pit);
            for (int i = 0; i < 4; i++) { // 4 spears to a pit
                if (one_in(3)) {
                    g->m.spawn_item(x, y, "spear_wood");
                }
            }
        }
    }
    g->u.add_disease("in_pit", 1, true);
}
void monster::melee_attack(Creature &target, bool, matec_id) {
    mod_moves(-100);
    if (type->melee_dice == 0) { // We don't attack, so just return
        return;
    }
    add_effect("hit_by_player", 3); // Make us a valid target for a few turns

    if (has_flag(MF_HIT_AND_RUN)) {
        add_effect("run", 4);
    }

    bool u_see_me = g->u_see(this);

    body_part bp_hit;
    //int highest_hit = 0;
    int hitstat = type->melee_skill;
    int hitroll = dice(hitstat,10);

    damage_instance damage;
    if(!is_hallucination()) {
        if (type->melee_dice > 0) {
            damage.add_damage(DT_BASH,
                    dice(type->melee_dice,type->melee_sides));
        }
        if (type->melee_cut > 0) {
            damage.add_damage(DT_CUT, type->melee_cut);
        }
    }

    /* TODO: height-related bodypart selection
    //If the player is knocked down or the monster can fly, any body part is a valid target
    if(target.is_on_ground() || has_flag(MF_FLIES)){
        highest_hit = 20;
    }
    else {
        switch (type->size) {
        case MS_TINY:
            highest_hit = 3;
        break;
        case MS_SMALL:
            highest_hit = 12;
        break;
        case MS_MEDIUM:
            highest_hit = 20;
        break;
        case MS_LARGE:
            highest_hit = 28;
        break;
        case MS_HUGE:
            highest_hit = 35;
        break;
        }
        if (digging()){
            highest_hit -= 8;
        }
        if (highest_hit <= 1){
            highest_hit = 2;
        }
    }

    if (highest_hit > 20){
        highest_hit = 20;
    }

    int bp_rand = rng(0, highest_hit - 1);
    if (bp_rand <=  2){
        bp_hit = bp_legs;
    } else if (bp_rand <= 10){
        bp_hit = bp_torso;
    } else if (bp_rand <= 14){
        bp_hit = bp_arms;
    } else if (bp_rand <= 16){
        bp_hit = bp_mouth;
    } else if (bp_rand == 18){
        bp_hit = bp_eyes;
    } else{
        bp_hit = bp_head;
    }
    */

    dealt_damage_instance dealt_dam;
    int hitspread = target.deal_melee_attack(this, hitroll);
    if (hitspread >= 0) {
        target.deal_melee_hit(this, hitspread, false, damage, dealt_dam);
    }
    bp_hit = dealt_dam.bp_hit;

    if (hitspread < 0) { // a miss
        // TODO: characters practice dodge when a hit misses 'em
        if (target.is_player()) {
            if (u_see_me) {
                add_msg(_("You dodge %1$s."), disp_name().c_str());
            } else {
                add_msg(_("You dodge an attack from an unseen source."));
            }
        } else {
            if (u_see_me) {
                add_msg(_("The %1$s dodges %2$s attack."), name().c_str(),
                            target.disp_name(true).c_str());
            }
        }
    //Hallucinations always produce messages but never actually deal damage
    } else if (is_hallucination() || dealt_dam.total_damage() > 0) {
        if (target.is_player()) {
            if (u_see_me) {
                add_msg(m_bad, _("The %1$s hits your %2$s."), name().c_str(),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str());
            } else {
                add_msg(m_bad, _("Something hits your %s."),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str());
            }
        } else {
            if (u_see_me) {
                add_msg(_("The %1$s hits %2$s %3$s."), name().c_str(),
                            target.disp_name(true).c_str(),
                            body_part_name(bp_hit, random_side(bp_hit)).c_str());
            }
        }
    } else {
        if (target.is_player()) {
            if (u_see_me) {
                add_msg(_("The %1$s hits your %2$s, but your %3$s protects you."), name().c_str(),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str(), target.skin_name().c_str());
            } else {
                add_msg(_("Something hits your %1$s, but your %2$s protects you."),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str(), target.skin_name().c_str());
            }
        } else {
            if (u_see_me) {
                add_msg(_("The %1$s hits %2$s %3$s but is stopped by %2$s %4$s."), name().c_str(),
                            target.disp_name(true).c_str(),
                            body_part_name(bp_hit, random_side(bp_hit)).c_str(),
                            target.skin_name().c_str());
            }
        }
    }

    if (is_hallucination()) {
        if(one_in(7)) {
            dead = true;
        }
        return;
    }

    // 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;
        }
    }
}
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;
        }
    }
}
Beispiel #7
0
void shoot_player(player &p, player *h, int &dam, double goodhit)
{
    int npcdex = g->npc_at(h->posx, h->posy);
    // Gunmods don't have a type, so use the player gun type.
    it_gun* firing = dynamic_cast<it_gun*>(p.weapon.type);
    body_part hit = bp_torso;
    if (goodhit < .003) {
        hit = bp_eyes;
        dam = rng(3 * dam, 5 * dam);
        p.practice(g->turn, firing->skill_used, 5);
    } else if (goodhit < .066) {
        if (one_in(25)) {
            hit = bp_eyes;
        } else if (one_in(15)) {
            hit = bp_mouth;
        } else {
            hit = bp_head;
        }
        dam = rng(2 * dam, 5 * dam);
        p.practice(g->turn, firing->skill_used, 5);
    } else if (goodhit < .2) {
        hit = bp_torso;
        dam = rng(dam, 2 * dam);
        p.practice(g->turn, firing->skill_used, 2);
    } else if (goodhit < .4) {
        if (one_in(3)) {
            hit = bp_torso;
        } else if (one_in(2)) {
            hit = bp_arms;
        } else {
            hit = bp_legs;
        }
        dam = rng(int(dam * .9), int(dam * 1.5));
        p.practice(g->turn, firing->skill_used, rng(0, 1));
    } else if (goodhit < .5) {
        if (one_in(2)) {
            hit = bp_arms;
        } else {
            hit = bp_legs;
        }
        dam = rng(dam / 2, dam);
    } else {
        dam = 0;
    }
    if (dam > 0) {
        int side = random_side(hit);
        h->moves -= rng(0, dam);
        if (h == &(g->u)) {
            g->add_msg(_("%s shoots your %s for %d damage!"), p.name.c_str(),
                          body_part_name(hit, side).c_str(), dam);
        } else {
            if (&p == &(g->u)) {
                g->add_msg(_("You shoot %s's %s."), h->name.c_str(),
                               body_part_name(hit, side).c_str());
                g->active_npc[npcdex]->make_angry();
            } else if (g->u_see(h->posx, h->posy)) {
                g->add_msg(_("%s shoots %s's %s."),
                   (g->u_see(p.posx, p.posy) ? p.name.c_str() : _("Someone")),
                    h->name.c_str(), body_part_name(hit, side).c_str());
            }
        }
        h->hit(&p, hit, side, 0, dam);
    }
}