From 967b12d940462b13bd07f989b15c94ab9000a6be Mon Sep 17 00:00:00 2001
From: Chris Oelmueller <chris.oelmueller@gmail.com>
Date: Sat, 22 Mar 2014 06:59:22 +0100
Subject: Introduce SPFLAG_MR_CHECK for spells checking monster MR

Conflicts:
	crawl-ref/source/spl-data.h
---
 crawl-ref/source/spl-cast.h |  1 +
 crawl-ref/source/spl-data.h | 26 +++++++++++++-------------
 2 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index 0277a19..5a073b4 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -42,6 +42,7 @@ enum spflag_type
     SPFLAG_UTILITY             = 0x1000000,      // usable no matter what foe is
     SPFLAG_NO_GHOST            = 0x2000000,      // ghosts can't get this spell
     SPFLAG_CLOUD               = 0x4000000,      // makes a cloud
+    SPFLAG_MR_CHECK            = 0x8000000,      // spell that checks monster MR
 };
 
 enum spret_type
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index 0662878..980e89f 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -178,7 +178,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_SLOW, "Slow",
      SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      2,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -201,7 +201,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_PETRIFY, "Petrify",
      SPTYP_TRANSMUTATION | SPTYP_EARTH,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      4,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -212,7 +212,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_CONFUSE, "Confuse",
      SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      3,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -338,7 +338,7 @@ static const struct spell_desc spelldata[] =
     SPELL_TELEPORT_OTHER, "Teleport Other",
      SPTYP_TRANSLOCATION,
      SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_ESCAPE
-         | SPFLAG_EMERGENCY | SPFLAG_NEEDS_TRACER,
+         | SPFLAG_EMERGENCY | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      3,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -596,7 +596,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_ENSLAVEMENT, "Enslavement",
      SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      4,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -618,7 +618,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_PAIN, "Pain",
      SPTYP_NECROMANCY,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_BATTLE | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_BATTLE | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      1,
      25,
      6, 6,
@@ -629,7 +629,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_CONTROL_UNDEAD, "Control Undead",
      SPTYP_NECROMANCY,
-     SPFLAG_NONE,
+     SPFLAG_MR_CHECK,
      4,
      200,
      -1, -1,
@@ -856,7 +856,7 @@ static const struct spell_desc spelldata[] =
     SPELL_BANISHMENT, "Banishment",
      SPTYP_TRANSLOCATION,
      SPFLAG_DIR_OR_TARGET | SPFLAG_UNHOLY | SPFLAG_CHAOTIC | SPFLAG_MONSTER
-         | SPFLAG_EMERGENCY | SPFLAG_NEEDS_TRACER,
+         | SPFLAG_EMERGENCY | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      4,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -1119,7 +1119,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_AGONY, "Agony",
      SPTYP_NECROMANCY,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      5,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -1373,7 +1373,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_HIBERNATION, "Ensorcelled Hibernation",
      SPTYP_HEXES | SPTYP_ICE,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      2,
      56,
      LOS_RADIUS, LOS_RADIUS,
@@ -1485,7 +1485,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_CORONA, "Corona",
      SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      1,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -1663,7 +1663,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_PARALYSE, "Paralyse",
      SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_NEEDS_TRACER,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_MONSTER | SPFLAG_NEEDS_TRACER | SPFLAG_MR_CHECK,
      4,
      200,
      LOS_RADIUS, LOS_RADIUS,
