예제 #1
0
int monster::hit(game *g, player &p, body_part &bp_hit)
{
 int numdice = type->melee_skill;
 if (dice(numdice, 10) <= dice(p.dodge(g), 10) && !one_in(20)) {
  if (numdice > p.sklevel[sk_dodge])
   p.practice(sk_dodge, 10);
  return 0;	// We missed!
 }
 p.practice(sk_dodge, 5);
 int ret = 0;
 int highest_hit;
 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 (has_flag(MF_DIGS))
  highest_hit -= 8;
 if (has_flag(MF_FLIES))
  highest_hit += 20;
 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 == 17)
  bp_hit = bp_eyes;
 else
  bp_hit = bp_head;
 ret += dice(type->melee_dice, type->melee_sides);
 return ret;
}
예제 #2
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;
        }
    }
}
예제 #3
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;
        }
    }
}
예제 #4
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;
  }
 }
}