コード例 #1
0
bool player::can_arm_block() {
  martialart ma = martialarts[style_selected];
  if (ma.arm_block < 0 || !(ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms")))
    return false;
  int unarmed_skill = has_active_bionic("bio_cqb") ? 5 : (int)skillLevel("unarmed");
  if (unarmed_skill < ma.arm_block && !(ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms")))
      return false;
  if (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0)
    return true;
  else
    return false;
}
コード例 #2
0
ファイル: character.cpp プロジェクト: alanpost/Cataclysm-DDA
int Character::volume_capacity() const
{
    int ret = 2; // A small bonus (the overflow)
    for (auto &i : worn) {
        ret += i.get_storage();
    }
    if (has_bionic("bio_storage")) {
        ret += 8;
    }
    if (has_trait("SHELL")) {
        ret += 16;
    }
    if (has_trait("SHELL2") && !has_active_mutation("SHELL2")) {
        ret += 24;
    }
    if (has_trait("PACKMULE")) {
        ret = int(ret * 1.4);
    }
    if (has_trait("DISORGANIZED")) {
        ret = int(ret * 0.6);
    }
    if (ret < 2) {
        ret = 2;
    }
    return ret;
}
コード例 #3
0
ファイル: bionics.cpp プロジェクト: MisterTea/Cataclysm-DDA
bool player::install_bionics(it_bionic *type)
{
    if (type == NULL) {
        debugmsg("Tried to install NULL bionic");
        return false;
    }
    if (bionics.count(type->id) == 0) {
        popup("invalid / unknown bionic id %s", type->id.c_str());
        return false;
    }
    if (has_bionic(type->id)) {
        if (!(type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII")) {
            popup(_("You have already installed this bionic."));
            return false;
        }
    }
    int chance_of_success = bionic_manip_cos(int_cur,
                            skillLevel("electronics"),
                            skillLevel("firstaid"),
                            skillLevel("mechanics"),
                            type->difficulty);

    if (!query_yn(
            _("WARNING: %i percent chance of genetic damage, blood loss, or damage to existing bionics! Install anyway?"),
            100 - chance_of_success)) {
        return false;
    }
    int pow_up = 0;
    if (type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII") {
        pow_up = BATTERY_AMOUNT;
        if (type->id == "bio_power_storage_mkII") {
            pow_up = 250;
        }
    }

    practice( "electronics", int((100 - chance_of_success) * 1.5) );
    practice( "firstaid", int((100 - chance_of_success) * 1.0) );
    practice( "mechanics", int((100 - chance_of_success) * 0.5) );
    int success = chance_of_success - rng(1, 100);
    if (success > 0) {
        add_memorial_log(pgettext("memorial_male", "Installed bionic: %s."),
                         pgettext("memorial_female", "Installed bionic: %s."),
                         bionics[type->id]->name.c_str());
        if (pow_up) {
            max_power_level += pow_up;
            add_msg_if_player(m_good, _("Increased storage capacity by %i"), pow_up);
        } else {
            add_msg(m_good, _("Successfully installed %s."), bionics[type->id]->name.c_str());
            add_bionic(type->id);
        }
    } else {
        add_memorial_log(pgettext("memorial_male", "Installed bionic: %s."),
                         pgettext("memorial_female", "Installed bionic: %s."),
                         bionics[type->id]->name.c_str());
        bionics_install_failure(this, type, success);
    }
    g->refresh_all();
    return true;
}
コード例 #4
0
ファイル: character.cpp プロジェクト: alanpost/Cataclysm-DDA
// This must be called when any of the following change:
// - effects
// - bionics
// - traits
// - underwater
// - clothes
// With the exception of clothes, all changes to these character attributes must
// occur through a function in this class which calls this function. Clothes are
// typically added/removed with wear() and takeoff(), but direct access to the
// 'wears' vector is still allowed due to refactor exhaustion.
void Character::recalc_sight_limits()
{
    sight_max = 9999;
    sight_boost = 0;
    sight_boost_cap = 0;

    // Set sight_max.
    if (has_effect("blind")) {
        sight_max = 0;
    } else if (has_effect("in_pit") ||
            (has_effect("boomered") && (!(has_trait("PER_SLIME_OK")))) ||
            (underwater && !has_bionic("bio_membrane") &&
                !has_trait("MEMBRANE") && !worn_with_flag("SWIM_GOGGLES") &&
                !has_trait("CEPH_EYES") && !has_trait("PER_SLIME_OK") ) ) {
        sight_max = 1;
    } else if (has_active_mutation("SHELL2")) {
        // You can kinda see out a bit.
        sight_max = 2;
    } else if ( (has_trait("MYOPIC") || has_trait("URSINE_EYE")) &&
            !is_wearing("glasses_eye") && !is_wearing("glasses_monocle") &&
            !is_wearing("glasses_bifocal") && !has_effect("contacts")) {
        sight_max = 4;
    } else if (has_trait("PER_SLIME")) {
        sight_max = 6;
    }

    // Set sight_boost and sight_boost_cap, based on night vision.
    // (A player will never have more than one night vision trait.)
    sight_boost_cap = 12;
    // Debug-only NV, by vache's request
    if (has_trait("DEBUG_NIGHTVISION")) {
        sight_boost = 59;
        sight_boost_cap = 59;
    } else if (has_nv() || is_wearing("rm13_armor_on") || has_active_mutation("NIGHTVISION3") ||
        has_active_mutation("ELFA_FNV") || (has_active_mutation("CEPH_VISION")) ) {
        // Yes, I'm breaking the cap. I doubt the reality bubble shrinks at night.
        // BIRD_EYE represents excellent fine-detail vision so I think it works.
        if (has_trait("BIRD_EYE")) {
            sight_boost_cap = 13;
        }
        sight_boost = sight_boost_cap;
    } else if (has_active_mutation("ELFA_NV")) {
        sight_boost = 6; // Elf-a and Bird eyes shouldn't coexist
    } else if (has_active_mutation("NIGHTVISION2") || has_active_mutation("FEL_NV") ||
        has_active_mutation("URSINE_EYE")) {
        if (has_trait("BIRD_EYE")) {
            sight_boost = 5;
        } else {
            sight_boost = 4;
         }
    } else if (has_active_mutation("NIGHTVISION")) {
        if (has_trait("BIRD_EYE")) {
            sight_boost = 2;
        } else {
            sight_boost = 1;
        }
    }
}
コード例 #5
0
ファイル: ranged.cpp プロジェクト: 9600bauds/Cataclysm-DDA
// utility functions for projectile_attack
double player::get_weapon_dispersion(item *weapon) {
    int weapon_skill_level = 0;
    if(weapon->is_gunmod()) {
      it_gunmod* firing = dynamic_cast<it_gunmod *>(weapon->type);
      weapon_skill_level = skillLevel(firing->skill_used);
    } else {
      it_gun* firing = dynamic_cast<it_gun *>(weapon->type);
      weapon_skill_level = skillLevel(firing->skill_used);
    }
    double dispersion = 0.; // Measured in quarter-degrees.
    // Up to 0.75 degrees for each skill point < 8.
    if (weapon_skill_level < 8) {
        dispersion += rng(0, 3 * (8 - weapon_skill_level));
    }
    // Up to 0.25 deg per each skill point < 9.
    if (skillLevel("gun") < 9) {
        dispersion += rng(0, 9 - skillLevel("gun"));
    }

    dispersion += rng(0, ranged_dex_mod());
    dispersion += rng(0, ranged_per_mod());

    dispersion += rng(0, 2 * encumb(bp_arms)) + rng(0, 4 * encumb(bp_eyes));

    dispersion += rng(0, weapon->curammo->dispersion);
    // item::dispersion() doesn't support gunmods.
    dispersion += rng(0, weapon->dispersion());
    int adj_recoil = recoil + driving_recoil;
    dispersion += rng(int(adj_recoil / 4), adj_recoil);

    // this is what the total bonus USED to look like
    // rng(0,x) on each term in the sum
    // 3 * skill + skill + 2 * dex + 2 * per
    // - 2*p.encumb(bp_arms) - 4*p.encumb(bp_eyes) - 5/8 * recoil

    // old targeting bionic suddenly went from 0.8 to 0.65 when LONG_RANGE was
    // crossed, so increasing range by 1 would actually increase accuracy by a
    // lot. This is kind of a compromise
    if (has_bionic("bio_targeting"))
        dispersion *= 0.75;
    if ((is_underwater() && !weapon->has_flag("UNDERWATER_GUN")) || // Range is effectively four times longer when shooting unflagged guns underwater.
            (!is_underwater() && weapon->has_flag("UNDERWATER_GUN"))) { // Range is effectively four times longer when shooting flagged guns out of water.
        dispersion *= 4;
    }

    if (dispersion < 0) { return 0; }
    return dispersion;
}
コード例 #6
0
ファイル: martialarts.cpp プロジェクト: gienkov/Cataclysm-DDA
bool player::can_arm_block()
{
    martialart ma = martialarts[style_selected];
    int unarmed_skill = has_active_bionic("bio_cqb") ? 5 : (int)skillLevel("unarmed");

    // Success conditions.
    if (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0) {
        if( unarmed_skill >= ma.arm_block ) {
            return true;
        } else if( ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms") ) {
            return true;
        }
    }
    // if not above, can't block.
    return false;
}
コード例 #7
0
ファイル: martialarts.cpp プロジェクト: Nukesor/Cataclysm-DDA
bool player::can_arm_block() const
{
    const martialart &ma = style_selected.obj();
    ///\EFFECT_UNARMED increases ability to perform arm block
    int unarmed_skill = has_active_bionic( bionic_id( "bio_cqb" ) ) ? 5 : (int)get_skill_level(skill_id("unarmed"));

    // Success conditions.
    if (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0) {
        if( unarmed_skill >= ma.arm_block ) {
            return true;
        } else if( ma.arm_block_with_bio_armor_arms && has_bionic( bionic_id( "bio_armor_arms" ) ) ) {
            return true;
        }
    }
    // if not above, can't block.
    return false;
}
コード例 #8
0
ファイル: consumption.cpp プロジェクト: Caeous/Cataclysm-DDA
// TODO: Move pizza scraping here.
// Same for other kinds of nutrition alterations
// This is used by item display, making actual nutrition available to player.
int player::nutrition_for( const item &comest ) const
{
    static const trait_id trait_CARNIVORE( "CARNIVORE" );
    static const trait_id trait_GIZZARD( "GIZZARD" );
    static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" );
    static const std::string flag_CARNIVORE_OK( "CARNIVORE_OK" );
    if( !comest.is_comestible() ) {
        return 0;
    }

    // As float to avoid rounding too many times
    float nutr = comest.type->comestible->nutr;

    if( has_trait( trait_GIZZARD ) ) {
        nutr *= 0.6f;
    }


    if( has_trait( trait_CARNIVORE ) && comest.has_flag( flag_CARNIVORE_OK ) &&
        comest.has_any_flag( carnivore_blacklist ) ) {
        // TODO: Comment pizza scrapping
        nutr *= 0.5f;
    }

    const float relative_rot = comest.get_relative_rot();
    // Saprophages get full nutrition from rotting food
    if( relative_rot > 1.0f && !has_trait( trait_SAPROPHAGE ) ) {
        // everyone else only gets a portion of the nutrition
        // Scaling linearly from 100% at just-rotten to 0 at halfway-rotten-away
        const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f );
        nutr *= ( 1.0f - rottedness );
    }

    // Bio-digestion gives extra nutrition
    if( has_bionic( bio_digestion ) ) {
        nutr *= 1.5f;
    }

    return ( int )nutr;
}
コード例 #9
0
ファイル: character.cpp プロジェクト: Priapism/Cataclysm-DDA
int Character::volume_capacity() const
{
    int ret = 0;
    for (auto &i : worn) {
        ret += i.get_storage();
    }
    if (has_bionic("bio_storage")) {
        ret += 8;
    }
    if (has_trait("SHELL")) {
        ret += 16;
    }
    if (has_trait("SHELL2") && !has_active_mutation("SHELL2")) {
        ret += 24;
    }
    if (has_trait("PACKMULE")) {
        ret = int(ret * 1.4);
    }
    if (has_trait("DISORGANIZED")) {
        ret = int(ret * 0.6);
    }
    ret = std::max(ret, 0);
    return ret;
}
コード例 #10
0
ファイル: character.cpp プロジェクト: Priapism/Cataclysm-DDA
void Character::reset_stats()
{
    // Bionic buffs
    if (has_active_bionic("bio_hydraulics"))
        mod_str_bonus(20);
    if (has_bionic("bio_eye_enhancer"))
        mod_per_bonus(2);
    if (has_bionic("bio_str_enhancer"))
        mod_str_bonus(2);
    if (has_bionic("bio_int_enhancer"))
        mod_int_bonus(2);
    if (has_bionic("bio_dex_enhancer"))
        mod_dex_bonus(2);

    // Trait / mutation buffs
    if (has_trait("THICK_SCALES")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("CHITIN2") || has_trait("CHITIN3") || has_trait("CHITIN_FUR3")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("BIRD_EYE")) {
        mod_per_bonus(4);
    }
    if (has_trait("INSECT_ARMS")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("WEBBED")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("ARACHNID_ARMS")) {
        mod_dex_bonus(-4);
    }
    if (has_trait("ARM_TENTACLES") || has_trait("ARM_TENTACLES_4") ||
            has_trait("ARM_TENTACLES_8")) {
        mod_dex_bonus(1);
    }

    // Dodge-related effects
    if (has_trait("TAIL_LONG")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_CATTLE")) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAT")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_THICK") && !(has_active_mutation("TAIL_THICK")) ) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAPTOR")) {
        mod_dodge_bonus(3);
    }
    if (has_trait("TAIL_FLUFFY")) {
        mod_dodge_bonus(4);
    }
    if (has_trait("WINGS_BAT")) {
        mod_dodge_bonus(-3);
    }
    if (has_trait("WINGS_BUTTERFLY")) {
        mod_dodge_bonus(-4);
    }

    ///\EFFECT_STR_MAX above 15 decreases Dodge bonus by 1 (NEGATIVE)
    if (str_max >= 16) {mod_dodge_bonus(-1);} // Penalty if we're huge
    ///\EFFECT_STR_MAX below 6 increases Dodge bonus by 1
    else if (str_max <= 5) {mod_dodge_bonus(1);} // Bonus if we're small

    nv_cached = false;

    // Reset our stats to normal levels
    // Any persistent buffs/debuffs will take place in effects,
    // player::suffer(), etc.

    // repopulate the stat fields
    str_cur = str_max + get_str_bonus();
    dex_cur = dex_max + get_dex_bonus();
    per_cur = per_max + get_per_bonus();
    int_cur = int_max + get_int_bonus();

    // Floor for our stats.  No stat changes should occur after this!
    if( dex_cur < 0 ) {
        dex_cur = 0;
    }
    if( str_cur < 0 ) {
        str_cur = 0;
    }
    if( per_cur < 0 ) {
        per_cur = 0;
    }
    if( int_cur < 0 ) {
        int_cur = 0;
    }

    // Does nothing! TODO: Remove
    Creature::reset_stats();
}
コード例 #11
0
ファイル: character.cpp プロジェクト: Priapism/Cataclysm-DDA
// This must be called when any of the following change:
// - effects
// - bionics
// - traits
// - underwater
// - clothes
// With the exception of clothes, all changes to these character attributes must
// occur through a function in this class which calls this function. Clothes are
// typically added/removed with wear() and takeoff(), but direct access to the
// 'wears' vector is still allowed due to refactor exhaustion.
void Character::recalc_sight_limits()
{
    sight_max = 9999;
    vision_mode_cache.reset();

    // Set sight_max.
    if (has_effect("blind") || worn_with_flag("BLIND") || has_active_bionic("bio_blindfold")) {
        sight_max = 0;
    } else if( has_effect("boomered") && (!(has_trait("PER_SLIME_OK"))) ) {
        sight_max = 1;
        vision_mode_cache.set( BOOMERED );
    } else if (has_effect("in_pit") ||
            (underwater && !has_bionic("bio_membrane") &&
                !has_trait("MEMBRANE") && !worn_with_flag("SWIM_GOGGLES") &&
                !has_trait("CEPH_EYES") && !has_trait("PER_SLIME_OK") ) ) {
        sight_max = 1;
    } else if (has_active_mutation("SHELL2")) {
        // You can kinda see out a bit.
        sight_max = 2;
    } else if ( (has_trait("MYOPIC") || has_trait("URSINE_EYE")) &&
            !is_wearing("glasses_eye") && !is_wearing("glasses_monocle") &&
            !is_wearing("glasses_bifocal") && !has_effect("contacts")) {
        sight_max = 4;
    } else if (has_trait("PER_SLIME")) {
        sight_max = 6;
    } else if( has_effect( "darkness" ) ) {
        vision_mode_cache.set( DARKNESS );
        sight_max = 10;
    }

    // Debug-only NV, by vache's request
    if( has_trait("DEBUG_NIGHTVISION") ) {
        vision_mode_cache.set( DEBUG_NIGHTVISION );
    }
    if( has_nv() ) {
        vision_mode_cache.set( NV_GOGGLES );
    }
    if( has_active_mutation("NIGHTVISION3") || is_wearing("rm13_armor_on") ) {
        vision_mode_cache.set( NIGHTVISION_3 );
    }
    if( has_active_mutation("ELFA_FNV") ) {
        vision_mode_cache.set( FULL_ELFA_VISION );
    }
    if( has_active_mutation("CEPH_VISION") ) {
        vision_mode_cache.set( CEPH_VISION );
    }
    if (has_active_mutation("ELFA_NV")) {
        vision_mode_cache.set( ELFA_VISION );
    }
    if( has_active_mutation("NIGHTVISION2") ) {
        vision_mode_cache.set( NIGHTVISION_2 );
    }
    if( has_active_mutation("FEL_NV") ) {
        vision_mode_cache.set( FELINE_VISION );
    }
    if( has_active_mutation("URSINE_EYE") ) {
        vision_mode_cache.set( URSINE_VISION );
    }
    if (has_active_mutation("NIGHTVISION")) {
        vision_mode_cache.set(NIGHTVISION_1);
    }
    if( has_trait("BIRD_EYE") ) {
        vision_mode_cache.set( BIRD_EYE);
    }
}
コード例 #12
0
ファイル: melee.cpp プロジェクト: Azrael/Cataclysm
int player::hit_mon(game *g, monster *z)
{
 bool is_u = (this == &(g->u));	// Affects how we'll display messages
 int j;
 bool can_see = (is_u || g->u_see(posx, posy, j));
 std::string You  = (is_u ? "You"  : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : (male ? "his" : "her"));

// Types of combat (may overlap!)
 bool unarmed  = unarmed_attack(), bashing = weapon.is_bashing_weapon(),
      cutting  = weapon.is_cutting_weapon(),
      stabbing = (weapon.has_weapon_flag(WF_SPEAR) ||
                  weapon.has_weapon_flag(WF_STAB));

// Recoil penalty
 if (recoil <= 30)
  recoil += 6;
// Movement cost
 moves -= weapon.attack_time() + 20 * encumb(bp_torso);
// Different sizes affect your chance to hit
 if (hit_roll() < z->dodge_roll()) {// A miss!
  stumble(g);
  return 0;
 }
 if (z->has_flag(MF_SHOCK) && !wearing_something_on(bp_hands) &&
     (unarmed || weapon.conductive())) {
  if (is_u)
   g->add_msg("The %s's electric body shocks you!", z->name().c_str());
  hurtall(rng(1, 3));
 }
// For very high hit rolls, we crit!
 bool critical_hit = (hit_roll() >= 50 + 10 * z->dodge_roll());
 int dam = base_damage(true);
 int cutting_penalty = 0; // Moves lost from getting a cutting weapon stuck

// Drunken Master damage bonuses
 if (has_trait(PF_DRUNKEN) && has_disease(DI_DRUNK)) {
// Remember, a single drink gives 600 levels of DI_DRUNK
  if (unarmed)
   dam += disease_level(DI_DRUNK) / 250;
  else
   dam += disease_level(DI_DRUNK) / 400;
 }

 if (unarmed) { // Unarmed bonuses
  dam += rng(0, sklevel[sk_unarmed]);
  if (has_trait(PF_TALONS) && z->type->armor - sklevel[sk_unarmed] < 10) {
   int z_armor = (z->type->armor - sklevel[sk_unarmed]);
   if (z_armor < 0)
    z_armor = 0;
   dam += 10 - z_armor;
  }
 } else if (rng(1, 45 - dex_cur) < 2 * sklevel[sk_unarmed] &&
            rng(1, 65 - dex_cur) < 2 * sklevel[sk_unarmed]   ) {
// If we're not unarmed, there's still a possibility of getting in a bonus
// unarmed attack.
  if (is_u || can_see) {
   switch (rng(1, 4)) {
    case 1: g->add_msg("%s kick%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 2: g->add_msg("%s headbutt%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 3: g->add_msg("%s elbow%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 4: g->add_msg("%s knee%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
   }
  }
  dam += rng(1, sklevel[sk_unarmed]);
  practice(sk_unarmed, 2);
 }
// Melee skill bonus
 dam += rng(0, sklevel[sk_melee]);
// Bashing damage bonus
 int bash_dam = weapon.type->melee_dam,
     bash_cap = 5 + str_cur + sklevel[sk_bashing];
 if (bash_dam > bash_cap)// Cap for weak characters
  bash_dam = (bash_cap * 3 + bash_dam) / 4;
 if (bashing)
  bash_dam += rng(0, sklevel[sk_bashing]) * sqrt(str_cur);
 int bash_min = bash_dam / 4;
 if (bash_min < sklevel[sk_bashing] * 2)
  bash_min = sklevel[sk_bashing] * 2;
 dam += rng(bash_dam / 4, bash_dam);
// Take some moves away from the target; at this point it's skill & bash damage
 z->moves -= rng(0, dam * 2);
// Spears treat cutting damage specially.
 if (weapon.has_weapon_flag(WF_SPEAR) &&
     weapon.type->melee_cut > z->type->armor - int(sklevel[sk_stabbing])) {
  int z_armor = z->type->armor - int(sklevel[sk_stabbing]);
  dam += int(weapon.type->melee_cut / 5);
  int minstab = sklevel[sk_stabbing] *  8 + weapon.type->melee_cut * 2,
      maxstab = sklevel[sk_stabbing] * 20 + weapon.type->melee_cut * 4;
  int monster_penalty = rng(minstab, maxstab);
  if (monster_penalty >= 150)
   g->add_msg("You force the %s to the ground!", z->name().c_str());
  else if (monster_penalty >= 80)
   g->add_msg("The %s is skewered and flinches!", z->name().c_str());
  z->moves -= monster_penalty;
  cutting_penalty = weapon.type->melee_cut * 4 + z_armor * 8 -
                    dice(sklevel[sk_stabbing], 10);
  practice(sk_stabbing, 2);
// Cutting damage bonus
 } else if (weapon.type->melee_cut >
            z->type->armor - int(sklevel[sk_cutting] / 2)) {
  int z_armor = z->type->armor - int(sklevel[sk_cutting] / 2);
  if (z_armor < 0)
   z_armor = 0;
  dam += weapon.type->melee_cut - z_armor;
  cutting_penalty = weapon.type->melee_cut * 3 + z_armor * 8 -
                    dice(sklevel[sk_cutting], 10);
 }
 if (weapon.has_weapon_flag(WF_MESSY)) { // e.g. chainsaws
  cutting_penalty /= 6; // Harder to get stuck
  for (int x = z->posx - 1; x <= z->posx + 1; x++) {
   for (int y = z->posy - 1; y <= z->posy + 1; y++) {
    if (!one_in(3)) {
     if (g->m.field_at(x, y).type == fd_blood &&
         g->m.field_at(x, y).density < 3)
      g->m.field_at(x, y).density++;
     else
      g->m.add_field(g, x, y, fd_blood, 1);
    }
   }
  }
 }

// Bonus attacks!

 bool shock_them = (!z->has_flag(MF_SHOCK) && has_bionic(bio_shock) &&
                    power_level >= 2 && unarmed && one_in(3));
 bool drain_them = (has_bionic(bio_heat_absorb) && power_level >= 1 &&
                    !is_armed() && z->has_flag(MF_WARM));
 bool  bite_them = (has_trait(PF_FANGS) && z->armor() < 18 &&
                    one_in(20 - dex_cur - sklevel[sk_unarmed]));
 bool  peck_them = (has_trait(PF_BEAK)  && z->armor() < 16 &&
                    one_in(15 - dex_cur - sklevel[sk_unarmed]));
 if (drain_them)
  power_level--;
 drain_them &= one_in(2);	// Only works half the time

// Critical hit effects
 if (critical_hit) {
  bool headshot = (!z->has_flag(MF_NOHEAD) && !one_in(3));
// Second chance for shock_them, drain_them, bite_them and peck_them
  shock_them = (shock_them || (!z->has_flag(MF_SHOCK) && has_bionic(bio_shock)&&
                               power_level >= 2 && unarmed && !one_in(3)));
  drain_them = (drain_them || (has_bionic(bio_heat_absorb) && !is_armed() &&
                               power_level >= 1 && z->has_flag(MF_WARM) &&
                               !one_in(3)));
  bite_them  = ( bite_them || (has_trait(PF_FANGS) && z->armor() < 18 &&
                               one_in(5)));
  peck_them  = ( peck_them || (has_trait(PF_BEAK)  && z->armor() < 16 &&
                               one_in(4)));

  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB)) {
   dam += weapon.type->melee_cut;
   dam += weapon.type->melee_cut * double(sklevel[sk_stabbing] / 10);
   practice(sk_stabbing, 5);
  }

  if (unarmed) {
   dam += rng(2, 6) * sklevel[sk_unarmed];
   if (sklevel[sk_unarmed] > 5)
    dam += 4 * (sklevel[sk_unarmed - 3]);
   z->moves -= dam;	// Stunning blow
   if (weapon.type->id == itm_bio_claws) {
    if (sklevel[sk_cutting] >= 3)
     dam += 5;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s claws pierce the %s's skull!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s claws stab straight through the %s!", Your.c_str(),
                z->name().c_str());
   } else if (has_trait(PF_TALONS)) {
    dam += 2;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s talons tear the %s's head open!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s bur%s %s talons into the %s!", You.c_str(),(is_u?"y":"ies"),
                your.c_str(), z->name().c_str());
   } else {
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull in a single blow!", 
                You.c_str(), (is_u ? "" : "es"), z->name().c_str());
    else if (can_see)
     g->add_msg("%s deliver%s a crushing punch!",You.c_str(),(is_u ? "" : "s"));
   }
   if (z->hp > 0 && rng(1, 5) < sklevel[sk_unarmed])
    z->add_effect(ME_STUNNED, 1 + sklevel[sk_unarmed]);
  } else {	// Not unarmed
   if (bashing) {
    dam += 8 + (str_cur / 2);
    int turns_stunned = int(dam / 20) + int(sklevel[sk_bashing] / 2);
    if (turns_stunned > 6)
     turns_stunned = 6;
    z->add_effect(ME_STUNNED, turns_stunned);
   }
   if (cutting) {
    double cut_multiplier = double(sklevel[sk_cutting] / 12);
    if (cut_multiplier > 1.5)
     cut_multiplier = 1.5;
    dam += cut_multiplier * weapon.type->melee_cut;
    headshot &= z->hp < dam;
    if (stabbing) {
     if (headshot && can_see)
      g->add_msg("%s %s stabs through the %s's skull!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else if (can_see)
      g->add_msg("%s stab %s %s through the %s!", You.c_str(), your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    } else {
     if (headshot && can_see)
      g->add_msg("%s %s slices the %s's head off!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else
      g->add_msg("%s %s cuts the %s deeply!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    }
   } else {	// Not cutting, probably bashing
    headshot &= z->hp < dam;
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s crush%s the %s's body!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
   }
  }	// End of not-unarmed
 }	// End of critical hit

 if (shock_them) {
  power_level -= 2;
  if (can_see)
   g->add_msg("%s shock%s the %s!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  int shock = rng(2, 5);
  dam += shock * rng(1, 3);
  z->moves -= shock * 180;
 }
 if (drain_them) {
  charge_power(rng(0, 4));
  if (can_see)
   g->add_msg("%s drain%s the %s's body heat!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  dam += rng(4, 10);
  z->moves -= rng(80, 120);
 }
 if (bite_them) {
  if (can_see)
   g->add_msg("%s sink %s fangs into the %s!", You.c_str(), your.c_str(),
              z->name().c_str());
  dam += 18 - z->armor();
 }
 if (peck_them) {
  if (can_see)
   g->add_msg("%s peck%s the %s viciously!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  dam += 16 - z->armor();
 }

// Make a rather quiet sound, to alert any nearby monsters
 g->sound(posx, posy, 8, "");

// Glass weapons shatter sometimes
 if (weapon.made_of(GLASS) &&
     rng(0, weapon.volume() + 8) < weapon.volume() + str_cur) {
  if (can_see)
   g->add_msg("%s %s shatters!", Your.c_str(), weapon.tname(g).c_str());
  g->sound(posx, posy, 16, "");
// Dump its contents on the ground
  for (int i = 0; i < weapon.contents.size(); i++)
   g->m.add_item(posx, posy, weapon.contents[i]);
  hit(g, bp_arms, 1, 0, rng(0, weapon.volume() * 2));// Take damage
  if (weapon.is_two_handed(this))// Hurt left arm too, if it was big
   hit(g, bp_arms, 0, 0, rng(0, weapon.volume()));
  dam += rng(0, 5 + int(weapon.volume() * 1.5));// Hurt the monster extra
  remove_weapon();
 }

 if (dam <= 0) {
  if (is_u)
   g->add_msg("You hit the %s, but do no damage.", z->name().c_str());
  else if (can_see)
   g->add_msg("%s's %s hits the %s, but does no damage.", You.c_str(),
              weapon.tname(g).c_str(), z->name().c_str());
  practice(sk_melee, rng(2, 5));
  if (unarmed)
   practice(sk_unarmed, 2);
  if (bashing)
   practice(sk_bashing, 2);
  if (cutting)
   practice(sk_cutting, 2);
  if (stabbing)
   practice(sk_stabbing, 2);
  return 0;
 }
 if (is_u)
  g->add_msg("You hit the %s for %d damage.", z->name().c_str(), dam);
 else if (can_see)
  g->add_msg("%s hits the %s with %s %s.", You.c_str(), z->name().c_str(),
             (male ? "his" : "her"),
             (weapon.type->id == 0 ? "fists" : weapon.tname(g).c_str()));
 practice(sk_melee, rng(5, 10));
 if (unarmed)
  practice(sk_unarmed, rng(5, 10));
 if (bashing)
  practice(sk_bashing, rng(5, 10));
 if (cutting)
  practice(sk_cutting, rng(5, 10));
 if (stabbing)
  practice(sk_stabbing, rng(5, 10));

// Penalize the player if their cutting weapon got stuck
 if (!unarmed && dam < z->hp && cutting_penalty > dice(str_cur * 2, 20)) {
  if (is_u)
   g->add_msg("Your %s gets stuck in the %s, pulling it out of your hands!",
              weapon.tname().c_str(), z->type->name.c_str());
  z->add_item(remove_weapon());
  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB))
   z->speed *= .7;
  else
   z->speed *= .85;
 } else {
  if (dam >= z->hp) {
   cutting_penalty /= 2;
   cutting_penalty -= rng(sklevel[sk_cutting], sklevel[sk_cutting] * 2 + 2);
  }
  if (cutting_penalty > 0)
   moves -= cutting_penalty;
  if (cutting_penalty >= 50 && is_u)
   g->add_msg("Your %s gets stuck in the %s, but you yank it free.",
              weapon.tname().c_str(), z->type->name.c_str());
  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB))
   z->speed *= .9;
 }

 return dam;
}
コード例 #13
0
ファイル: melee.cpp プロジェクト: StoicDwarf/Cataclysm-DDA
void player::melee_special_effects(game *g, monster *z, player *p, bool crit,
                                   int &bash_dam, int &cut_dam, int &stab_dam)
{
 if (z == NULL && p == NULL)
  return;
 bool mon = (z != NULL);
 int junk;
 bool is_u = (!is_npc());
 bool can_see = (is_u || g->u_see(posx, posy, junk));
 std::string You = (is_u ? "You" : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : name + "'s");
 std::string target = (mon ? "the " + z->name() :
                       (p->is_npc() ? p->name : "you"));
 std::string target_possessive = (mon ? "the " + z->name() + "'s" :
                                  (p->is_npc() ? p->name + "'s" : your));
 int tarposx = (mon ? z->posx : p->posx), tarposy = (mon ? z->posy : p->posy);

// Bashing effecs
 if (mon)
  z->moves -= rng(0, bash_dam * 2);
 else
  p->moves -= rng(0, bash_dam * 2);

// Bashing crit
 if (crit && !unarmed_attack()) {
  int turns_stunned = int(bash_dam / 20) + rng(0, int(skillLevel("bashing") / 2));
  if (turns_stunned > 6)
   turns_stunned = 6;
  if (turns_stunned > 0) {
   if (mon)
    z->add_effect(ME_STUNNED, turns_stunned);
   else
    p->add_disease(DI_STUNNED, 1 + turns_stunned / 2, g);
  }
 }

// Stabbing effects
 int stab_moves = rng(stab_dam / 2, stab_dam * 1.5);
 if (crit)
  stab_moves *= 1.5;
 if (stab_moves >= 150) {
  if (can_see)
   g->add_msg("%s force%s the %s to the ground!", You.c_str(),
              (is_u ? "" : "s"), target.c_str());
  if (mon) {
   z->add_effect(ME_DOWNED, 1);
   z->moves -= stab_moves / 2;
  } else {
   p->add_disease(DI_DOWNED, 1, g);
   p->moves -= stab_moves / 2;
  }
 } else if (mon)
  z->moves -= stab_moves;
 else
  p->moves -= stab_moves;

// Bonus attacks!
 bool shock_them = (has_bionic("bio_shock") && power_level >= 2 &&
                    unarmed_attack() && (!mon || !z->has_flag(MF_ELECTRIC)) &&
                    one_in(3));

 bool drain_them = (has_bionic("bio_heat_absorb") && power_level >= 1 &&
                    !is_armed() && (!mon || z->has_flag(MF_WARM)));

 if (drain_them)
  power_level--;
 drain_them &= one_in(2);	// Only works half the time

 if (shock_them) {
  power_level -= 2;
  int shock = rng(2, 5);
  if (mon) {
   z->hurt( shock * rng(1, 3) );
   z->moves -= shock * 180;
   if (can_see)
    g->add_msg("%s shock%s %s!", You.c_str(), (is_u ? "" : "s"),
               target.c_str());
  } else {
   p->hurt(g, bp_torso, 0, shock * rng(1, 3));
   p->moves -= shock * 80;
  }
 }

 if (drain_them) {
  charge_power(rng(0, 4));
  if (can_see)
   g->add_msg("%s drain%s %s body heat!", You.c_str(), (is_u ? "" : "s"),
               target_possessive.c_str());
  if (mon) {
   z->moves -= rng(80, 120);
   z->speed -= rng(4, 6);
  } else
   p->moves -= rng(80, 120);
 }

 bool conductive = !wearing_something_on(bp_hands) && weapon.conductive();

 if (mon && z->has_flag(MF_ELECTRIC) && conductive) {
  hurtall(rng(0, 1));
  moves -= rng(0, 50);
  if (is_u)
   g->add_msg("Contact with the %s shocks you!", z->name().c_str());
 }

// Glass weapons shatter sometimes
 if (weapon.made_of(GLASS) &&
     rng(0, weapon.volume() + 8) < weapon.volume() + str_cur) {
  if (can_see)
   g->add_msg("%s %s shatters!", Your.c_str(), weapon.tname(g).c_str());
  g->sound(posx, posy, 16, "");
// Dump its contents on the ground
  for (int i = 0; i < weapon.contents.size(); i++)
   g->m.add_item(posx, posy, weapon.contents[i]);
  hit(g, bp_arms, 1, 0, rng(0, weapon.volume() * 2));// Take damage
  if (weapon.is_two_handed(this))// Hurt left arm too, if it was big
   hit(g, bp_arms, 0, 0, rng(0, weapon.volume()));
  cut_dam += rng(0, 5 + int(weapon.volume() * 1.5));// Hurt the monster extra
  remove_weapon();
 }

// Getting your weapon stuck
 int cutting_penalty = roll_stuck_penalty(z, stab_dam > cut_dam);
 if (weapon.has_flag(IF_MESSY)) { // e.g. chainsaws
  cutting_penalty /= 6; // Harder to get stuck
  for (int x = tarposx - 1; x <= tarposx + 1; x++) {
   for (int y = tarposy - 1; y <= tarposy + 1; y++) {
    if (!one_in(3)) {
     if (g->m.field_at(x, y).type == fd_blood &&
         g->m.field_at(x, y).density < 3)
      g->m.field_at(x, y).density++;
     else
      g->m.add_field(g, x, y, fd_blood, 1);
    }
   }
  }
 }
 if (!unarmed_attack() && cutting_penalty > dice(str_cur * 2, 20)) {
  if (is_u)
   g->add_msg("Your %s gets stuck in %s, pulling it out of your hands!",
              weapon.tname().c_str(), target.c_str());
  if (mon) {
   if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB))
    z->speed *= .7;
   else
    z->speed *= .85;
   z->add_item(remove_weapon());
  } else
   g->m.add_item(posx, posy, remove_weapon());
 } else {
  if (mon && (cut_dam >= z->hp || stab_dam >= z->hp)) {
   cutting_penalty /= 2;
   cutting_penalty -= rng(skillLevel("cutting"), skillLevel("cutting") * 2 + 2);
  }
  if (cutting_penalty > 0)
   moves -= cutting_penalty;
  if (cutting_penalty >= 50 && is_u)
   g->add_msg("Your %s gets stuck in %s, but you yank it free.",
              weapon.tname().c_str(), target.c_str());
  if (mon && (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)))
   z->speed *= .9;
 }

// Finally, some special effects for martial arts
 if(weapon.typeId() == "style_karate"){
   dodges_left++;
   blocks_left += 2;
 } else if(weapon.typeId() == "style_aikido"){
   bash_dam /= 2;
 } else if(weapon.typeId() == "style_capoeira"){
   add_disease(DI_DODGE_BOOST, 2, g, 2);
 } else if(weapon.typeId() == "style_muay_thai"){
   if ((mon && z->type->size >= MS_LARGE) || (!mon && p->str_max >= 12))
    bash_dam += rng((mon ? z->type->size : (p->str_max - 8) / 4),
                    3 * (mon ? z->type->size : (p->str_max - 8) / 4));
 } else if(weapon.typeId() == "style_tiger"){
   add_disease(DI_DAMAGE_BOOST, 2, g, 2, 10);
 } else if(weapon.typeId() == "style_centipede"){
   add_disease(DI_SPEED_BOOST, 2, g, 4, 40);
 } else if(weapon.typeId() == "style_venom_snake"){
   if (has_disease(DI_VIPER_COMBO)) {
    if (disease_intensity(DI_VIPER_COMBO) == 1) {
     if (is_u)
      g->add_msg("Snakebite!");
     int dambuf = bash_dam;
     bash_dam = stab_dam;
     stab_dam = dambuf;
     add_disease(DI_VIPER_COMBO, 2, g, 1, 2); // Upgrade to Viper Strike
    } else if (disease_intensity(DI_VIPER_COMBO) == 2) {
     if (hp_cur[hp_arm_l] >= hp_max[hp_arm_l] * .75 &&
         hp_cur[hp_arm_r] >= hp_max[hp_arm_r] * .75   ) {
      if (is_u)
       g->add_msg("Viper STRIKE!");
      bash_dam *= 3;
     } else if (is_u)
      g->add_msg("Your injured arms prevent a viper strike!");
     rem_disease(DI_VIPER_COMBO);
    }
   } else if (crit) {
    if (is_u)
     g->add_msg("Tail whip!  Viper Combo Intiated!");
    bash_dam += 5;
    add_disease(DI_VIPER_COMBO, 2, g, 1, 2);
   }
 } else if(weapon.typeId() == "style_scorpion"){
   if (crit) {
    if (!is_npc())
     g->add_msg("Stinger Strike!");
    if (mon) {
     z->add_effect(ME_STUNNED, 3);
     int zposx = z->posx, zposy = z->posy;
     z->knock_back_from(g, posx, posy);
     if (z->posx != zposx || z->posy != zposy)
      z->knock_back_from(g, posx, posy); // Knock a 2nd time if the first worked
    } else {
     p->add_disease(DI_STUNNED, 2, g);
     int pposx = p->posx, pposy = p->posy;
     p->knock_back_from(g, posx, posy);
     if (p->posx != pposx || p->posy != pposy)
      p->knock_back_from(g, posx, posy); // Knock a 2nd time if the first worked
    }
   }
 } else if(weapon.typeId() == "style_zui_quan"){
   dodges_left = 50; // Basically, unlimited.
 }
}
コード例 #14
0
ファイル: bionics.cpp プロジェクト: CoZarctan/Cataclysm-DDA
bool player::install_bionics(game *g, it_bionic* type)
{
 if (type == NULL) {
  debugmsg("Tried to install NULL bionic");
  return false;
 }
 std::string bio_name = type->name.substr(5);	// Strip off "CBM: "

 WINDOW* w = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0);
 WINDOW* w_description = newwin(3, FULL_SCREEN_WIDTH-2, 21 + getbegy(w), 1 + getbegx(w));

 werase(w);
 wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX,
            LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX );

 int pl_skill = int_cur +
   skillLevel("electronics") * 4 +
   skillLevel("firstaid")    * 3 +
   skillLevel("mechanics")   * 2;

 int skint = int(pl_skill / 4);
 int skdec = int((pl_skill * 10) / 4) % 10;