@@ -2596,7 +2596,7 @@ static const struct spell_desc spelldata[] =
 {
     SPELL_DAZZLING_SPRAY, "Dazzling Spray",
      SPTYP_CONJURATION | SPTYP_HEXES,
-     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF,
+     SPFLAG_DIR_OR_TARGET | SPFLAG_NOT_SELF | SPFLAG_MR_CHECK,
      3,
      100,
      6, 6,
-- 
2.1.3


From e22a36d1c2ae3defafb7ee2ca5f8a6255da21ff6 Mon Sep 17 00:00:00 2001
From: Chris Oelmueller <chris.oelmueller@gmail.com>
Date: Fri, 5 Dec 2014 17:49:11 +0100
Subject: Display success chance for targeted MR-checking spells

Also enabled for Banishment right now.

Making this resist more transparent has been the goal of two recent changes
to monster MR: moving from HD multipliers to fixed amounts, and displaying
that amount in monster lookup through x-v.

Hexes in particular are mostly binary success/fail outcome with monster MR
and spellpower as factors. One of these, monster MR, is fully visible
in-game as of recently, and the other is available in a slightly fuzzed
way. Both use bars instead of plain numbers for display purposes.

When implementing the chance display, I considered applying a fuzz to the
displayed chances as well, as to not "leak information". After playtesting
the fuzzed version, I revised my opinion and now believe it is much better
to present the actual not-fuzzed chances right where they belong.
For reference, "fuzzed" here means using the spellpower number corres-
ponding to the highest power bar displayed for calculating chances.

Because this certainly will come up in discussions, here are my thoughts:
Raw spellpower numbers are obfuscated through bars not because knowing
about them would break the game in several ways, but because the numbers
themselves would carry little meaning in the disconnected screen that
currently holds the power bars.

This is different in two ways from showing a chance that aims to correctly
provide players with information relevant to their choices: The number that
is calculated here has a clear and concise meaning (how likely to succeed)
and is presented right where it matters (in the targeter itself).

Of course players can, and some will, use the numbers to calculate their
spellpower - but it's not like that is impossible as of now, and more
importantly they cannot do much more with that information than what the
functionality added with this commit already provides.

Brought to compilation by |amethyst and to correctness by rwbarton, thanks!
---
 crawl-ref/source/ability.cc  | 13 ++++++++++---
 crawl-ref/source/directn.cc  |  2 +-
 crawl-ref/source/mon-info.h  |  2 +-
 crawl-ref/source/spl-cast.cc | 46 +++++++++++++++++++++++++++++++++++++++++++-
 crawl-ref/source/spl-cast.h  |  1 +
 5 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/crawl-ref/source/ability.cc b/crawl-ref/source/ability.cc
index 4909cca..af8e1b9 100644
--- a/crawl-ref/source/ability.cc
+++ b/crawl-ref/source/ability.cc
@@ -52,6 +52,7 @@
 #include "prompt.h"
 #include "religion.h"
 #include "skills.h"
+#include "spl-cast.h"
 #include "spl-clouds.h"
 #include "spl-damage.h"
 #include "spl-goditem.h"
@@ -2823,10 +2824,16 @@ static spret_type _do_ability(const ability_def& abil, bool fail)
         break;
 
     case ABIL_LUGONU_BANISH:
+    {
         beam.range = LOS_RADIUS;
+        const int pow = 16 + you.skill(SK_INVOCATIONS, 8);
 
-        if (!spell_direction(spd, beam))
+        if (!spell_direction(spd, beam, DIR_NONE, TARG_HOSTILE, 0,
+                             true, true, false, NULL, NULL, false, NULL,
+                             bind(desc_success_chance, placeholders::_1, pow)))
+        {
             return SPRET_ABORT;
+        }
 
         if (beam.target == you.pos())
         {
@@ -2834,8 +2841,8 @@ static spret_type _do_ability(const ability_def& abil, bool fail)
             return SPRET_ABORT;
         }
 
-        return zapping(ZAP_BANISHMENT, 16 + you.skill(SK_INVOCATIONS, 8), beam,
-                       true, nullptr, fail);
+        return zapping(ZAP_BANISHMENT, pow, beam, true, nullptr, fail);
+    }
 
     case ABIL_LUGONU_CORRUPT:
         fail_check();
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index 2baa117..8b7af33 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -3803,6 +3803,6 @@ vector<string> targeting_behaviour::get_monster_desc(const monster_info& mi)
 {
     vector<string> descs;
     if (get_desc_func)
-        _append_container(descs, (*get_desc_func)(mi));
+        _append_container(descs, (get_desc_func)(mi));
     return descs;
 }
diff --git a/crawl-ref/source/mon-info.h b/crawl-ref/source/mon-info.h
index 380b9bc..9d167db 100644
--- a/crawl-ref/source/mon-info.h
+++ b/crawl-ref/source/mon-info.h
@@ -351,5 +351,5 @@ void clear_monster_list_colours();
 
 void get_monster_info(vector<monster_info>& mons);
 
-typedef vector<string> (*desc_filter) (const monster_info& mi);
+typedef function<vector<string> (const monster_info& mi)> (desc_filter);
 #endif
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 6d69075..2e7f9b3 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -1143,6 +1143,41 @@ static void _spellcasting_corruption(spell_type spell)
     ouch(hp_cost, KILLED_BY_SOMETHING, MID_NOBODY, source);
 }
 
