itype_id mtype::get_meat_itype() const
{
    if( has_flag( MF_POISON ) ) {
        if( made_of( material_id( "flesh" ) ) || made_of( material_id( "hflesh" ) ) ) {
            return "meat_tainted";
        } else if( made_of( material_id( "iflesh" ) ) ) {
            //In the future, insects could drop insect flesh rather than plain ol' meat.
            return "meat_tainted";
        } else if( made_of( material_id( "veggy" ) ) ) {
            return "veggy_tainted";
        } else if( made_of( material_id( "bone" ) ) ) {
            return "bone_tainted";
        }
    } else {
        if( made_of( material_id( "flesh" ) ) || made_of( material_id( "hflesh" ) ) ) {
            if( has_flag( MF_HUMAN ) ) {
                return "human_flesh";
            } else if( has_flag( MF_AQUATIC ) ) {
                return "fish";
            } else {
                return "meat";
            }
        } else if( made_of( material_id( "iflesh" ) ) ) {
            //In the future, insects could drop insect flesh rather than plain ol' meat.
            return "meat";
        } else if( made_of( material_id( "veggy" ) ) ) {
            return "veggy";
        } else if( made_of( material_id( "bone" ) ) ) {
            return "bone";
        }
    }
    return "null";
}
Exemple #2
0
int item::weight()
{
 if (type->id == itm_corpse) {
  int ret;
  switch (corpse->size) {
   case MS_TINY:   ret =    5;	break;
   case MS_SMALL:  ret =   60;	break;
   case MS_MEDIUM: ret =  520;	break;
   case MS_LARGE:  ret = 2000;	break;
   case MS_HUGE:   ret = 4000;	break;
  }
  if (made_of(VEGGY))
   ret /= 10;
  else if (made_of(IRON) || made_of(STEEL) || made_of(STONE))
   ret *= 5;
  return ret;
 }
 int ret = type->weight;
 if (is_ammo()) { 
  ret *= charges;
  ret /= 100;
 }
 for (int i = 0; i < contents.size(); i++)
  ret += contents[i].weight();
 return ret;
}
field_id monster::gibType() {
    if (has_flag(MF_LARVA) || type->in_species("MOLLUSK"))
        return fd_gibs_invertebrate;
    if (made_of("veggy"))
        return fd_gibs_veggy;
    if (made_of("iflesh"))
        return fd_gibs_insect;
    return fd_gibs_flesh; //Please update the corpse gib type code at mtypedef.cpp modifying these rules!
}
field_id monster::monGibType() {
    if (has_flag(MF_LARVA) || type->in_species("MOLLUSK"))
        return fd_gibs_invertebrate;
    if (made_of("veggy"))
        return fd_gibs_veggy;
    if (made_of("iflesh"))
        return fd_gibs_insect;
    return fd_gibs_flesh;
}
void monster::process_effects()
{
    for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) {
        std::string id = effect_it->second.get_id();
        if (id == "nasty_poisoned") {
            mod_speed_bonus( -rng(3, 5) );
            apply_damage( nullptr, bp_torso, rng( 3, 6 ) );
        } if (id == "poisoned") {
            mod_speed_bonus( -rng(0, 3) );
            apply_damage( nullptr, bp_torso, rng( 1, 3 ) );

        // MATERIALS-TODO: use fire resistance
        } else if (id == "onfire") {
            if (made_of("flesh") || made_of("iflesh"))
                apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
            if (made_of("veggy"))
                apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
            if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                made_of("wool"))
                apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
        }
    }

    Creature::process_effects();
}
void monster::process_effects()
{
    for (std::vector<effect>::iterator it = effects.begin();
            it != effects.end(); ++it) {
        std::string id = it->get_id();
        if (id == "nasty_poisoned") {
            speed -= rng(3, 5);
            hurt(rng(3, 6));
        } if (id == "poisoned") {
            speed -= rng(0, 3);
            hurt(rng(1, 3));

        // MATERIALS-TODO: use fire resistance
        } else if (id == "onfire") {
            if (made_of("flesh") || made_of("iflesh"))
                hurt(rng(3, 8));
            if (made_of("veggy"))
                hurt(rng(10, 20));
            if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                made_of("wool"))
                hurt(rng(15, 40));
        }
    }

    Creature::process_effects();
}
Exemple #7
0
int item::weight()
{
 if (typeId() == itm_corpse) {
  int ret;
  switch (corpse->size) {
   case MS_TINY:   ret =    5;	break;
   case MS_SMALL:  ret =   60;	break;
   case MS_MEDIUM: ret =  520;	break;
   case MS_LARGE:  ret = 2000;	break;
   case MS_HUGE:   ret = 4000;	break;
  }
  if (made_of(VEGGY))
   ret /= 10;
  else if (made_of(IRON) || made_of(STEEL) || made_of(STONE))
   ret *= 5;
  return ret;
 }

 if( is_null() )
  return 0;

 int ret = type->weight;

 if (count_by_charges() && !made_of(LIQUID)) {
 ret *= charges;
 ret /= 100;
 }

 for (int i = 0; i < contents.size(); i++)
  if (contents[i].made_of(LIQUID))
  {
    if (contents[i].type->is_food()) 
      {
        it_comest* tmp_comest = dynamic_cast<it_comest*>(contents[i].type);
        ret += contents[i].weight() * (contents[i].charges / tmp_comest->charges);
      }    
      else if (contents[i].type->is_ammo())
      {
        it_ammo* tmp_ammo = dynamic_cast<it_ammo*>(contents[i].type);
        ret += contents[i].weight() * (contents[i].charges / tmp_ammo->count);    
      }
      else
        ret += contents[i].weight();
  }
  else
  ret += contents[i].weight();
  
 return ret;
}
Exemple #8
0
item item::in_its_container(std::vector<itype*> *itypes)
{

 if (is_software()) {
  item ret( (*itypes)[itm_usb_drive], 0);
  ret.contents.push_back(*this);
  ret.invlet = invlet;
  return ret;
 }

  if (!is_food() || (dynamic_cast<it_comest*>(type))->container == itm_null)
  return *this;
  
    it_comest *food = dynamic_cast<it_comest*>(type);
    item ret((*itypes)[food->container], bday);

  if (dynamic_cast<it_comest*>(type)->container == itm_can_food)
   food->spoils = 0;

    if (made_of(LIQUID))
    {
     it_container* container = dynamic_cast<it_container*>(ret.type);
      charges = container->contains * food->charges;
    }
    ret.contents.push_back(*this);
    ret.invlet = invlet;
    return ret;  
    
}
field_id monster::bloodType() {
    if (has_flag(MF_ACID_BLOOD))
        //A monster that has the death effect "ACID" does not need to have acid blood.
        return fd_acid;
    if (has_flag(MF_BILE_BLOOD))
        return fd_bile;
    if (has_flag(MF_LARVA) || has_flag(MF_ARTHROPOD_BLOOD))
        return fd_blood_invertebrate;
    if (made_of("veggy"))
        return fd_blood_veggy;
    if (made_of("iflesh"))
        return fd_blood_insect;
    if (has_flag(MF_WARM))
        return fd_blood;
    return fd_null; //Please update the corpse blood type code at mtypedef.cpp modifying these rules!
}
field_id monster::monBloodType() {
    if (has_flag(MF_ACID_BLOOD))
        //A monster that has the death effect "ACID" does not need to have acid blood.
        return fd_acid;
    if (has_flag(MF_BILE_BLOOD))
        return fd_bile;
    if (has_flag(MF_LARVA) || has_flag(MF_ARTHROPOD_BLOOD))
        return fd_blood_invertebrate;
    if (made_of("veggy"))
        return fd_blood_veggy;
    if (made_of("iflesh"))
        return fd_blood_insect;
    if (has_flag(MF_WARM))
        return fd_blood;
    return fd_null; //Please update the corpse blood type code at activity_on_turn_pulp() in game.cpp when modifying these rules!
                    //And splatter() in ranged.cpp
}
Exemple #11
0
field_id mtype::gibType() const
{
    if( has_flag( MF_LARVA ) || in_species( MOLLUSK ) ) {
        return fd_gibs_invertebrate;
    }
    if( made_of( material_id( "veggy" ) ) ) {
        return fd_gibs_veggy;
    }
    if( made_of( material_id( "iflesh" ) ) ) {
        return fd_gibs_insect;
    }
    if( made_of( material_id( "flesh" ) ) ) {
        return fd_gibs_flesh;
    }
    // There are other materials not listed here like steel, protoplasmic, powder, null, stone, bone
    return fd_null;
}
Exemple #12
0
void monster::process_effects(game *g)
{
 for (int i = 0; i < effects.size(); i++) {
  switch (effects[i].type) {
  case ME_POISONED:
   speed -= rng(0, 3);
   hurt(rng(1, 3));
   break;

// MATERIALS-TODO: use fire resistance
  case ME_ONFIRE:
   if (made_of("flesh"))
    hurt(rng(3, 8));
   if (made_of("veggy"))
    hurt(rng(10, 20));
   if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
       made_of("wool"))
    hurt(rng(15, 40));
   break;

  }
  if (effects[i].duration > 0) {
   effects[i].duration--;
   if (g->debugmon)
    debugmsg("Duration %d", effects[i].duration);
  }
  if (effects[i].duration == 0) {
   if (g->debugmon)
    debugmsg("Deleting");
   effects.erase(effects.begin() + i);
   i--;
  }
 }
}
Exemple #13
0
void monster::process_effects(game *g)
{
 for (int i = 0; i < effects.size(); i++) {
  switch (effects[i].type) {
  case ME_POISONED:
   speed -= rng(0, 3);
   hurt(rng(1, 3));
   break;

  case ME_ONFIRE:
   if (made_of(FLESH))
    hurt(rng(3, 8));
   if (made_of(VEGGY))
    hurt(rng(10, 20));
   if (made_of(PAPER) || made_of(POWDER) || made_of(WOOD) || made_of(COTTON) ||
       made_of(WOOL))
    hurt(rng(15, 40));
   break;

  }
  if (effects[i].duration > 0) {
   effects[i].duration--;
   if (g->debugmon)
    debugmsg("Duration %d", effects[i].duration);
  }
  if (effects[i].duration == 0) {
   if (g->debugmon)
    debugmsg("Deleting");
   effects.erase(effects.begin() + i);
   i--;
  }
 }
}
Exemple #14
0
item::item(itype* it, unsigned int turn)
{
 if(!it)
  type = nullitem();
 else
  type = it;
 bday = turn;
 name = "";
 invlet = 0;
 damage = 0;
 burnt = 0;
 poison = 0;
 mode = IF_NULL;
 item_flags = 0;
 item_counter = 0;
 active = false;
 curammo = NULL;
 corpse = NULL;
 owned = -1;
 mission_id = -1;
 player_id = -1;
 if (it == NULL)
  return;
 if (it->is_gun())
  charges = 0;
 else if (it->is_ammo()) {
  it_ammo* ammo = dynamic_cast<it_ammo*>(it);
  charges = ammo->count;
 } else if (it->is_food()) {
  it_comest* comest = dynamic_cast<it_comest*>(it);
  if (comest->charges == 1 && !made_of(LIQUID))
  charges = -1;
  else
   charges = comest->charges;
 } else if (it->is_tool()) {
  it_tool* tool = dynamic_cast<it_tool*>(it);
  if (tool->max_charges == 0)
   charges = -1;
  else
   charges = tool->def_charges;
 } else if ((it->is_gunmod() && it->id == "spare_mag") || it->item_flags & mfb(IF_MODE_AUX)) {
  charges = 0;
 } else
  charges = -1;
 if(it->is_var_veh_part()){
  it_var_veh_part* varcarpart = dynamic_cast<it_var_veh_part*>(it);
  bigness= rng( varcarpart->min_bigness, varcarpart->max_bigness);
 }
}
Exemple #15
0
field_id mtype::bloodType() const
{
    if( has_flag( MF_ACID_BLOOD ) )
        //A monster that has the death effect "ACID" does not need to have acid blood.
    {
        return fd_acid;
    }
    if( has_flag( MF_BILE_BLOOD ) ) {
        return fd_bile;
    }
    if( has_flag( MF_LARVA ) || has_flag( MF_ARTHROPOD_BLOOD ) ) {
        return fd_blood_invertebrate;
    }
    if( made_of( material_id( "veggy" ) ) ) {
        return fd_blood_veggy;
    }
    if( made_of( material_id( "iflesh" ) ) ) {
        return fd_blood_insect;
    }
    if( has_flag( MF_WARM ) && made_of( material_id( "flesh" ) ) ) {
        return fd_blood;
    }
    return fd_null;
}
Exemple #16
0
item::item(itype *it, unsigned int turn, char let)
{
 if(!it)
  type = nullitem();
 else
  type = it;
 bday = turn;
 name = "";
 damage = 0;
 burnt = 0;
 poison = 0;
 mode = IF_NULL;
 active = false;
 if (it->is_gun()) {
  charges = 0;
 } else if (it->is_ammo()) {
  it_ammo* ammo = dynamic_cast<it_ammo*>(it);
  charges = ammo->count;
 } else if (it->is_food()) {
  it_comest* comest = dynamic_cast<it_comest*>(it);
  if (comest->charges == 1 && !made_of(LIQUID))
    charges = -1;
  else
   charges = comest->charges;
 } else if (it->is_tool()) {
  it_tool* tool = dynamic_cast<it_tool*>(it);
  if (tool->max_charges == 0)
   charges = -1;
  else
   charges = tool->def_charges;
 } else if (it->is_gunmod() && it->id == itm_spare_mag) {
  charges = 0;
 } else {
  charges = -1;
 }
 if(it->is_var_veh_part()){
  it_var_veh_part* engine = dynamic_cast<it_var_veh_part*>(it);
  bigness= rng( engine->min_bigness, engine->max_bigness);
 }
 curammo = NULL;
 corpse = NULL;
 owned = -1;
 invlet = let;
 mission_id = -1;
 player_id = -1;
}
Exemple #17
0
void monster::process_effects(game *g)
{
    for (int i = 0; i < effects.size(); i++) {
        switch (effects[i].type) {
        case ME_ONFIRE:
            if (made_of(FLESH))
                hurt(rng(3, 8));
            if (made_of(VEGGY))
                hurt(rng(10, 20));
            if (made_of(PAPER) || made_of(POWDER) || made_of(WOOD) || made_of(COTTON) ||
                    made_of(WOOL))
                hurt(rng(15, 40));
            break;

        }
        effects[i].duration--;
        if (effects[i].duration <= 0) {
            effects.erase(effects.begin() + i);
            i--;
        }
    }
}
Exemple #18
0
void monster::process_effects()
{
    for( auto effect_it = effects.begin(); effect_it != effects.end(); ++effect_it ) {
        std::string id = effect_it->second.get_id();
        if (id == "nasty_poisoned") {
            mod_speed_bonus( -rng(3, 5) );
            apply_damage( nullptr, bp_torso, rng( 3, 6 ) );
        } if (id == "poisoned") {
            mod_speed_bonus( -rng(0, 3) );
            apply_damage( nullptr, bp_torso, rng( 1, 3 ) );

        // MATERIALS-TODO: use fire resistance
        } else if (id == "onfire") {
            if (made_of("flesh") || made_of("iflesh"))
                apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
            if (made_of("veggy"))
                apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
            if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                made_of("wool"))
                apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
        }
    }

    //If this monster has the ability to heal in combat, do it now.
    if( has_flag( MF_REGENERATES_50 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( this ) ) {
                add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() );
            }
            hp += 50;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }
    if( has_flag( MF_REGENERATES_10 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( this ) ) {
                add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() );
            }
            hp += 10;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }

    //Monster will regen morale and aggression if it is on max HP
    //It regens more morale and aggression if is currently fleeing.
    if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) {
        if( is_fleeing( g->u ) ) {
            morale = type->morale;
            anger = type->agro;
        }
        if( morale <= type->morale ) {
            morale += 1;
        }
        if( anger <= type->agro ) {
            anger += 1;
        }
        if( morale < 0 ) {
            morale += 5;
        }
        if( anger < 0 ) {
            anger += 5;
        }
    }

    // If this critter dies in sunlight, check & assess damage.
    if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) {
        if( g->u.sees( this ) ) {
            add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() );
        }
        hp -= 100;
        if( hp < 0 ) {
            hp = 0;
        }
    }

    Creature::process_effects();
}
void monster::process_effects()
{
    // Monster only effects
    int mod = 1;
    for( auto &elem : effects ) {
        for( auto &_effect_it : elem.second ) {
            auto &it = _effect_it.second;
            // Monsters don't get trait-based reduction, but they do get effect based reduction
            bool reduced = has_effect(it.get_resist_effect());

            mod_speed_bonus(it.get_mod("SPEED", reduced));

            int val = it.get_mod("HURT", reduced);
            if (val > 0) {
                if(it.activated(calendar::turn, "HURT", val, reduced, mod)) {
                    apply_damage(nullptr, bp_torso, val);
                }
            }

            std::string id = _effect_it.second.get_id();
            // MATERIALS-TODO: use fire resistance
            if (id == "onfire") {
                if (made_of("flesh") || made_of("iflesh"))
                    apply_damage( nullptr, bp_torso, rng( 3, 8 ) );
                if (made_of("veggy"))
                    apply_damage( nullptr, bp_torso, rng( 10, 20 ) );
                if (made_of("paper") || made_of("powder") || made_of("wood") || made_of("cotton") ||
                    made_of("wool"))
                    apply_damage( nullptr, bp_torso, rng( 15, 40 ) );
            }
        }
    }

    //If this monster has the ability to heal in combat, do it now.
    if( has_flag( MF_REGENERATES_50 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( *this ) ) {
                add_msg( m_warning, _( "The %s is visibly regenerating!" ), name().c_str() );
            }
            hp += 50;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }
    if( has_flag( MF_REGENERATES_10 ) ) {
        if( hp < type->hp ) {
            if( one_in( 2 ) && g->u.sees( *this ) ) {
                add_msg( m_warning, _( "The %s seems a little healthier." ), name().c_str() );
            }
            hp += 10;
            if( hp > type->hp ) {
                hp = type->hp;
            }
        }
    }

    //Monster will regen morale and aggression if it is on max HP
    //It regens more morale and aggression if is currently fleeing.
    if( has_flag( MF_REGENMORALE ) && hp >= type->hp ) {
        if( is_fleeing( g->u ) ) {
            morale = type->morale;
            anger = type->agro;
        }
        if( morale <= type->morale ) {
            morale += 1;
        }
        if( anger <= type->agro ) {
            anger += 1;
        }
        if( morale < 0 ) {
            morale += 5;
        }
        if( anger < 0 ) {
            anger += 5;
        }
    }

    // If this critter dies in sunlight, check & assess damage.
    if( has_flag( MF_SUNDEATH ) && g->is_in_sunlight( posx(), posy() ) ) {
        if( g->u.sees( *this ) ) {
            add_msg( m_good, _( "The %s burns horribly in the sunlight!" ), name().c_str() );
        }
        apply_damage( nullptr, bp_torso, 100 );
        if( hp < 0 ) {
            hp = 0;
        }
    }

    Creature::process_effects();
}
/**
 * Attempts to harm a creature with a projectile.
 *
 * @param source Pointer to the creature who shot the projectile.
 * @param attack A structure describing the attack and its results.
 */
