Power attack, and some notification-related cleanup.
authorMartin Read <martin@blackswordsonics.com>
Wed, 19 Feb 2014 01:46:42 +0000 (01:46 +0000)
committerMartin Read <martin@blackswordsonics.com>
Wed, 19 Feb 2014 01:46:42 +0000 (01:46 +0000)
* combat.cc,combat.hh: Implement power attack and refactor uhitm().
* map.cc: Replace touch_back_buffer() with notify_fov()
* notify-local-tty.cc, notify.hh: Various new notifications.
* objects.cc: Reflow eat_food(), eliminate reference to display vars therein.
* u.cc: Debug chain-of-detection for power attack

combat.cc
combat.hh
map.cc
notify-local-tty.cc
notify.hh
objects.cc
u.cc

index 37cd9aa..7d51ed9 100644 (file)
--- a/combat.cc
+++ b/combat.cc
 #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);
     }
@@ -53,14 +158,9 @@ Action_cost player_attack(Offset 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)
@@ -69,52 +169,8 @@ int uhitm(int mon)
         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. */
 }
 
index 27df577..fe0699d 100644 (file)
--- a/combat.hh
+++ b/combat.hh
@@ -41,6 +41,8 @@
 /* XXX combat.c data and funcs */
 extern Action_cost throw_flask(int obj, Offset step);
 extern Action_cost player_attack(Offset step);
+extern Action_cost player_power_attack(Offset step);
+extern void resolve_player_melee(int mon, int damage);
 extern int mhitu(int mon, Damtyp dtyp);
 extern int uhitm(int mon);
 extern int mshootu(int mon);
diff --git a/map.cc b/map.cc
index 406b0e1..6e36831 100644 (file)
--- a/map.cc
+++ b/map.cc
@@ -600,7 +600,7 @@ void inject_player(void)
 void look_around_you(void)
 {
     compute_fov();
-    touch_back_buffer();
+    notify_fov();
 }
 
 Terrain_props terrain_props[NUM_TERRAINS] = 
index b9738c1..45504b9 100644 (file)
@@ -351,6 +351,13 @@ void notify_player_hit_mon(int mon)
     print_msg(".\n");
 }
 
+void notify_player_combo_powatk(int mon)
+{
+    print_msg("You deal a powerful blow to ");
+    print_mon_name(mon, 1);
+    print_msg(".\n");
+}
+
 void notify_player_shot_terrain(int obj, Coord c)
 {
     print_msg("Your %s hits the %s.\n", (objects[obj].obj_id == PO_CROSSBOW) ? "bolt" : "arrow", terrain_props[lvl.terrain_at(c)].name);
@@ -829,11 +836,13 @@ void notify_dress_shredded(void)
 
 void notify_eat_food(bool ravenous)
 {
+    status_updated = true;
     print_msg(ravenous ? "You ravenously devour your food!\n" : "You eat some food.\n");
 }
 
 void notify_ingest_spleen(void)
 {
+    status_updated = true;
     print_msg("%s power suffuses your body as you devour the devil spleen.\n", u.corrupt() ? "Delicious" : "Vile");
 }
 
@@ -926,6 +935,11 @@ void notify_new_mon_at(Coord c, int mon)
     newsym(c);
 }
 
+void notify_fov(void)
+{
+    touch_back_buffer();
+}
+
 /* Debugging notifications */
 
 void debug_bad_monspell(int spell)
index 67766f5..c1aa42b 100644 (file)
--- a/notify.hh
+++ b/notify.hh
@@ -114,6 +114,7 @@ void notify_ring_boost(int mon, int pobj);
 void notify_player_hit_mon(int mon);
 void notify_player_hurt_mon(int mon, int damage);
 void notify_player_killed_mon(int mon);
+void notify_player_combo_powatk(int mon);
 void notify_knockback_mon_resisted(int mon);
 void notify_knockback_mon_blocked(int mon);
 void notify_knockback_mon_hover_lava(int mon);
@@ -152,6 +153,9 @@ void notify_necrosmite_fail(void);
 void notify_necrosmite_hit(void);
 void notify_hellfire_hit(bool resisted);
 
+// Miscellaneous notifications
+void notify_fov(void);
+
 // Debugging notifications
 void debug_move_oob(Coord c);
 void debug_body_gain(int amount);
index a812346..5d4b619 100644 (file)
@@ -165,6 +165,8 @@ bool consume_obj(int obj)
 Action_cost eat_food(int obj)
 {
     Obj *optr = objects + obj;
+    bool ravenous = (u.food < 0);
+    u.food += 1500;
     if (permobjs[optr->obj_id].poclass != POCLASS_FOOD)
     {
         debug_eat_non_food(obj);
@@ -186,11 +188,8 @@ Action_cost eat_food(int obj)
     }
     else
     {
-        notify_eat_food(u.food < 0);
+        notify_eat_food(ravenous);
     }
-    u.food += 1500;
-    status_updated = 1;
-    display_update();
     consume_obj(obj);
     return Cost_std;
 }
diff --git a/u.cc b/u.cc
index 63c029a..0c07a18 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -564,7 +564,8 @@ enum Combo_phase
 
 bool action_rewrite(Action const *act, Action *revised_act)
 {
-    Coord c;
+    Coord c = u.pos;
+    int mon = NO_MON;
     Offset o;
     Action tmp_act = *act;
     Combo_phase p;
@@ -586,6 +587,7 @@ bool action_rewrite(Action const *act, Action *revised_act)
             p = Combo_invalid;
             break;
         }
+        mon = lvl.mon_at(c);
         p = Combo_finisher;
         break;
     case WALK:
@@ -601,6 +603,7 @@ bool action_rewrite(Action const *act, Action *revised_act)
         }
         else if (lvl.mon_at(c) != NO_MON)
         {
+            mon = lvl.mon_at(c);
             tmp_act.cmd = ATTACK;
             rewrite_flag = true;
             p = Combo_finisher;
@@ -655,7 +658,8 @@ bool action_rewrite(Action const *act, Action *revised_act)
             switch (past_actions.front().cmd)
             {
             case STAND_STILL:
-                if (empty_handed() || wielding_melee_weapon())
+                if ((empty_handed() || wielding_melee_weapon()) &&
+                    (mon != NO_MON))
                 {
                     rewrite_flag = true;
                     tmp_act.cmd = CMD_POWER_ATTACK;
@@ -700,7 +704,7 @@ Action_cost do_player_action(Action *act)
     case CMD_POWER_ATTACK:
         step.y = act->details[0];
         step.x = act->details[1];
-        return player_attack(step);
+        return player_power_attack(step);
 
     case WALK:
         step.y = act->details[0];