void shoot_monster(game *g, player &p, monster &mon, int &dam, double goodhit, item* weapon) { // Gunmods don't have a type, so use the player weapon type. it_gun* firing = dynamic_cast<it_gun*>(p.weapon.type); std::string message; bool u_see_mon = g->u_see(&(mon)); if (mon.has_flag(MF_HARDTOSHOOT) && !one_in(4) && weapon->curammo->phase != LIQUID && weapon->curammo->accuracy >= 4) { // Buckshot hits anyway if (u_see_mon) g->add_msg("The shot passes through the %s without hitting.", mon.name().c_str()); goodhit = 1; } else { // Not HARDTOSHOOT // Armor blocks BEFORE any critical effects. int zarm = mon.armor_cut(); zarm -= weapon->curammo->pierce; if (weapon->curammo->phase == LIQUID) zarm = 0; else if (weapon->curammo->accuracy < 4) // Shot doesn't penetrate armor well zarm *= rng(2, 4); if (zarm > 0) dam -= zarm; if (dam <= 0) { if (u_see_mon) g->add_msg("The shot reflects off the %s!", mon.name_with_armor().c_str()); dam = 0; goodhit = 1; } if (goodhit < .1 && !mon.has_flag(MF_NOHEAD)) { message = "Headshot!"; dam = rng(5 * dam, 8 * dam); p.practice(g->turn, firing->skill_used, 5); } else if (goodhit < .2) { message = "Critical!"; dam = rng(dam * 2, dam * 3); p.practice(g->turn, firing->skill_used, 2); } else if (goodhit < .4) { dam = rng(int(dam * .9), int(dam * 1.5)); p.practice(g->turn, firing->skill_used, rng(0, 2)); } else if (goodhit <= .7) { message = "Grazing hit."; dam = rng(0, dam); } else dam = 0; // Find the zombie at (x, y) and hurt them, MAYBE kill them! if (dam > 0) { mon.moves -= dam * 5; if (&p == &(g->u) && u_see_mon) g->add_msg("%s You hit the %s for %d damage.", message.c_str(), mon.name().c_str(), dam); else if (u_see_mon) g->add_msg("%s %s shoots the %s.", message.c_str(), p.name.c_str(), mon.name().c_str()); bool bMonDead = mon.hurt(dam); hit_animation(mon.posx - g->u.posx + VIEWX - g->u.view_offset_x, mon.posy - g->u.posy + VIEWY - g->u.view_offset_y, red_background(mon.type->color), (bMonDead) ? '%' : mon.symbol()); if (bMonDead) g->kill_mon(g->mon_at(mon.posx, mon.posy), (&p == &(g->u))); else if (weapon->curammo->ammo_effects != 0) g->hit_monster_with_flags(mon, weapon->curammo->ammo_effects); dam = 0; } } }
void shoot_monster(game *g, player &p, monster &mon, int &dam, double goodhit, item* weapon) { // Gunmods don't have a type, so use the player weapon type. it_gun* firing = dynamic_cast<it_gun*>(p.weapon.type); std::string message; bool u_see_mon = g->u_see(&(mon)); int adjusted_damage = dam; if (mon.has_flag(MF_HARDTOSHOOT) && !one_in(10 - 10 * (.8 - goodhit)) && // Maxes out at 50% chance with perfect hit weapon->curammo->phase != LIQUID && !weapon->curammo->ammo_effects.count("SHOT") && !weapon->curammo->ammo_effects.count("BOUNCE")) { if (u_see_mon) g->add_msg(_("The shot passes through the %s without hitting."), mon.name().c_str()); goodhit = 1; } else { // Not HARDTOSHOOT // Armor blocks BEFORE any critical effects. int zarm = mon.armor_cut(); zarm -= weapon->curammo->pierce; if (weapon->curammo->phase == LIQUID) zarm = 0; else if (weapon->curammo->ammo_effects.count("SHOT")) // Shot doesn't penetrate armor well zarm *= rng(2, 3); if (zarm > 0) adjusted_damage -= zarm; if (adjusted_damage <= 0) { if (u_see_mon) g->add_msg(_("The shot reflects off the %s!"), mon.name_with_armor().c_str()); adjusted_damage = 0; goodhit = 1; } if (goodhit <= .1 && !mon.has_flag(MF_NOHEAD)) { message = _("Headshot!"); adjusted_damage = rng(5 * adjusted_damage, 8 * adjusted_damage); p.practice(g->turn, firing->skill_used, 5); } else if (goodhit <= .2) { message = _("Critical!"); adjusted_damage = rng(adjusted_damage * 2, adjusted_damage * 3); p.practice(g->turn, firing->skill_used, 3); } else if (goodhit <= .4) { message = _("Good hit!"); adjusted_damage = rng(adjusted_damage , adjusted_damage * 2); p.practice(g->turn, firing->skill_used, 2); } else if (goodhit <= .6) { adjusted_damage = rng(adjusted_damage / 2, adjusted_damage); p.practice(g->turn, firing->skill_used, 1); } else if (goodhit <= .8) { message = _("Grazing hit."); adjusted_damage = rng(0, adjusted_damage); } else { adjusted_damage = 0; } if(item(weapon->curammo, 0).has_flag("NOGIB")) { adjusted_damage = std::min(adjusted_damage, mon.hp+10); } // Find the zombie at (x, y) and hurt them, MAYBE kill them! if (adjusted_damage > 0) { switch (mon.type->size) { case MS_TINY: mon.moves -= rng(0, adjusted_damage * 5); break; case MS_SMALL: mon.moves -= rng(0, adjusted_damage * 3); break; case MS_MEDIUM: mon.moves -= rng(0, adjusted_damage); break; case MS_LARGE: mon.moves -= rng(0, adjusted_damage / 3); break; case MS_HUGE: mon.moves -= rng(0, adjusted_damage / 5); break; } if (&p == &(g->u) && u_see_mon) { g->add_msg(_("%s You hit the %s for %d damage."), message.c_str(), mon.name().c_str(), adjusted_damage); } else if (u_see_mon) { g->add_msg(_("%s %s shoots the %s."), message.c_str(), p.name.c_str(), mon.name().c_str()); } bool bMonDead = mon.hurt(adjusted_damage, dam); if( u_see_mon ) { hit_animation(mon.posx - g->u.posx + VIEWX - g->u.view_offset_x, mon.posy - g->u.posy + VIEWY - g->u.view_offset_y, red_background(mon.type->color), (bMonDead) ? '%' : mon.symbol()); } if (bMonDead) { g->kill_mon(g->mon_at(mon.posx, mon.posy), (&p == &(g->u))); } else if (!weapon->curammo->ammo_effects.empty()) { g->hit_monster_with_flags(mon, weapon->curammo->ammo_effects); } adjusted_damage = 0; } } dam = adjusted_damage; }