// Header text
 mvwprintz(w, 1,  1, c_white, "Installing bionics:");
 mvwprintz(w, 1, 21, type->color, bio_name.c_str());

// Dividing bars
 for (int i = 1; i < 79; i++) {
  mvwputch(w,  2, i, c_ltgray, LINE_OXOX);
  mvwputch(w, 20, i, c_ltgray, LINE_OXOX);
 }

 mvwputch(w, 2,  0, c_ltgray, LINE_XXXO); // |-
 mvwputch(w, 2, 79, c_ltgray, LINE_XOXX); // -|

 mvwputch(w, 20,  0, c_ltgray, LINE_XXXO); // |-
 mvwputch(w, 20, 79, c_ltgray, LINE_XOXX); // -|

// Init the list of bionics
 for (int i = 1; i < type->options.size(); i++) {
  bionic_id bio_id = type->options[i];
  mvwprintz(w, i + 3, 1, (has_bionic(bio_id) ? c_ltred : c_ltblue),
            bionics[bio_id]->name.c_str());
 }
// Helper text
 mvwprintz(w, 3, 39, c_white,        "Difficulty of this module: %d",
           type->difficulty);
 mvwprintz(w, 4, 39, c_white,        "Your installation skill:   %d.%d",
           skint, skdec);
 mvwprintz(w, 5, 39, c_white,       "Installation requires high intelligence,");
 mvwprintz(w, 6, 39, c_white,       "and skill in electronics, first aid, and");
 mvwprintz(w, 7, 39, c_white,       "mechanics (in that order of importance).");

 int chance_of_success = int((100 * pl_skill) /
                             (pl_skill + 4 * type->difficulty));

 mvwprintz(w, 9, 39, c_white,        "Chance of success:");

 nc_color col_suc;
 if (chance_of_success >= 95)
  col_suc = c_green;
 else if (chance_of_success >= 80)
  col_suc = c_ltgreen;
 else if (chance_of_success >= 60)
  col_suc = c_yellow;
 else if (chance_of_success >= 35)
  col_suc = c_ltred;
 else
  col_suc = c_red;

 mvwprintz(w, 9, 59, col_suc, "%d%%%%", chance_of_success);

 mvwprintz(w, 11, 39, c_white,       "Failure may result in crippling damage,");
 mvwprintz(w, 12, 39, c_white,       "loss of existing bionics, genetic damage");
 mvwprintz(w, 13, 39, c_white,       "or faulty installation.");
 wrefresh(w);

 if (type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII") { // No selection list; just confirm
   int pow_up = BATTERY_AMOUNT;

   if (type->id == "bio_power_storage_mkII") {
     pow_up = 10;
   }

  mvwprintz(w, 3, 1, h_ltblue, "Power Storage +%d", pow_up);
  mvwprintz(w_description, 0, 0, c_ltblue, "\
Installing this bionic will increase your total power storage by %d.\n\
Power is necessary for most bionics to function. You also require a\n\
charge mechanism, which must be installed from another CBM.", pow_up);

  InputEvent input;
  wrefresh(w_description);
  wrefresh(w);
  do
   input = get_input();
  while (input != Confirm && input != Cancel);
  if (input == Confirm) {
   practice(g->turn, "electronics", (100 - chance_of_success) * 1.5);
   practice(g->turn, "firstaid", (100 - chance_of_success) * 1.0);
   practice(g->turn, "mechanics", (100 - chance_of_success) * 0.5);
   int success = chance_of_success - rng(1, 100);
   if (success > 0) {
    g->add_msg("Successfully installed batteries.");
    max_power_level += pow_up;
   } else
    bionics_install_failure(g, this, success);
   werase(w);
   delwin(w);
   g->refresh_all();
   return true;
  }
  werase(w);
  delwin(w);
  g->refresh_all();
  return false;
 }