void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack )
{
    const double missed_by = attack.missed_by;
    if( missed_by >= 1.0 ) {
        // Total miss
        return;
    }

    const projectile &proj = attack.proj;
    dealt_damage_instance &dealt_dam = attack.dealt_dam;
    const auto &proj_effects = proj.proj_effects;

    const bool u_see_this = g->u.sees(*this);

    const int avoid_roll = dodge_roll();
    // Do dice(10, speed) instead of dice(speed, 10) because speed could potentially be > 10000
    const int diff_roll = dice( 10, proj.speed );
    // Partial dodge, capped at [0.0, 1.0], added to missed_by
    const double dodge_rescaled = avoid_roll / static_cast<double>( diff_roll );
    const double goodhit = missed_by + std::max( 0.0, std::min( 1.0, dodge_rescaled ) ) ;

    if( goodhit >= 1.0 ) {
        // "Avoid" rather than "dodge", because it includes removing self from the line of fire
        //  rather than just Matrix-style bullet dodging
        if( source != nullptr && g->u.sees( *source ) ) {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid %s projectile!"),
                _("<npcname> avoids %s projectile."),
                source->disp_name(true).c_str() );
        } else {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid an incoming projectile!"),
                _("<npcname> avoids an incoming projectile.") );
        }

        attack.missed_by = 1.0; // Arbitrary value
        return;
    }

    // Bounce applies whether it does damage or not.
    if( proj.proj_effects.count( "BOUNCE" ) ) {
        add_effect( effect_bounced, 1_turns );
    }

    body_part bp_hit;
    double hit_value = missed_by + rng_float(-0.5, 0.5);
    // Headshots considered elsewhere
    if( hit_value <= 0.4 ) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        if( one_in(2)) {
            bp_hit = bp_leg_l;
        } else {
            bp_hit = bp_leg_r;
        }
    } else {
        if( one_in(2)) {
            bp_hit = bp_arm_l;
        } else {
            bp_hit = bp_arm_r;
        }
    }

    double damage_mult = 1.0;

    std::string message = "";
    game_message_type gmtSCTcolor = m_neutral;

    if( goodhit < accuracy_headshot ) {
        message = _("Headshot!");
        gmtSCTcolor = m_headshot;
        damage_mult *= rng_float(1.95, 2.05);
        bp_hit = bp_head; // headshot hits the head, of course

    } else if( goodhit < accuracy_critical ) {
        message = _("Critical!");
        gmtSCTcolor = m_critical;
        damage_mult *= rng_float(1.5, 2.0);

    } else if( goodhit < accuracy_goodhit ) {
        message = _("Good hit!");
        gmtSCTcolor = m_good;
        damage_mult *= rng_float(1, 1.5);

    } else if( goodhit < accuracy_standard ) {
        damage_mult *= rng_float(0.5, 1);

    } else if( goodhit < accuracy_grazing ) {
        message = _("Grazing hit.");
        gmtSCTcolor = m_grazing;
        damage_mult *= rng_float(0, .25);
    }

    if( source != nullptr && !message.empty() ) {
        source->add_msg_if_player(m_good, message.c_str());
    }

    attack.missed_by = goodhit;

    // copy it, since we're mutating
    damage_instance impact = proj.impact;
    if( damage_mult > 0.0f && proj_effects.count( "NO_DAMAGE_SCALING" ) ) {
        damage_mult = 1.0f;
    }

    impact.mult_damage(damage_mult);

    if( proj_effects.count( "NOGIB" ) > 0 ) {
        float dmg_ratio = (float)impact.total_damage() / get_hp_max( player::bp_to_hp( bp_hit ) );
        if( dmg_ratio > 1.25f ) {
            impact.mult_damage( 1.0f / dmg_ratio );
        }
    }

    dealt_dam = deal_damage(source, bp_hit, impact);
    dealt_dam.bp_hit = bp_hit;

    // Apply ammo effects to target.
    if (proj.proj_effects.count("FLAME")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng( 8_turns, 20_turns ), bp_hit );
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, rng( 5_turns, 10_turns ), bp_hit );
        }
    } else if (proj.proj_effects.count("INCENDIARY") ) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng( 2_turns, 6_turns ), bp_hit );
        } else if ( (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) &&
                    one_in(4) ) {
            add_effect( effect_onfire, rng( 1_turns, 4_turns ), bp_hit );
        }
    } else if (proj.proj_effects.count("IGNITE")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, 6_turns, bp_hit );
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, 10_turns, bp_hit );
        }
    }

    if( bp_hit == bp_head && proj_effects.count( "BLINDS_EYES" ) ) {
        // TODO: Change this to require bp_eyes
        add_env_effect( effect_blind, bp_eyes, 5, rng( 3_turns, 10_turns ) );
    }

    if( proj_effects.count( "APPLY_SAP" ) ) {
        add_effect( effect_sap, 1_turns * dealt_dam.total_damage() );
    }

    int stun_strength = 0;
    if (proj.proj_effects.count("BEANBAG")) {
        stun_strength = 4;
    }
    if (proj.proj_effects.count("LARGE_BEANBAG")) {
        stun_strength = 16;
    }
    if( stun_strength > 0 ) {
        switch( get_size() ) {
        case MS_TINY:
            stun_strength *= 4;
            break;
        case MS_SMALL:
            stun_strength *= 2;
            break;
        case MS_MEDIUM:
        default:
            break;
        case MS_LARGE:
            stun_strength /= 2;
            break;
        case MS_HUGE:
            stun_strength /= 4;
            break;
        }
        add_effect( effect_stunned, 1_turns * rng( stun_strength / 2, stun_strength ) );
    }

    if(u_see_this) {
        if( damage_mult == 0 ) {
            if( source != nullptr ) {
                add_msg( source->is_player() ? _("You miss!") : _("The shot misses!") );
            }
        } else if( dealt_dam.total_damage() == 0 ) {
            //~ 1$ - monster name, 2$ - character's bodypart or monster's skin/armor
            add_msg( _("The shot reflects off %1$s %2$s!"), disp_name(true).c_str(),
                     is_monster() ?
                        skin_name().c_str() :
                        body_part_name_accusative(bp_hit).c_str() );
        } else if( is_player() ) {
                //monster hits player ranged
                //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value.
                add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ),
                                  body_part_name_accusative(bp_hit).c_str(),
                                  dealt_dam.total_damage());
        } else if( source != nullptr ) {
            if( source->is_player() ) {
                //player hits monster ranged
                SCT.add(posx(), posy(),
                        direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                        get_hp_bar(dealt_dam.total_damage(), get_hp_max(), true).first,
                        m_good, message, gmtSCTcolor);

                if (get_hp() > 0) {
                    SCT.add(posx(), posy(),
                            direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                            get_hp_bar(get_hp(), get_hp_max(), true).first, m_good,
                            //~ "hit points", used in scrolling combat text
                            _("hp"), m_neutral, "hp");
                } else {
                    SCT.removeCreatureHP();
                }

                add_msg(m_good, _("You hit %s for %d damage."),
                        disp_name().c_str(), dealt_dam.total_damage());
            } else if( u_see_this ) {
                //~ 1$ - shooter, 2$ - target
                add_msg(_("%1$s shoots %2$s."),
                        source->disp_name().c_str(), disp_name().c_str());
            }
        }
    }

    check_dead_state();
    attack.hit_critter = this;
    attack.missed_by = goodhit;
}