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"; }
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(); }
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; }
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 }
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; }
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--; } } }
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--; } } }
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); } }
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; }
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; }
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--; } } }
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; }