コード例 #15
0
ファイル: character.cpp プロジェクト: alanpost/Cataclysm-DDA
void Character::reset_stats()
{
    Creature::reset_stats();
    
    // Bionic buffs
    if (has_active_bionic("bio_hydraulics"))
        mod_str_bonus(20);
    if (has_bionic("bio_eye_enhancer"))
        mod_per_bonus(2);
    if (has_bionic("bio_str_enhancer"))
        mod_str_bonus(2);
    if (has_bionic("bio_int_enhancer"))
        mod_int_bonus(2);
    if (has_bionic("bio_dex_enhancer"))
        mod_dex_bonus(2);

    // Trait / mutation buffs
    if (has_trait("THICK_SCALES")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("CHITIN2") || has_trait("CHITIN3") || has_trait("CHITIN_FUR3")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("BIRD_EYE")) {
        mod_per_bonus(4);
    }
    if (has_trait("INSECT_ARMS")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("WEBBED")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("ARACHNID_ARMS")) {
        mod_dex_bonus(-4);
    }
    if (has_trait("ARM_TENTACLES") || has_trait("ARM_TENTACLES_4") ||
            has_trait("ARM_TENTACLES_8")) {
        mod_dex_bonus(1);
    }

    // Dodge-related effects
    if (has_trait("TAIL_LONG")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_CATTLE")) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAT")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_THICK") && !(has_active_mutation("TAIL_THICK")) ) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAPTOR")) {
        mod_dodge_bonus(3);
    }
    if (has_trait("TAIL_FLUFFY")) {
        mod_dodge_bonus(4);
    }
    if (has_trait("WINGS_BAT")) {
        mod_dodge_bonus(-3);
    }
    if (has_trait("WINGS_BUTTERFLY")) {
        mod_dodge_bonus(-4);
    }

    if (str_max >= 16) {mod_dodge_bonus(-1);} // Penalty if we're huge
    else if (str_max <= 5) {mod_dodge_bonus(1);} // Bonus if we're small

    nv_cached = false;
}
コード例 #16
0
ファイル: consumption.cpp プロジェクト: Caeous/Cataclysm-DDA
bool player::eat( item &food, bool force )
{
    if( !food.is_food() ) {
        return false;
    }
    // Check if it's rotten before eating!
    food.calc_rot( global_square_location() );
    const auto ret = force ? can_eat( food ) : will_eat( food, is_player() );
    if( !ret.success() ) {
        return false;
    }

    if( food.type->has_use() ) {
        if( food.type->invoke( *this, food, pos() ) <= 0 ) {
            return false;
        }
    }

    // Note: the block below assumes we decided to eat it
    // No coming back from here

    const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) );
    const int nutr = nutrition_for( food );
    const int quench = food.type->comestible->quench;
    const bool spoiled = food.rotten();

    // The item is solid food
    const bool chew = food.type->comestible->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" );
    // This item is a drink and not a solid food (and not a thick soup)
    const bool drinkable = !chew && food.type->comestible->comesttype == "DRINK";
    // If neither of the above is true then it's a drug and shouldn't get mealtime penalty/bonus

    if( hibernate &&
        ( get_hunger() > -60 && get_thirst() > -60 ) &&
        ( get_hunger() - nutr < -60 || get_thirst() - quench < -60 ) ) {
        add_memorial_log( pgettext( "memorial_male", "Began preparing for hibernation." ),
                          pgettext( "memorial_female", "Began preparing for hibernation." ) );
        add_msg_if_player(
            _( "You've begun stockpiling calories and liquid for hibernation.  You get the feeling that you should prepare for bed, just in case, but...you're hungry again, and you could eat a whole week's worth of food RIGHT NOW." ) );
    }

    const bool will_vomit = get_hunger() < 0 && nutr >= 5 && !has_trait( trait_id( "GOURMAND" ) ) &&
                            !hibernate &&
                            !has_trait( trait_id( "SLIMESPAWNER" ) ) && !has_trait( trait_id( "EATHEALTH" ) ) &&
                            rng( -200, 0 ) > get_hunger() - nutr;
    const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) );
    if( spoiled && !saprophage ) {
        add_msg_if_player( m_bad, _( "Ick, this %s doesn't taste so good..." ), food.tname().c_str() );
        if( !has_trait( trait_id( "SAPROVORE" ) ) && !has_trait( trait_id( "EATDEAD" ) ) &&
            ( !has_bionic( bio_digestion ) || one_in( 3 ) ) ) {
            add_effect( effect_foodpoison, rng( 60, ( nutr + 1 ) * 60 ) );
        }
        consume_effects( food );
    } else if( spoiled && saprophage ) {
        add_msg_if_player( m_good, _( "Mmm, this %s tastes delicious..." ), food.tname().c_str() );
        consume_effects( food );
    } else {
        consume_effects( food );
    }

    const bool amorphous = has_trait( trait_id( "AMORPHOUS" ) );
    int mealtime = 250;
    if( drinkable || chew ) {
        // Those bonuses/penalties only apply to food
        // Not to smoking weed or applying bandages!
        if( has_trait( trait_id( "MOUTH_TENTACLES" ) )  || has_trait( trait_id( "MANDIBLES" ) ) ) {
            mealtime /= 2;
        } else if( has_trait( trait_id( "GOURMAND" ) ) ) {
            // Don't stack those two - that would be 25 moves per item
            mealtime -= 100;
        }

        if( has_trait( trait_id( "BEAK_HUM" ) ) && !drinkable ) {
            mealtime += 200; // Much better than PROBOSCIS but still optimized for fluids
        } else if( has_trait( trait_id( "SABER_TEETH" ) ) ) {
            mealtime += 250; // They get In The Way
        }

        if( amorphous ) {
            mealtime *= 1.1;
            // Minor speed penalty for having to flow around it
            // rather than just grab & munch
        }
    }

    moves -= mealtime;

    // If it's poisonous... poison us.
    // TODO: Move this to a flag
    if( food.poison > 0 && !has_trait( trait_id( "EATPOISON" ) ) &&
        !has_trait( trait_id( "EATDEAD" ) ) ) {
        if( food.poison >= rng( 2, 4 ) ) {
            add_effect( effect_poison, food.poison * 100 );
        }

        add_effect( effect_foodpoison, food.poison * 300 );
    }

    if( amorphous ) {
        add_msg_player_or_npc( _( "You assimilate your %s." ), _( "<npcname> assimilates a %s." ),
                               food.tname().c_str() );
    } else if( drinkable ) {
        add_msg_player_or_npc( _( "You drink your %s." ), _( "<npcname> drinks a %s." ),
                               food.tname().c_str() );
    } else if( chew ) {
        add_msg_player_or_npc( _( "You eat your %s." ), _( "<npcname> eats a %s." ),
                               food.tname().c_str() );
    }

    if( item::find_type( food.type->comestible->tool )->tool ) {
        // Tools like lighters get used
        use_charges( food.type->comestible->tool, 1 );
    }

    if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL" ) ) {
        charge_power( rng( 50, 200 ) );
    }
    if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_WEAK" ) ) {
        charge_power( rng( 25, 100 ) );
    }
    if( has_bionic( bio_ethanol ) && food.type->can_use( "ALCOHOL_STRONG" ) ) {
        charge_power( rng( 75, 300 ) );
    }

    if( food.has_flag( "CANNIBALISM" ) ) {
        // Sapiovores don't recognize humans as the same species.
        // But let them possibly feel cool about eating sapient stuff - treat like psycho
        const bool cannibal = has_trait( trait_id( "CANNIBAL" ) );
        const bool psycho = has_trait( trait_id( "PSYCHOPATH" ) ) || has_trait( trait_id( "SAPIOVORE" ) );
        const bool spiritual = has_trait( trait_id( "SPIRITUAL" ) );
        if( cannibal && psycho && spiritual ) {
            add_msg_if_player( m_good,
                               _( "You feast upon the human flesh, and in doing so, devour their spirit." ) );
            // You're not really consuming anything special; you just think you are.
            add_morale( MORALE_CANNIBAL, 25, 300 );
        } else if( cannibal && psycho ) {
            add_msg_if_player( m_good, _( "You feast upon the human flesh." ) );
            add_morale( MORALE_CANNIBAL, 15, 200 );
        } else if( cannibal && spiritual ) {
            add_msg_if_player( m_good, _( "You consume the sacred human flesh." ) );
            // Boosted because you understand the philosophical implications of your actions, and YOU LIKE THEM.
            add_morale( MORALE_CANNIBAL, 15, 200 );
        } else if( cannibal ) {
            add_msg_if_player( m_good, _( "You indulge your shameful hunger." ) );
            add_morale( MORALE_CANNIBAL, 10, 50 );
        } else if( psycho && spiritual ) {
            add_msg_if_player( _( "You greedily devour the taboo meat." ) );
            // Small bonus for violating a taboo.
            add_morale( MORALE_CANNIBAL, 5, 50 );
        } else if( psycho ) {
            add_msg_if_player( _( "Meh. You've eaten worse." ) );
        } else if( spiritual ) {
            add_msg_if_player( m_bad,
                               _( "This is probably going to count against you if there's still an afterlife." ) );
            add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 );
        } else {
            add_msg_if_player( m_bad, _( "You feel horrible for eating a person." ) );
            add_morale( MORALE_CANNIBAL, -60, -400, 600, 300 );
        }
    }

    // Allergy check
    const auto allergy = allergy_type( food );
    if( allergy != MORALE_NULL ) {
        add_msg_if_player( m_bad, _( "Yuck! How can anybody eat this stuff?" ) );
        add_morale( allergy, -75, -400, 300, 240 );
    }
    // Carnivores CAN eat junk food, but they won't like it much.
    // Pizza-scraping happens in consume_effects.
    if( has_trait( trait_id( "CARNIVORE" ) ) && food.has_flag( "ALLERGEN_JUNK" ) &&
        !food.has_flag( "CARNIVORE_OK" ) ) {
        add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) );
        add_morale( MORALE_NO_DIGEST, -25, -125, 300, 240 );
    }
    if( !spoiled && chew && has_trait( trait_id( "SAPROPHAGE" ) ) ) {
        // It's OK to *drink* things that haven't rotted.  Alternative is to ban water.  D:
        add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) );
        add_morale( MORALE_NO_DIGEST, -75, -400, 300, 240 );
    }
    if( food.has_flag( "URSINE_HONEY" ) && ( !crossed_threshold() ||
            has_trait( trait_id( "THRESH_URSINE" ) ) ) &&
        mutation_category_level["MUTCAT_URSINE"] > 40 ) {
        //Need at least 5 bear mutations for effect to show, to filter out mutations in common with other mutcats
        int honey_fun = has_trait( trait_id( "THRESH_URSINE" ) ) ?
                        std::min( mutation_category_level["MUTCAT_URSINE"] / 8, 20 ) :
                        mutation_category_level["MUTCAT_URSINE"] / 12;
        if( honey_fun < 10 ) {
            add_msg_if_player( m_good, _( "You find the sweet taste of honey surprisingly palatable." ) );
        } else {
            add_msg_if_player( m_good, _( "You feast upon the sweet honey." ) );
        }
        add_morale( MORALE_HONEY, honey_fun, 100 );
    }

    if( will_vomit ) {
        vomit();
    }

    // chance to become parasitised
    if( !( has_bionic( bio_digestion ) || has_trait( trait_id( "PARAIMMUNE" ) ) ) ) {
        if( food.type->comestible->parasites > 0 && one_in( food.type->comestible->parasites ) ) {
            switch( rng( 0, 3 ) ) {
                case 0:
                    if( !has_trait( trait_id( "EATHEALTH" ) ) ) {
                        add_effect( effect_tapeworm, 1, num_bp, true );
                    }
                    break;
                case 1:
                    if( !has_trait( trait_id( "ACIDBLOOD" ) ) ) {
                        add_effect( effect_bloodworms, 1, num_bp, true );
                    }
                    break;
                case 2:
                    add_effect( effect_brainworms, 1, num_bp, true );
                    break;
                case 3:
                    add_effect( effect_paincysts, 1, num_bp, true );
            }
        }
    }

    for( const auto &v : this->vitamins_from( food ) ) {
        auto qty = has_effect( effect_tapeworm ) ? v.second / 2 : v.second;

        // can never develop hypervitaminosis from consuming food
        vitamin_mod( v.first, qty );
    }

    food.mod_charges( -1 );
    return true;
}
コード例 #17
0
ファイル: consumption.cpp プロジェクト: Caeous/Cataclysm-DDA
void player::consume_effects( const item &food )
{
    if( !food.is_comestible() ) {
        debugmsg( "called player::consume_effects with non-comestible" );
        return;
    }
    const auto &comest = *food.type->comestible;

    const int capacity = stomach_capacity();
    if( has_trait( trait_id( "THRESH_PLANT" ) ) && food.type->can_use( "PLANTBLECH" ) ) {
        // Just keep nutrition capped, to prevent vomiting
        cap_nutrition_thirst( *this, capacity, true, true );
        return;
    }
    if( ( has_trait( trait_id( "HERBIVORE" ) ) || has_trait( trait_id( "RUMINANT" ) ) ) &&
        food.has_any_flag( herbivore_blacklist ) ) {
        // No good can come of this.
        return;
    }

    // Rotten food causes health loss
    const float relative_rot = food.get_relative_rot();
    if( relative_rot > 1.0f && !has_trait( trait_id( "SAPROPHAGE" ) ) &&
        !has_trait( trait_id( "SAPROVORE" ) ) && !has_bionic( bio_digestion ) ) {
        const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f );
        // ~-1 health per 1 nutrition at halfway-rotten-away, ~0 at "just got rotten"
        // But always round down
        int h_loss = -rottedness * comest.nutr;
        mod_healthy_mod( h_loss, -200 );
        add_msg( m_debug, "%d health from %0.2f%% rotten food", h_loss, rottedness );
    }

    const auto nutr = nutrition_for( food );
    mod_hunger( -nutr );
    mod_thirst( -comest.quench );
    mod_stomach_food( nutr );
    mod_stomach_water( comest.quench );
    if( comest.healthy != 0 ) {
        // Effectively no cap on health modifiers from food
        mod_healthy_mod( comest.healthy, ( comest.healthy >= 0 ) ? 200 : -200 );
    }

    if( comest.stim != 0 &&
        ( abs( stim ) < ( abs( comest.stim ) * 3 ) ||
          sgn( stim ) != sgn( comest.stim ) ) ) {
        if( comest.stim < 0 ) {
            stim = std::max( comest.stim * 3, stim + comest.stim );
        } else {
            stim = std::min( comest.stim * 3, stim + comest.stim );
        }
    }
    add_addiction( comest.add, comest.addict );
    if( addiction_craving( comest.add ) != MORALE_NULL ) {
        rem_morale( addiction_craving( comest.add ) );
    }

    // Morale is in minutes
    int morale_time = HOURS( 2 ) / MINUTES( 1 );
    if( food.has_flag( "HOT" ) && food.has_flag( "EATEN_HOT" ) ) {
        morale_time = HOURS( 3 ) / MINUTES( 1 );
        int clamped_nutr = std::max( 5, std::min( 20, nutr / 10 ) );
        add_morale( MORALE_FOOD_HOT, clamped_nutr, 20, morale_time, morale_time / 2 );
    }

    std::pair<int, int> fun = fun_for( food );
    if( fun.first < 0 ) {
        add_morale( MORALE_FOOD_BAD, fun.first, fun.second, morale_time, morale_time / 2, false,
                    food.type );
    } else if( fun.first > 0 ) {
        add_morale( MORALE_FOOD_GOOD, fun.first, fun.second, morale_time, morale_time / 2, false,
                    food.type );
    }

    const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) );
    if( hibernate ) {
        if( ( nutr > 0 && get_hunger() < -60 ) || ( comest.quench > 0 && get_thirst() < -60 ) ) {
            //Tell the player what's going on
            add_msg_if_player( _( "You gorge yourself, preparing to hibernate." ) );
            if( one_in( 2 ) ) {
                //50% chance of the food tiring you
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -200 ) || ( comest.quench > 0 && get_thirst() < -200 ) ) {
            //Hibernation should cut burn to 60/day
            add_msg_if_player( _( "You feel stocked for a day or two. Got your bed all ready and secured?" ) );
            if( one_in( 2 ) ) {
                //And another 50%, intended cumulative
                mod_fatigue( nutr );
            }
        }

        if( ( nutr > 0 && get_hunger() < -400 ) || ( comest.quench > 0 && get_thirst() < -400 ) ) {
            add_msg_if_player(
                _( "Mmm.  You can still fit some more in...but maybe you should get comfortable and sleep." ) );
            if( !one_in( 3 ) ) {
                //Third check, this one at 66%
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -600 ) || ( comest.quench > 0 && get_thirst() < -600 ) ) {
            add_msg_if_player( _( "That filled a hole!  Time for bed..." ) );
            // At this point, you're done.  Schlaf gut.
            mod_fatigue( nutr );
        }
    }

    // Moved here and changed a bit - it was too complex
    // Incredibly minor stuff like this shouldn't require complexity
    if( !is_npc() && has_trait( trait_id( "SLIMESPAWNER" ) ) &&
        ( get_hunger() < capacity + 40 || get_thirst() < capacity + 40 ) ) {
        add_msg_if_player( m_mixed,
                           _( "You feel as though you're going to split open!  In a good way?" ) );
        mod_pain( 5 );
        std::vector<tripoint> valid;
        for( const tripoint &dest : g->m.points_in_radius( pos(), 1 ) ) {
            if( g->is_empty( dest ) ) {
                valid.push_back( dest );
            }
        }
        int numslime = 1;
        for( int i = 0; i < numslime && !valid.empty(); i++ ) {
            const tripoint target = random_entry_removed( valid );
            if( monster *const slime = g->summon_mon( mon_player_blob, target ) ) {
                slime->friendly = -1;
            }
        }
        mod_hunger( 40 );
        mod_thirst( 40 );
        //~slimespawns have *small voices* which may be the Nice equivalent
        //~of the Rat King's ALL CAPS invective.  Probably shared-brain telepathy.
        add_msg_if_player( m_good, _( "hey, you look like me! let's work together!" ) );
    }

    // Last thing that happens before capping hunger
    if( get_hunger() < capacity && has_trait( trait_id( "EATHEALTH" ) ) ) {
        int excess_food = capacity - get_hunger();
        add_msg_player_or_npc( _( "You feel the %s filling you out." ),
                               _( "<npcname> looks better after eating the %s." ),
                               food.tname().c_str() );
        // Guaranteed 1 HP healing, no matter what.  You're welcome.  ;-)
        if( excess_food <= 5 ) {
            healall( 1 );
        } else {
            // Straight conversion, except it's divided amongst all your body parts.
            healall( excess_food /= 5 );
        }

        // Note: We want this here to prevent "you can't finish this" messages
        set_hunger( capacity );
    }

    cap_nutrition_thirst( *this, capacity, nutr > 0, comest.quench > 0 );
}
コード例 #18
0
ファイル: bionics.cpp プロジェクト: MisterTea/Cataclysm-DDA
bool player::uninstall_bionic(bionic_id b_id)
{
    // malfunctioning bionics don't have associated items and get a difficulty of 12
    int difficulty = 12;
    if( item_controller->has_template(b_id) > 0) {
        const it_bionic *type = dynamic_cast<it_bionic *> (item_controller->find_template(b_id));
        difficulty = type->difficulty;
    }

    if (!has_bionic(b_id)) {
        popup(_("You don't have this bionic installed."));
        return false;
    }
    if (!(inv.has_items_with_quality("CUT", 1, 1) && has_amount("1st_aid", 1))) {
        popup(_("Removing bionics requires a cutting tool and a first aid kit."));
        return false;
    }

    if ( b_id == "bio_blaster" ) {
        popup(_("Removing your Fusion Blaster Arm would leave you with a useless stump."));
        return false;
    }

    // removal of bionics adds +2 difficulty over installation
    int chance_of_success = bionic_manip_cos(int_cur,
                            skillLevel("electronics"),
                            skillLevel("firstaid"),
                            skillLevel("mechanics"),
                            difficulty + 2);

    if (!query_yn(_("WARNING: %i percent chance of SEVERE bodily damage! Remove anyway?"),
                  100 - chance_of_success)) {
        return false;
    }

    use_charges("1st_aid", 1);

    practice( "electronics", int((100 - chance_of_success) * 1.5) );
    practice( "firstaid", int((100 - chance_of_success) * 1.0) );
    practice( "mechanics", int((100 - chance_of_success) * 0.5) );

    int success = chance_of_success - rng(1, 100);

    if (success > 0) {
        add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."),
                         pgettext("memorial_female", "Removed bionic: %s."),
                         bionics[b_id]->name.c_str());
        // until bionics can be flagged as non-removable
        add_msg(m_neutral, _("You jiggle your parts back into their familiar places."));
        add_msg(m_good, _("Successfully removed %s."), bionics[b_id]->name.c_str());
        remove_bionic(b_id);
        g->m.spawn_item(posx, posy, "burnt_out_bionic", 1);
    } else {
        add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."),
                         pgettext("memorial_female", "Removed bionic: %s."),
                         bionics[b_id]->name.c_str());
        bionics_uninstall_failure(this);
    }
    g->refresh_all();
    return true;
}
コード例 #19
0
ファイル: melee.cpp プロジェクト: tung/Cataclysm
int player::hit_mon(game *g, monster *z)
{
 bool is_u = (this == &(g->u));	// Affects how we'll display messages
 if (is_u)
  z->add_effect(ME_HIT_BY_PLAYER, 100); // Flag as attacked by us
 int j;
 bool can_see = (is_u || g->u_see(posx, posy, j));
 std::string You  = (is_u ? "You"  : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : (male ? "his" : "her"));

// Types of combat (may overlap!)
 bool unarmed  = unarmed_attack(),
      bashing  = weapon.is_bashing_weapon(),
      cutting  = weapon.is_cutting_weapon(),
      stabbing = (weapon.has_flag(IF_SPEAR) ||
                  weapon.has_flag(IF_STAB)    );

 bool can_poison = false;

// Recoil penalty
 if (recoil <= 30)
  recoil += 6;
// Movement cost
 int move_cost = weapon.attack_time() + 20 * encumb(bp_torso);
 if (has_trait(PF_LIGHT_BONES))
  move_cost *= .9;
 if (has_trait(PF_HOLLOW_BONES))
  move_cost *= .8;
 moves -= move_cost;
// Different sizes affect your chance to hit
 if (hit_roll() < z->dodge_roll() ||
     one_in(4 + dex_cur + weapon.type->m_to_hit)) {// A miss!
  stumble(g);
  return 0;
 }
// For very high hit rolls, we crit!
 bool critical_hit = scored_crit(z->dodge_roll());
 int dam = base_damage(true);
 int cutting_penalty = 0; // Moves lost from getting a cutting weapon stuck

// Drunken Master damage bonuses
 if (has_trait(PF_DRUNKEN) && has_disease(DI_DRUNK)) {
// Remember, a single drink gives 600 levels of DI_DRUNK
  int mindrunk, maxdrunk;
  if (unarmed) {
   mindrunk = disease_level(DI_DRUNK) / 600;
   maxdrunk = disease_level(DI_DRUNK) / 250;
  } else {
   mindrunk = disease_level(DI_DRUNK) / 900;
   maxdrunk = disease_level(DI_DRUNK) / 400;
  }
  dam += rng(mindrunk, maxdrunk);
 }

 if (unarmed) { // Unarmed bonuses
  dam += rng(0, sklevel[sk_unarmed]);
  if (has_trait(PF_NAILS) && z->armor_cut() == 0 &&
      !wearing_something_on(bp_hands)) {
   dam++;
   if (one_in(2))
    can_poison = true;
  }
  if (has_trait(PF_CLAWS) && z->armor_cut() < 6 &&
      !wearing_something_on(bp_hands)) {
   dam += 6;
   if (one_in(2))
    can_poison = true;
  }
  if (has_trait(PF_TALONS) && z->armor_cut() - sklevel[sk_unarmed] < 10) {
   int z_armor = (z->armor_cut() - sklevel[sk_unarmed]);
   if (z_armor < 0)
    z_armor = 0;
   dam += 10 - z_armor;
   if (one_in(2))
    can_poison = true;
  }
  if (has_trait(PF_THORNS) && z->armor_cut() < 4 &&
      !wearing_something_on(bp_hands)) {
   dam += 4 - z->armor_cut();
   if (one_in(2))
    can_poison = true;
  }
  if (has_trait(PF_SLIME_HANDS) && !z->has_flag(MF_ACIDPROOF) &&
      !wearing_something_on(bp_hands)) {
   dam += rng(4, 6);
   can_poison = true;
  }
 }

 if (rng(1, 45 - dex_cur) < 2 * sklevel[sk_unarmed] &&
     rng(1, 65 - dex_cur) < 2 * sklevel[sk_unarmed]   ) {
// Bonus unarmed attack!
  if (is_u || can_see) {
   switch (rng(1, 2)) {
    case 1: g->add_msg("%s elbow%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 2: g->add_msg("%s knee%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
   }
  }
  if (sklevel[sk_unarmed] >= 4)
   dam += rng(1, sklevel[sk_unarmed] / 2);
  else
   dam++;
  practice(sk_unarmed, 2);
 }
// Melee skill bonus
 dam += rng(0, sklevel[sk_melee]);
// Bashing damage bonus
 int bash_dam = weapon.damage_bash() - z->armor_bash(),
     bash_cap = 5 + str_cur + sklevel[sk_bashing];
 if (bash_dam > bash_cap)// Cap for weak characters
  bash_dam = (bash_cap * 3 + bash_dam) / 4;
 if (bashing)
  bash_dam += rng(0, sklevel[sk_bashing] + sqrt(double(str_cur)));
 if (z->has_flag(MF_PLASTIC))
  bash_dam /= rng(2, 4);
 int bash_min = bash_dam / 4;
 if (bash_min < sklevel[sk_bashing] )
  bash_min = sklevel[sk_bashing];
 dam += rng(bash_min, bash_dam);
// Take some moves away from the target; at this point it's skill & bash damage
 z->moves -= rng(0, dam * 2);

// Spears treat cutting damage specially.
 if (weapon.has_flag(IF_SPEAR) &&
     weapon.damage_cut() > z->armor_cut() - int(sklevel[sk_stabbing])) {
  int z_armor = z->armor_cut() - int(sklevel[sk_stabbing]);
  dam += int(weapon.damage_cut() / 5);
  int minstab = sklevel[sk_stabbing] *  5 + weapon.volume() * 2,
      maxstab = sklevel[sk_stabbing] * 15 + weapon.volume() * 4;
  int monster_penalty = rng(minstab, maxstab);
  if (monster_penalty >= 150)
   g->add_msg("You force the %s to the ground!", z->name().c_str());
  else if (monster_penalty >= 50)
   g->add_msg("The %s is skewered and flinches!", z->name().c_str());
  z->moves -= monster_penalty;
  cutting_penalty = weapon.damage_cut() * 4 + z_armor * 8 -
                    dice(sklevel[sk_stabbing], 10);
  practice(sk_stabbing, 2);

// Cutting damage bonus
 } else if (weapon.damage_cut() >
            z->armor_cut() - int(sklevel[sk_cutting] / 2)) {

  int z_armor = z->armor_cut() - int(sklevel[sk_cutting] / 2);
  if (z_armor < 0)
   z_armor = 0;
  dam += weapon.damage_cut() - z_armor;
  cutting_penalty = weapon.damage_cut() * 3 + z_armor * 8 -
                    dice(sklevel[sk_cutting], 10);
 }

 if (weapon.has_flag(IF_MESSY)) { // e.g. chainsaws
  cutting_penalty /= 6; // Harder to get stuck
  for (int x = z->posx - 1; x <= z->posx + 1; x++) {
   for (int y = z->posy - 1; y <= z->posy + 1; y++) {
    if (!one_in(3)) {
     if (g->m.field_at(x, y).type == fd_blood &&
         g->m.field_at(x, y).density < 3)
      g->m.field_at(x, y).density++;
     else
      g->m.add_field(g, x, y, fd_blood, 1);
    }
   }
  }
 }


// Critical hit effects
 if (critical_hit) {
  bool headshot = (!z->has_flag(MF_NOHEAD) && !one_in(3));

  if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)) {
   dam += weapon.damage_cut();
   dam += weapon.damage_cut() * double(sklevel[sk_stabbing] / 10);
   practice(sk_stabbing, 5);
  }

  if (unarmed) {
   dam += rng(1, 4) * sklevel[sk_unarmed];
   z->moves -= dam;	// Stunning blow

   if (weapon.type->id == itm_bio_claws) {
    if (sklevel[sk_cutting] >= 3)
     dam += 5;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s claws pierce the %s's skull!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s claws stab straight through the %s!", Your.c_str(),
                z->name().c_str());
   } else if (has_trait(PF_TALONS)) {
    dam += 2;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s talons tear the %s's head open!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s bur%s %s talons into the %s!", You.c_str(),(is_u?"y":"ies"),
                your.c_str(), z->name().c_str());
   } else {
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull in a single blow!", 
                You.c_str(), (is_u ? "" : "es"), z->name().c_str());
    else if (can_see)
     g->add_msg("%s deliver%s a crushing punch!",You.c_str(),(is_u ? "" : "s"));
   }
   if (z->hp > 0 && rng(1, 5) < sklevel[sk_unarmed])
    z->add_effect(ME_STUNNED, 1 + sklevel[sk_unarmed]);

  } else {	// Not unarmed

   if (bashing) {
    dam += (str_cur / 2);
    int turns_stunned = int(dam / 20) + rng(0, int(sklevel[sk_bashing] / 2));
    if (turns_stunned > 6)
     turns_stunned = 6;
    z->add_effect(ME_STUNNED, turns_stunned);
   }
   if (cutting || stabbing) {
    double cut_multiplier;
    if (cutting)
     cut_multiplier = double(sklevel[sk_cutting]  / 12);
    else
     cut_multiplier = double(sklevel[sk_stabbing] /  5);
    if (cut_multiplier > 1.5)
     cut_multiplier = 1.5;
    dam += cut_multiplier * weapon.damage_cut();
    headshot &= z->hp < dam;

    if (stabbing) {
     if (headshot && can_see)
      g->add_msg("%s %s stabs through the %s's skull!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else if (can_see)
      g->add_msg("%s stab %s %s through the %s!", You.c_str(), your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    } else {
     if (headshot && can_see)
      g->add_msg("%s %s slices the %s's head off!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else
      g->add_msg("%s %s cuts the %s deeply!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    }
   } else if (bashing) {
    headshot &= z->hp < dam;
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s crush%s the %s's body!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
   }
  }	// End of not-unarmed
 }	// End of critical hit

// Bonus attacks!
 bool shock_them = (has_bionic(bio_shock) && power_level >= 2 && unarmed &&
                    one_in(3));
 bool drain_them = (has_bionic(bio_heat_absorb) && power_level >= 1 &&
                    !is_armed() && z->has_flag(MF_WARM));
 if (drain_them)
  power_level--;
 drain_them &= one_in(2);	// Only works half the time

 std::vector<special_attack> special_attacks = mutation_attacks(z);

 if (shock_them) {
  power_level -= 2;
  if (can_see)
   g->add_msg("%s shock%s the %s!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  int shock = rng(2, 5);
  dam += shock * rng(1, 3);
  z->moves -= shock * 180;
 }
 if (drain_them) {
  charge_power(rng(0, 4));
  if (can_see)
   g->add_msg("%s drain%s the %s's body heat!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  dam += rng(4, 10);
  z->moves -= rng(80, 120);
 }

 for (int i = 0; i < special_attacks.size(); i++) {
  int spec_dam = 0;
  spec_dam += special_attacks[i].bash;
  if (special_attacks[i].cut > z->armor_cut())
   spec_dam += special_attacks[i].cut - z->armor_cut();
  if (special_attacks[i].stab > z->armor_cut() * .8)
   spec_dam += special_attacks[i].stab - z->armor_cut() * .8;

  if (!can_poison && one_in(2) &&
      (special_attacks[i].cut > z->armor_cut() ||
       special_attacks[i].stab > z->armor_cut() * .8))
   can_poison = true;

  if (spec_dam > 0) {
   g->add_msg( special_attacks[i].text.c_str() );
   dam += spec_dam;
  }
 }

 if (can_poison && has_trait(PF_POISONOUS)) {
   if (is_u)
    g->add_msg("You poison the %s!", z->name().c_str());
   z->add_effect(ME_POISONED, 6);
  }

// Make a rather quiet sound, to alert any nearby monsters
 g->sound(posx, posy, 8, "");

// Glass weapons shatter sometimes
 if (weapon.made_of(GLASS) &&
     rng(0, weapon.volume() + 8) < weapon.volume() + str_cur) {
  if (can_see)
   g->add_msg("%s %s shatters!", Your.c_str(), weapon.tname(g).c_str());
  g->sound(posx, posy, 16, "");
// Dump its contents on the ground
  for (int i = 0; i < weapon.contents.size(); i++)
   g->m.add_item(posx, posy, weapon.contents[i]);
  hit(g, bp_arms, 1, 0, rng(0, weapon.volume() * 2));// Take damage
  if (weapon.is_two_handed(this))// Hurt left arm too, if it was big
   hit(g, bp_arms, 0, 0, rng(0, weapon.volume()));
  dam += rng(0, 5 + int(weapon.volume() * 1.5));// Hurt the monster extra
  remove_weapon();
 }

 if (dam <= 0) {
  if (is_u)
   g->add_msg("You hit the %s, but do no damage.", z->name().c_str());
  else if (can_see)
   g->add_msg("%s's %s hits the %s, but does no damage.", You.c_str(),
              weapon.tname(g).c_str(), z->name().c_str());
  practice(sk_melee, rng(2, 5));
  if (unarmed)
   practice(sk_unarmed, 2);
  if (bashing)
   practice(sk_bashing, 2);
  if (cutting)
   practice(sk_cutting, 2);
  if (stabbing)
   practice(sk_stabbing, 2);
  return 0;
 }
 if (is_u)
  g->add_msg("You hit the %s for %d damage.", z->name().c_str(), dam);
 else if (can_see)
  g->add_msg("%s hits the %s with %s %s.", You.c_str(), z->name().c_str(),
             (male ? "his" : "her"),
             (weapon.type->id == 0 ? "fists" : weapon.tname(g).c_str()));
 practice(sk_melee, rng(5, 10));
 if (unarmed)
  practice(sk_unarmed, rng(5, 10));
 if (bashing)
  practice(sk_bashing, rng(5, 10));
 if (cutting)
  practice(sk_cutting, rng(5, 10));
 if (stabbing)
  practice(sk_stabbing, rng(5, 10));

// Penalize the player if their cutting weapon got stuck
 if (!unarmed && dam < z->hp && cutting_penalty > dice(str_cur * 2, 20)) {
  if (is_u)
   g->add_msg("Your %s gets stuck in the %s, pulling it out of your hands!",
              weapon.tname().c_str(), z->type->name.c_str());
  z->add_item(remove_weapon());
  if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB))
   z->speed *= .7;
  else
   z->speed *= .85;
 } else {
  if (dam >= z->hp) {
   cutting_penalty /= 2;
   cutting_penalty -= rng(sklevel[sk_cutting], sklevel[sk_cutting] * 2 + 2);
  }
  if (cutting_penalty > 0)
   moves -= cutting_penalty;
  if (cutting_penalty >= 50 && is_u)
   g->add_msg("Your %s gets stuck in the %s, but you yank it free.",
              weapon.tname().c_str(), z->type->name.c_str());
  if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB))
   z->speed *= .9;
 }

 return dam;
}
コード例 #20
0
ファイル: bionics.cpp プロジェクト: AkrionXxarr/Cataclysm-DDA
bool player::install_bionics(game *g, it_bionic* type)
{
 if (type == NULL) {
  debugmsg("Tried to install NULL bionic");
  return false;
 }
 std::string bio_name = type->name.substr(5);	// Strip off "CBM: "
 WINDOW* w = newwin(25, 80, 0, 0);

 int pl_skill = int_cur +
   skillLevel("electronics").level() * 4 +
   skillLevel("firstaid").level()    * 3 +
   skillLevel("mechanics").level()   * 2;

 int skint = int(pl_skill / 4);
 int skdec = int((pl_skill * 10) / 4) % 10;

// Header text
 mvwprintz(w, 0,  0, c_white, "Installing bionics:");
 mvwprintz(w, 0, 20, type->color, bio_name.c_str());

// Dividing bars
 for (int i = 0; i < 80; i++) {
  mvwputch(w,  1, i, c_ltgray, LINE_OXOX);
  mvwputch(w, 21, i, c_ltgray, LINE_OXOX);
 }
// Init the list of bionics
 for (unsigned int i = 1; i < type->options.size(); i++) {
  bionic_id id = type->options[i];
  mvwprintz(w, i + 2, 0, (has_bionic(id) ? c_ltred : c_ltblue),
            bionics[id].name.c_str());
 }
// Helper text
 mvwprintz(w, 2, 40, c_white,        "Difficulty of this module: %d",
           type->difficulty);
 mvwprintz(w, 3, 40, c_white,        "Your installation skill:   %d.%d",
           skint, skdec);
 mvwprintz(w, 4, 40, c_white,       "Installation requires high intelligence,");
 mvwprintz(w, 5, 40, c_white,       "and skill in electronics, first aid, and");
 mvwprintz(w, 6, 40, c_white,       "mechanics (in that order of importance).");

 int chance_of_success = int((100 * pl_skill) /
                             (pl_skill + 4 * type->difficulty));

 mvwprintz(w, 8, 40, c_white,        "Chance of success:");

 nc_color col_suc;
 if (chance_of_success >= 95)
  col_suc = c_green;
 else if (chance_of_success >= 80)
  col_suc = c_ltgreen;
 else if (chance_of_success >= 60)
  col_suc = c_yellow;
 else if (chance_of_success >= 35)
  col_suc = c_ltred;
 else
  col_suc = c_red;

 mvwprintz(w, 8, 59, col_suc, "%d%%%%", chance_of_success);

 mvwprintz(w, 10, 40, c_white,       "Failure may result in crippling damage,");
 mvwprintz(w, 11, 40, c_white,       "loss of existing bionics, genetic damage");
 mvwprintz(w, 12, 40, c_white,       "or faulty installation.");
 wrefresh(w);

 if (type->id == itm_bionics_battery) {	// No selection list; just confirm
  mvwprintz(w,  2, 0, h_ltblue, "Battery Level +%d", BATTERY_AMOUNT);
  mvwprintz(w, 22, 0, c_ltblue, "\
Installing this bionic will increase your total battery capacity by %d.\n\
Batteries are necessary for most bionics to function.  They also require a\n\
charge mechanism, which must be installed from another CBM.", BATTERY_AMOUNT);
  char ch;
  wrefresh(w);
  do
   ch = getch();
  while (ch != 'q' && ch != '\n' && ch != KEY_ESCAPE);
  if (ch == '\n') {
   practice("electronics", (100 - chance_of_success) * 1.5);
   practice("firstaid", (100 - chance_of_success) * 1.0);
   practice("mechanics", (100 - chance_of_success) * 0.5);
   int success = chance_of_success - rng(1, 100);
   if (success > 0) {
    g->add_msg("Successfully installed batteries.");
    max_power_level += BATTERY_AMOUNT;
   } else
    bionics_install_failure(g, this, success);
   werase(w);
   delwin(w);
   g->refresh_all();
   return true;
  }
  werase(w);
  delwin(w);
  g->refresh_all();
  return false;
 }
コード例 #21
0
ファイル: consumption.cpp プロジェクト: kd8qdz/Cataclysm-DDA
void player::consume_effects( item &food, bool rotten )
{
    if( !food.is_food() ) {
        debugmsg( "called player::consume_effects with non-comestible" );
        return;
    }
    const auto comest = food.type->comestible.get();

    const int capacity = stomach_capacity();
    if( has_trait( "THRESH_PLANT" ) && food.type->can_use( "PLANTBLECH" ) ) {
        // Just keep nutrition capped, to prevent vomiting
        cap_nutrition_thirst( *this, capacity, true, true );
        return;
    }
    if( ( has_trait( "HERBIVORE" ) || has_trait( "RUMINANT" ) ) &&
        food.has_any_flag( herbivore_blacklist ) ) {
        // No good can come of this.
        return;
    }
    float factor = 1.0f;
    float hunger_factor = 1.0f;
    bool unhealthy_allowed = true;

    if( has_trait( "GIZZARD" ) ) {
        factor *= 0.6f;
    }

    if( has_trait( "CARNIVORE" ) && food.has_flag( "CARNIVORE_OK" ) ) {
        // At least partially edible
        if( food.has_any_flag( carnivore_blacklist ) ) {
            // Other things are in it, we only get partial benefits
            add_msg_if_player( _( "You pick out the edible parts and throw away the rest." ) );
            factor *= 0.5f;
        } else {
            // Carnivores don't get unhealthy off pure meat diets
            unhealthy_allowed = false;
        }
    }
    // Saprophages get full nutrition from rotting food
    if( rotten && !has_trait( "SAPROPHAGE" ) ) {
        // everyone else only gets a portion of the nutrition
        hunger_factor *= rng_float( 0, 1 );
        // and takes a health penalty if they aren't adapted
        if( !has_trait( "SAPROVORE" ) && !has_bionic( "bio_digestion" ) ) {
            mod_healthy_mod( -30, -200 );
        }
    }

    // Bio-digestion gives extra nutrition
    if( has_bionic( "bio_digestion" ) ) {
        hunger_factor += rng_float( 0, 1 );
    }

    const auto nutr = nutrition_for( food.type );
    mod_hunger( -nutr * factor * hunger_factor );
    mod_thirst( -comest->quench * factor );
    mod_stomach_food( nutr * factor * hunger_factor );
    mod_stomach_water( comest->quench * factor );
    if( unhealthy_allowed || comest->healthy > 0 ) {
        // Effectively no cap on health modifiers from food
        mod_healthy_mod( comest->healthy, ( comest->healthy >= 0 ) ? 200 : -200 );
    }

    if( comest->stim != 0 &&
        ( abs( stim ) < ( abs( comest->stim ) * 3 ) ||
          sgn( stim ) != sgn( comest->stim ) ) ) {
        if( comest->stim < 0 ) {
            stim = std::max( comest->stim * 3, stim + comest->stim );
        } else {
            stim = std::min( comest->stim * 3, stim + comest->stim );
        }
    }
    add_addiction( comest->add, comest->addict );
    if( addiction_craving( comest->add ) != MORALE_NULL ) {
        rem_morale( addiction_craving( comest->add ) );
    }
    if( food.has_flag( "HOT" ) && food.has_flag( "EATEN_HOT" ) ) {
        add_morale( MORALE_FOOD_HOT, 5, 10 );
    }
    auto fun = comest->fun;
    if( food.has_flag( "COLD" ) && food.has_flag( "EATEN_COLD" ) && fun > 0 ) {
        if( fun > 0 ) {
            add_morale( MORALE_FOOD_GOOD, fun * 3, fun * 3, 60, 30, false, food.type );
        } else {
            fun = 1;
        }
    }

    const bool gourmand = has_trait( "GOURMAND" );
    const bool hibernate = has_active_mutation( "HIBERNATE" );
    if( gourmand ) {
        if( fun < -2 ) {
            add_morale( MORALE_FOOD_BAD, fun * 0.5, fun, 60, 30, false, food.type );
        } else if( fun > 0 ) {
            add_morale( MORALE_FOOD_GOOD, fun * 3, fun * 6, 60, 30, false, food.type );
        }
    } else if( fun < 0 ) {
        add_morale( MORALE_FOOD_BAD, fun, fun * 6, 60, 30, false, food.type );
    } else if( fun > 0 ) {
        add_morale( MORALE_FOOD_GOOD, fun, fun * 4, 60, 30, false, food.type );
    }

    if( hibernate ) {
        if( ( nutr > 0 && get_hunger() < -60 ) || ( comest->quench > 0 && get_thirst() < -60 ) ) {
            //Tell the player what's going on
            add_msg_if_player( _( "You gorge yourself, preparing to hibernate." ) );
            if( one_in( 2 ) ) {
                //50% chance of the food tiring you
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -200 ) || ( comest->quench > 0 && get_thirst() < -200 ) ) {
            //Hibernation should cut burn to 60/day
            add_msg_if_player( _( "You feel stocked for a day or two. Got your bed all ready and secured?" ) );
            if( one_in( 2 ) ) {
                //And another 50%, intended cumulative
                mod_fatigue( nutr );
            }
        }

        if( ( nutr > 0 && get_hunger() < -400 ) || ( comest->quench > 0 && get_thirst() < -400 ) ) {
            add_msg_if_player(
                _( "Mmm.  You can still fit some more in...but maybe you should get comfortable and sleep." ) );
            if( !one_in( 3 ) ) {
                //Third check, this one at 66%
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -600 ) || ( comest->quench > 0 && get_thirst() < -600 ) ) {
            add_msg_if_player( _( "That filled a hole!  Time for bed..." ) );
            // At this point, you're done.  Schlaf gut.
            mod_fatigue( nutr );
        }
    }

    // Moved here and changed a bit - it was too complex
    // Incredibly minor stuff like this shouldn't require complexity
    if( !is_npc() && has_trait( "SLIMESPAWNER" ) &&
        ( get_hunger() < capacity + 40 || get_thirst() < capacity + 40 ) ) {
        add_msg_if_player( m_mixed,
                           _( "You feel as though you're going to split open!  In a good way?" ) );
        mod_pain( 5 );
        std::vector<tripoint> valid;
        for( const tripoint &dest : g->m.points_in_radius( pos(), 1 ) ) {
            if( g->is_empty( dest ) ) {
                valid.push_back( dest );
            }
        }
        int numslime = 1;
        for( int i = 0; i < numslime && !valid.empty(); i++ ) {
            const tripoint target = random_entry_removed( valid );
            if( g->summon_mon( mon_player_blob, target ) ) {
                monster *slime = g->monster_at( target );
                slime->friendly = -1;
            }
        }
        mod_hunger( 40 );
        mod_thirst( 40 );
        //~slimespawns have *small voices* which may be the Nice equivalent
        //~of the Rat King's ALL CAPS invective.  Probably shared-brain telepathy.
        add_msg_if_player( m_good, _( "hey, you look like me! let's work together!" ) );
    }

    // Last thing that happens before capping hunger
    if( get_hunger() < capacity && has_trait( "EATHEALTH" ) ) {
        int excess_food = capacity - get_hunger();
        add_msg_player_or_npc( _( "You feel the %s filling you out." ),
                               _( "<npcname> looks better after eating the %s." ),
                               food.tname().c_str() );
        // Guaranteed 1 HP healing, no matter what.  You're welcome.  ;-)
        if( excess_food <= 5 ) {
            healall( 1 );
        } else {
            // Straight conversion, except it's divided amongst all your body parts.
            healall( excess_food /= 5 );
        }

        // Note: We want this here to prevent "you can't finish this" messages
        set_hunger( capacity );
    }

    cap_nutrition_thirst( *this, capacity, nutr > 0, comest->quench > 0 );
}