+// Returns the nth triangular number.
+static int _triangular_number(int n)
+{
+    return n * (n+1) / 2;
+}
+
+// Computes success chance for MR-checking spells and abilities.
+static double _success_chance(const int mr, const int powc)
+{
+    const int target = mr + 100 - powc;
+
+    if (target <= 0)
+        return 1.0;
+    if (target > 200)
+        return 0.0;
+    if (target <= 100)
+        return 1.0 - (double) _triangular_number(target) / (101 * 100);
+    return (double) _triangular_number(201 - target) / (101 * 100);
+}
+
+// Include success chance in targeter for spells checking monster MR.
+vector<string> desc_success_chance(const monster_info& mi, int pow)
+{
+    vector<string> descs;
+    const int mr = mi.res_magic();
+    if (mr == MAG_IMMUNE)
+        descs.push_back("magic immune");
+    else
+        descs.push_back(
+            make_stringf("chance %d%%",
+                (int) (100 * _success_chance(mr, pow))
+            ).c_str());
+    return descs;
+}
+
 /**
  * Targets and fires player-cast spells & spell-like effects.
  *
@@ -1218,6 +1253,14 @@ spret_type your_spells(spell_type spell, int powc,
 
         targetter *hitfunc = _spell_targetter(spell, powc, range);
 
+        // Add success chance to targetted spells checking monster MR
+        const bool mr_check = testbits(flags, SPFLAG_MR_CHECK)
+                              && testbits(flags, SPFLAG_DIR_OR_TARGET)
+                              && !testbits(flags, SPFLAG_HELPFUL);
+        desc_filter additional_desc = NULL;
+        if (mr_check)
+            additional_desc = bind(desc_success_chance, placeholders::_1, powc);
+
         string title = "Aiming: <white>";
         title += spell_title(spell);
         title += "</white>";
@@ -1226,7 +1269,8 @@ spret_type your_spells(spell_type spell, int powc,
                              needs_path, true, dont_cancel_me, prompt,
                              title.c_str(),
                              testbits(flags, SPFLAG_NOT_SELF),
-                             hitfunc))
+                             hitfunc,
+                             additional_desc))
         {
             if (hitfunc)
                 delete hitfunc;
diff --git a/crawl-ref/source/spl-cast.h b/crawl-ref/source/spl-cast.h
index 5a073b4..e9daf2e 100644
--- a/crawl-ref/source/spl-cast.h
+++ b/crawl-ref/source/spl-cast.h
@@ -72,6 +72,7 @@ bool cast_a_spell(bool check_range, spell_type spell = SPELL_NO_SPELL);
 void inspect_spells();
 void do_cast_spell_cmd(bool force);
 
+vector<string> desc_success_chance(const monster_info& mi, int pow);
 spret_type your_spells(spell_type spell, int powc = 0, bool allow_fail = true,
     bool evoked = false);
 
-- 
2.1.3
