#include "monsters.hh"
#include "objects.hh"
+
+/*! \brief Do the baseline melee damage calculation
+ *
+ * \return The computed basic damage output of the player's weapon/hands
+ */
+int player_melee_base(void)
+{
+ int dmgbase;
+ int damage;
+ if (u.weapon != NO_OBJ)
+ {
+ dmgbase = permobjs[objects[u.weapon].obj_id].power + (u.body / 10);
+ damage = dmgbase / 3 + one_die(dmgbase - dmgbase / 3);
+ }
+ else
+ {
+ damage = u.body / 10;
+ }
+ return damage;
+}
+
+/*! \brief Calculate the effect of the player's damage amplifier ring
+ */
+bool ring_effectiveness(int mon, int ring_pobj, int damage, int *bonus_damage, int *vamp_healing)
+{
+ bool rv = false;
+ int pm = monsters[mon].mon_id;
+ *vamp_healing = 0;
+ switch (ring_pobj)
+ {
+ case PO_FIRE_RING:
+ if (!pmon_resists_fire(pm))
+ {
+ *bonus_damage = dice(2, 4) + ((damage + 1) / 2);
+ rv = true;
+ }
+ break;
+ case PO_VAMPIRE_RING:
+ if (!pmon_resists_necro(pm))
+ {
+ *bonus_damage = dice(2, 4) + ((damage + 3) / 4);
+ *vamp_healing = std::min(monsters[mon].hpcur, (damage + 5) / 6);
+ rv = true;
+ }
+ break;
+ case PO_FROST_RING:
+ if (!pmon_resists_cold(pm))
+ {
+ *bonus_damage = dice(2, 4) + ((damage + 3) / 4);
+ rv = true;
+ }
+ break;
+ default:
+ break;
+ }
+ return rv;
+}
+
+/*! \brief Common damage path for uhitm(), player_power_attack()...
+ *
+ * \param mon Monster hit
+ * \param damage Rolled damage before rings are applied
+ */
+void resolve_player_melee(int mon, int damage)
+{
+ bool ring_eff;
+ int ring_bonus;
+ int healing; // = 0;
+ if (u.ring != NO_OBJ)
+ {
+ ring_eff = ring_effectiveness(mon, objects[u.ring].obj_id, damage, &ring_bonus, &healing);
+ if (ring_eff)
+ {
+ notify_ring_boost(mon, objects[u.ring].obj_id);
+ damage += ring_bonus;
+ }
+ }
+ notify_player_hurt_mon(mon, damage);
+ damage_mon(mon, damage, true);
+ if (healing > 0)
+ {
+ heal_u(healing, 0, 1);
+ }
+ if (u.weapon != NO_OBJ)
+ {
+ damage_obj(u.weapon);
+ }
+}
+
+/*! \brief Resolve the "Power Attack" combo move
+ *
+ * \param delta Direction in which player is attacking.
+ */
+Action_cost player_power_attack(Offset delta)
+{
+ Coord c = u.pos + delta;
+ int damage;
+ int mon = lvl.mon_at(c);
+ /* Power Attack: Always hit, do +75% damage. */
+ notify_player_combo_powatk(mon);
+ damage = (player_melee_base() * 7) / 4;
+ resolve_player_melee(mon, damage);
+ return Cost_std;
+}
+
Action_cost player_attack(Offset delta)
{
Coord c = u.pos + delta;
- if ((objects[u.weapon].obj_id == PO_BOW) || (objects[u.weapon].obj_id == PO_CROSSBOW))
+ if (wielding_ranged_weapon())
{
ushootm(delta);
}
int uhitm(int mon)
{
Mon *mp;
- Obj *wep;
- Permobj *pwep;
- Obj *ring;
int tohit;
int damage;
- int healing;
int hitbase = u.agility + u.level;
- int dmgbase;
mp = monsters + mon;
tohit = hitbase / 3 + zero_die(hitbase - hitbase / 3);
if (tohit < mp->defence)
return 0; /* Missed. */
}
notify_player_hit_mon(mon);
- if (u.weapon != NO_OBJ)
- {
- wep = objects + u.weapon;
- pwep = permobjs + wep->obj_id;
- dmgbase = pwep->power + u.body / 10;
- damage = dmgbase / 3 + one_die(dmgbase - dmgbase / 3);
- }
- else
- {
- damage = u.body / 10;
- }
- if (u.ring != NO_OBJ)
- {
- ring = objects + u.ring;
- switch (ring->obj_id)
- {
- case PO_FIRE_RING:
- if (!pmon_resists_fire(mp->mon_id))
- {
- notify_ring_boost(mon, ring->obj_id);
- damage += (damage + 1) / 2 + dice(2, 4);
- }
- break;
- case PO_VAMPIRE_RING:
- if (!pmon_is_undead(mp->mon_id))
- {
- notify_ring_boost(mon, ring->obj_id);
- damage += (damage + 3) / 4 + dice(2, 4);
- healing = std::min(mp->hpcur, (damage + 5) / 6);
- heal_u(healing, 0, 1);
- }
- break;
- case PO_FROST_RING:
- if (!pmon_resists_cold(mp->mon_id))
- {
- notify_ring_boost(mon, ring->obj_id);
- damage += (damage + 2) / 3 + dice(1, 6);
- }
- }
- }
- notify_player_hurt_mon(mon, damage);
- damage_mon(mon, damage, true);
- if (u.weapon != NO_OBJ)
- {
- damage_obj(u.weapon);
- }
+ damage = player_melee_base();
+ resolve_player_melee(mon, damage);
return 1; /* Hit. */
}