Spellcasting Fail Rate Calculator


Questions, Explanations, Howtos

Dungeon Dilettante

Posts: 1

Joined: Thursday, 10th July 2014, 02:47

Post Thursday, 10th July 2014, 03:01

Spellcasting Fail Rate Calculator

So I am making a spell fail rate calculator in excel, but am having trouble with two things: getting the stepdown function to work correctly, and spell fail in general. The calculator is off for spell fail in general, and I believe it is in "spell skills." According to the wiki the code for spellskills is:

spellFailure = 60
- [6 * spell skills]
- [2 * Intelligence]
+ Spell difficulty
+ Armour/shield penalty

Spell skills is, according to the wiki,

spellSkills = [Spellcasting / 2]
+ [Average(SpellSkills) * 2]

I do not think that is the real code, because I believe all other parts of the calculator (except stepdown) are working. I believe the problem lies here due to this early error, for example: No boosts, no wizardry, 12 spellcasting 14 conjurations casting orb of destruction should have a 10% spell fail rate. The calculator gives a fail rate of 4%, using the above code for spellskills.

I do not code normally, so reading the source code is a bit hard for me. Is the real code in game for spell skills what I am using?
User avatar

Dungeon Master

Posts: 762

Joined: Thursday, 25th April 2013, 02:43

Post Thursday, 10th July 2014, 04:23

Re: Spellcasting Fail Rate Calculator

Echolus wrote:According to the wiki
The wiki is a terrible, terrible, place to get your information, most pages are wrong or outdated in some way. The spell success page I found doesn't even claim to be more recent than 0.10, which is before I even started playing. (As an example off the top of my head: I know the details of Wizardry have changed some time in the last couple versions)

Spell success code is mostly legacy, particularly stepdowns, so I would not be surprised if figuring out how Crawl actually calculates success chance is nigh impossible. If you want to try, the best way to do it is to source dive. I believe lines 1347-1401 of spl-cast.cc would be the best place to start as the entry point to the code which calculates the fail chance, but I might be misreading that bit of code. The best way to browse the source code is to download it from the git repository (instructions in INSTALL.txt) and use and IDE/code viewing tool, but since you "do not code normally" you probably want to use a web interface, such this one.
On IRC my nick is reaverb. I play online under the name reaver, though.
User avatar

Pandemonium Purger

Posts: 1298

Joined: Wednesday, 11th April 2012, 02:42

Location: Sydney, Australia

Post Thursday, 10th July 2014, 06:10

Re: Spellcasting Fail Rate Calculator

If spellcasting failure is anything like ability failure, then it doesn't use the raw failure rate, but actually a tetrahedral number calculation based on it, because it rolls multiples times instead of just once against the 'raw failure rate' (thx to duvessa for initially tipping me off to the existence of this mechanism)

Code isn't hard to read. Just download the source code, download notepad++, set ctrl+shift+f to use the crawl source, and whenever you see an interesting term use ctrl+shift+f to find all instances of it in the codebase and investigate further, while keeping notes on what you've found so far so you don't get stuck in an infinite loop of stuff being pushed into/out of your brain's relatively small working memory.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Monday, 21st July 2014, 02:21

Re: Spellcasting Fail Rate Calculator

I've been doing this independently! This is the first I've seen this thread. I just happened to have been working on this exact problem today, myself, oddly enough, and the dual breakpoint sieve thingy has me in a tizzy. I thought the MP calculation that I hammered out first was arcane. This is something else.

look in spl-data.h, spl-util.cc, and spl-cast.cc. Support functions reside in stuff.cc, asg.cc and random.cc. This is all I know so far.

Basically, I'm creating a spreadsheet in Excel that mimics the character screen, with stats, level and skills editable, and the rest calculated to appear exactly as it would in-game. When you type in the spell names you have memorized, pre-coded adjacent cells light up with all the relevant information for that spell, based on the character data (lookup tables). I have a rudimentary working version of this, but they didn't make it simple, that's for sure. Much more code diving is going to be required to get it done.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Friday, 25th July 2014, 17:51

Re: Spellcasting Fail Rate Calculator

reaver wrote:you probably want to use a web interface, such this one.

This is much nicer than the gitorious crawl-ref interface (faster to load). Is this always showing the most recent code state?

I still cannot get fail calc to work properly.

I have accurate power bars and hunger readings, but my fail calc is fail.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Friday, 25th July 2014, 23:07

Re: Spellcasting Fail Rate Calculator

Here's what I have, so far. This is my rendering of pseudocode for spell_fail() in spl-cast.cc.
  Code:
chance initializes at 60
6 * calculated spell power is subtracted
2 * intelligence is subtracted
[I skip armor adjustments.]
a discrete value from a table ranging from 3 to 750 based on spell level is added
[I skip djinn adjustments.]
a discrete value from another table ranging from 0 to 45 replaces any value less than 45
the result is capped at 100

Calculated spell power I have proceeding as follows. This is also from spl-cast.cc.
  Code:
start with the average of (each relevant spells school's trained value * 2)
one-half of spellcasting is added
[I skip boosts, enhancers, mutations and augmentations.]
stepdown the power value using a specific function, capping it at 200
cap it again to the max power listed in spl-data.h

After all this is said and done, I appear to have a working spell power calculation but not a working spell failure calculation. I'm making at least one if not several assumptions that might not be correct. The first is that the code:

  Code:
you.skill(SK_SPELLCASTING, 50)

means one-half the trained skill in spellcasting, and that

  Code:
you.skill(spell_type2skill(bit), 200)

means twice the trained skill in the relevant spell school.

Am I on the right track, here?

Crypt Cleanser

Posts: 720

Joined: Friday, 6th September 2013, 09:17

Post Friday, 25th July 2014, 23:23

Re: Spellcasting Fail Rate Calculator

spell_fail function is not all you need, look at the failure_rate_to_int function. In particular, you have to apply the part from _get_true_fail_rate.

For this message the author stickyfingers has received thanks:
Aule

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Saturday, 26th July 2014, 01:16

Re: Spellcasting Fail Rate Calculator

Thank you. I do have those in my converted code blocks, including the tetrahedral number function.

I'm going to keep working on this. Do you have a working copy of the routine? If so, could you generate a table of results with various starting params that I can compare with to help debug my code?

Here's what I get for _get_true_fail_rate(n) with rounded percentage results:

  Code:
n   get_true_fail_rate(n)
1   0%
2   0%
3   0%
4   0%
5   0%
6   0%
7   0%
8   0%
9   0%
10   0%
11   1%
12   1%
13   1%
14   1%
15   2%
16   2%
17   2%
18   3%
19   3%
20   4%
21   4%
22   5%
23   6%
24   6%
25   7%
26   8%
27   9%
28   10%
29   11%
30   12%
31   14%
32   15%
33   16%
34   18%
35   19%
36   21%
37   23%
38   25%
39   27%
40   29%
41   31%
42   33%
43   35%
44   37%
45   39%
46   41%
47   43%
48   46%
49   48%
50   50%
51   52%
52   54%
53   57%
54   59%
55   61%
56   63%
57   65%
58   67%
59   69%
60   71%
61   73%
62   75%
63   77%
64   79%
65   81%
66   82%
67   84%
68   85%
69   86%
70   88%
71   89%
72   90%
73   91%
74   92%
75   93%
76   94%
77   94%
78   95%
79   96%
80   96%
81   97%
82   97%
83   98%
84   98%
85   98%
86   99%
87   99%
88   99%
89   99%
90   100%
91   100%
92   100%
93   100%
94   100%
95   100%
96   100%
97   100%
98   100%
99   100%
100   100%

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Saturday, 26th July 2014, 01:48

Re: Spellcasting Fail Rate Calculator

Maybe I actually have this working and I don't know it. Here's a table that I was referring to. Assuming the spell of Airstrike, level 4, power cap 200, single-school of Air Magic with only 1 skill point, the table's row indices are spellcasting points, and the column indices are int points. It actually looks reasonable. Hmmm... If so, then my problem is in my spreadsheet implementation using the function.

  Code:
      3      6      9     12     15     18     21     24     27     30
 0  109.0  106.0  100.0  100.0   97.0   88.0   79.0   54.0   41.0   29.0
 1  109.0  103.0  100.0   99.0   94.0   88.0   67.0   41.0   29.0   21.0
 2  109.0  103.0  100.0   97.0   94.0   79.0   54.0   35.0   25.0   18.0
 3  109.0  103.0  100.0   97.0   88.0   67.0   41.0   29.0   21.0   15.0
 4  109.0  103.0   99.0   94.0   79.0   54.0   35.0   21.0   15.0    0.0
 5  109.0  100.0   99.0   94.0   67.0   41.0   29.0   18.0   12.0    0.0
 6  106.0  100.0   99.0   88.0   54.0   35.0   25.0   15.0    0.0    0.0
 7  106.0  100.0   97.0   79.0   54.0   29.0   18.0   12.0    0.0    0.0
 8  106.0  100.0   97.0   79.0   41.0   25.0   15.0    0.0    0.0    0.0
 9  106.0  100.0   94.0   67.0   35.0   21.0   12.0    0.0    0.0    0.0
10  106.0  100.0   94.0   67.0   35.0   18.0    0.0    0.0    0.0    0.0
11  106.0  100.0   88.0   54.0   29.0   15.0    0.0    0.0    0.0    0.0
12  106.0   99.0   88.0   41.0   25.0   15.0    0.0    0.0    0.0    0.0
13  103.0   99.0   79.0   41.0   21.0   12.0    0.0    0.0    0.0    0.0
14  103.0   99.0   79.0   35.0   18.0    0.0    0.0    0.0    0.0    0.0
15  103.0   97.0   67.0   35.0   18.0    0.0    0.0    0.0    0.0    0.0
16  103.0   97.0   67.0   29.0   15.0    0.0    0.0    0.0    0.0    0.0
17  103.0   97.0   67.0   25.0   12.0    0.0    0.0    0.0    0.0    0.0
18  103.0   94.0   54.0   25.0   12.0    0.0    0.0    0.0    0.0    0.0
19  103.0   94.0   54.0   21.0    0.0    0.0    0.0    0.0    0.0    0.0
20  100.0   94.0   41.0   21.0    0.0    0.0    0.0    0.0    0.0    0.0
21  100.0   88.0   41.0   18.0    0.0    0.0    0.0    0.0    0.0    0.0
22  100.0   88.0   35.0   15.0    0.0    0.0    0.0    0.0    0.0    0.0
23  100.0   88.0   35.0   15.0    0.0    0.0    0.0    0.0    0.0    0.0
24  100.0   88.0   29.0   12.0    0.0    0.0    0.0    0.0    0.0    0.0
25  100.0   79.0   29.0   12.0    0.0    0.0    0.0    0.0    0.0    0.0
26  100.0   79.0   25.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
27  100.0   79.0   25.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0

Crypt Cleanser

Posts: 720

Joined: Friday, 6th September 2013, 09:17

Post Saturday, 26th July 2014, 09:16

Re: Spellcasting Fail Rate Calculator

Aule wrote:Thank you. I do have those in my converted code blocks, including the tetrahedral number function.

I'm going to keep working on this. Do you have a working copy of the routine? If so, could you generate a table of results with various starting params that I can compare with to help debug my code?

All I have is the crawl source :)

Here's what I get for _get_true_fail_rate(n) with rounded percentage results:

Looks good.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Saturday, 26th July 2014, 16:19

Re: Spellcasting Fail Rate Calculator

stickyfingers wrote:Looks good.

Yep, it's real purty, although completely inaccurate. :( Good thing I have plenty of hair to pull out.

Lair Larrikin

Posts: 25

Joined: Saturday, 26th July 2014, 22:01

Post Tuesday, 29th July 2014, 00:17

Re: Spellcasting Fail Rate Calculator

Do you still need this table?

Level 4 spell with one level in skill.
All of the values I checked in wizmode were correct (not all of the values from the table).

I also compiled all of the relevant source code into one file, that I used to create the table, but it's a bit of a mess, use it with caution.

The table:
  Code:
SP> 5 6  7  8  9  10 11 12 13 14 15 16 17 18 19
Int V
5  99 99 99 98 98 95 95 89 89 82 82 71 71 58 58
6  99 99 99 97 97 93 93 87 87 78 78 67 67 54 54
7  99 98 98 96 96 91 91 85 85 75 75 63 63 50 50
8  99 98 98 95 95 89 89 82 82 71 71 58 58 45 45
9  99 97 97 93 93 87 87 78 78 67 67 54 54 41 41
10 98 96 96 91 91 85 85 75 75 63 63 50 50 38 38
11 98 95 95 89 89 82 82 71 71 58 58 45 45 38 38
12 97 93 93 87 87 78 78 67 67 54 54 41 41 34 34
13 96 91 91 85 85 75 75 63 63 50 50 38 38 34 34
14 95 89 89 82 82 71 71 58 58 45 45 38 38 30 30
15 93 87 87 78 78 67 67 54 54 41 41 34 34 28 28
16 91 85 85 75 75 63 63 50 50 38 38 34 34 28 28
17 89 82 82 71 71 58 58 45 45 38 38 30 30 24 24
18 87 78 78 67 67 54 54 41 41 34 34 28 28 24 24
19 85 75 75 63 63 50 50 38 38 34 34 28 28 21 21


Source:
  Code:
#include <stdio.h>

#include <cstdarg>
#include <sstream>
#include <iomanip>
#include <algorithm>

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#include <map>

template < class T >
static inline void UNUSED(const volatile T &)
{
}


enum rounding_type
{
    ROUND_DOWN,
    ROUND_CLOSE,
    ROUND_RANDOM
};


int spell_fail(int spell_lvl,int intel,int skill,int spell_cast);
char* failure_rate_to_string(int fail);
int calc_spell_power(int skill,int spell_cast);
int stepdown_value(int base_value, int stepping, int first_step,
                   int last_step, int ceiling_value);
double stepdown(double value, double step);
static int _tetrahedral_number(int n);
static double _get_true_fail_rate(int raw_fail);
double random_real();
int min(int a,int b);
int max(int a,int b);

int main(){
   FILE* table=fopen("table","w");
   srand(time(0));
   int i,j;
   j=5;
   fprintf(table,"Spell Casting:");
   for(i=5;i<20;i++){
      fprintf(table,"%d ",i);
   }
   fprintf(table,"\n");

   fprintf(table,"Intelligence V\n");
   for(i=5;i<20;i++){
      fprintf(table,"%d ",i);
      for(j=5;j<20;j++){
           fprintf(table,failure_rate_to_string(spell_fail(4,i,1,j)));
         fprintf(table," ");
      }
      fprintf(table,"\n");
   }
}

//spell_lvl- the level of the spell
//intel-intelligence
//skill- skill level, compute it if you want more than one school
//spell_cast- spell casting skill level

int spell_fail(int spell_lvl,int intel,int skill,int spell_cast)
{
    int chance = 60;

    // Don't cap power for failure rate purposes.
    chance -= 6 * calc_spell_power(skill,spell_cast);
    chance -= (intel * 2);

//    const int armour_shield_penalty = player_armour_shield_spell_penalty();
//   dprf("Armour+Shield spell failure penalty: %d", armour_shield_penalty);
//  chance += armour_shield_penalty;

    switch (spell_lvl)
    {
    case  1: chance +=   3; break;
    case  2: chance +=  15; break;
    case  3: chance +=  35; break;
    case  4: chance +=  70; break;
    case  5: chance += 100; break;
    case  6: chance += 150; break;
    case  7: chance += 200; break;
    case  8: chance += 260; break;
    case  9: chance += 330; break;
    case 10: chance += 420; break;
    case 11: chance += 500; break;
    case 12: chance += 600; break;
    default: chance += 750; break;
    }

    int chance2 = chance;

    const int chance_breaks[][2] =
    {
        {45, 45}, {42, 43}, {38, 41}, {35, 40}, {32, 38}, {28, 36},
        {22, 34}, {16, 32}, {10, 30}, {2, 28}, {-7, 26}, {-12, 24},
        {-18, 22}, {-24, 20}, {-30, 18}, {-38, 16}, {-46, 14},
        {-60, 12}, {-80, 10}, {-100, 8}, {-120, 6}, {-140, 4},
        {-160, 2}, {-180, 0}
    };

//    for (unsigned int i = 0; i < ARRAYSZ(chance_breaks); ++i)
      for(unsigned int i=0;i<24;++i)
        if (chance < chance_breaks[i][0])
            chance2 = chance_breaks[i][1];




    if (chance2 > 100)
        chance2 = 100;

    return chance2;
}

//apply intel false
//fail rate check true
//cap_power false
int calc_spell_power(int skill,int spell_cast)
{
    int power = 0;
        int enhanced = 0;

     //   unsigned int disciplines = get_spell_disciplines(spell);

      //  int skillcount = count_bits(disciplines);

      //This counts total skill points / all skill schools involved i guess
/*        if (skillcount)
        {
            for (int ndx = 0; ndx <= SPTYP_LAST_EXPONENT; ndx++)
            {
                unsigned int bit = (1 << ndx);
                if (disciplines & bit)
                    power += you.skill(spell_type2skill(bit), 200);
            }
            power /= skillcount;
        }*/
      power+=skill*200;

        power += spell_cast*50;

        // Brilliance boosts spell power a bit (equivalent to three
        // spell school levels).
//        if (!fail_rate_check && you.duration[DUR_BRILLIANCE])
 //           power += 600;

  //      if (apply_intel)
   //         power = (power * you.intel()) / 10;

        // [dshaligram] Enhancers don't affect fail rates any more, only spell
        // power. Note that this does not affect Vehumet's boost in castability.
  //      if (!fail_rate_check)
  //         enhanced = _spell_enhancement(disciplines);

    /*    if (enhanced > 0)
        {
            for (int i = 0; i < enhanced; i++)
            {
                power *= 15;
                power /= 10;
            }
        }
        else if (enhanced < 0)
        {
            for (int i = enhanced; i < 0; i++)
                power /= 2;
        }*/

        // Wild magic boosts spell power but decreases success rate.
  //      if (!fail_rate_check)
   //     {
    //        power *= 10 + 5 * player_mutation_level(MUT_WILD_MAGIC);
     //       power /= 10;
      //  }

        // Augmentation boosts spell power at high HP.
       /* if (!fail_rate_check)
        {
            power *= 10 + 4 * augmentation_amount();
            power /= 10;
        }*/

        power = stepdown_value(power / 100, 50, 50, 150, 200);
   

 //   const int cap = spell_power_cap(spell);
//    if (cap > 0 && cap_power)
 //       power = min(power, cap);

    return power;
}

int stepdown(int value, int step, rounding_type rounding, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    // Randomised rounding
    if (rounding == ROUND_RANDOM)
    {
        double intpart;
        double fracpart = modf(ret, &intpart);
        if (random_real() < fracpart)
            ++intpart;
        return intpart;
    }

    return ret + (rounding == ROUND_CLOSE ? 0.5 : 0);
}

// Deprecated definition. Call directly stepdown instead.
int stepdown_value(int base_value, int stepping, int first_step,
                   int last_step, int ceiling_value)
{
    UNUSED(last_step);

    // Disabling max used to be -1.
    if (ceiling_value < 0)
        ceiling_value = 0;

    if (ceiling_value && ceiling_value < first_step)
        return min(base_value, ceiling_value);
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping, ROUND_DOWN,
                           ceiling_value ? ceiling_value - diff : 0);
}

int failure_rate_to_int(int fail)
{
    if (fail <= 0)
        return 0;
    else if (fail >= 100)
        return (fail + 100)/2;
    else
        return max(1, (int) (100 * _get_true_fail_rate(fail)));
}

char* failure_rate_to_string(int fail)
{
    char *buffer = (char *)malloc(9);
    sprintf(buffer, "%d%%", failure_rate_to_int(fail));
    return buffer;
}

static double _get_true_fail_rate(int raw_fail)
{
    //Need random2(101) + random2(101) + random2(100) to be less than 3*raw_fail.
    //Fun with tetrahedral numbers!

    int target = raw_fail * 3;

    if (target <= 100)
        return (double) _tetrahedral_number(target)/1020100;
    if (target <= 200)
    {
        //PIE: the negative term takes the maximum of 100 (or 99) into
        //consideration.  Note that only one term can exceed it in this case,
        //which is why this works.
        return (double) (_tetrahedral_number(target)
                         - 2*_tetrahedral_number(target - 101)
                         - _tetrahedral_number(target - 100)) / 1020100;
    }
    //The random2avg distribution is symmetric, so the last interval is
    //essentially the same as the first interval.
    return (double) (1020100 - _tetrahedral_number(300 - target)) / 1020100;
}

static int _tetrahedral_number(int n)
{
    return n * (n+1) * (n+2) / 6;
}

double stepdown(double value, double step)
{
    return step * log2(1 + value / step);
}

double random_real()
{
   unsigned int rnd=rand();
    return rnd / 4294967296.0;
}
int max(int a,int b){
   if(a>b){
      return a;
   }else{
      return b;
   }
}
int min(int a,int b){
   if(a<b){
       return a;
   }else{
       return b;
   }      
}

For this message the author lrvs has received thanks:
Aule

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Tuesday, 29th July 2014, 02:22

Re: Spellcasting Fail Rate Calculator

That is excellent! Yes, indeed, thank you very much!

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Tuesday, 29th July 2014, 02:36

Re: Spellcasting Fail Rate Calculator

  Code:
      power+=skill*200;
      power += spell_cast*50;

I see my assumption was way off. I couldn't find the you.skill() method to determine what the numbers actually meant, and i see you got rid of it altogether. I was looking at the wiki formula,
  Code:
((Spellcasting / 2) + (2 * [average_spell_schools]) ...) ...

and just went on the assumption that the function parameter was a percentage value, since it was a black box to me.

I should be able to get this working in vb. You really did a lot, and I'm thankful.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Tuesday, 29th July 2014, 23:47

Re: Spellcasting Fail Rate Calculator

Well, I can't get it to produce the same results in VB, so I wanted to just compile it in C to start with just so I can debug my code function by function. I am using MinGW, and I can compile a hello_world just fine, so I know the compiler works (all of them), but when I try to compile your code block I get this message:
  Code:
[tmp_path].o:spell_code.cc:(.eh_frame+0x4b): undefined reference to `___gxx_personality_v0'
collect2.exe: error: ld returned 1 exit status

If I try removing references, I get nowhere.

I'm also confused as to how the spell power calc without intel gets the right numbers. Did intel drop from that calculation?

There should be one module for spell calc stuff, called spl-calc.cc. If I knew enough about this stuff, I'd do it, but clearly I'm lacking. I just want to get one working. I do know the fundamentals of coding in various languages, but it's just not enough, evidently.

Thanks for any continued thought and effort on this. What did you compile yours with?

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Wednesday, 30th July 2014, 03:54

Re: Spellcasting Fail Rate Calculator

Okay, this is just bizarre. This code works, compiles, and executes just dandy:
  Code:
#include <stdio.h>
#include <math.h>

int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap);
int stepdown_value(int base_value, int stepping, int first_step, int ceiling_value);
int stepdown(int value, int step, int max);
double stepdown(double value, double stepping);

int main()
{
   int i, j;
   FILE* table = fopen("power_table.txt","w");

   fprintf(table, "\t");
   for(i = 1; i < 27; i++)
   {
      fprintf(table, "%d\t", i);
   }
   fprintf(table, "\n");

   for(i = 1; i < 27; i++)
   {
      fprintf(table, "%d\t", i);
      for (j = 1; j <= 27; j++)
         fprintf(table, "%d\t", calc_spell_power(i, j, 1, -1, -1, true, 200));
      fprintf(table, "\n");
   }
}

int calc_spell_power(int intel, double scast,
                  double sch1, double sch2, double sch3,
                  bool apply_intel, int pcap)
{
    int power = 0;

   if (sch3 == -1 && sch2 == -1)
      power += ((sch1 + sch2 + sch3) / 3) * 200;
   else if (sch3 == -1)
      power += ((sch1 + sch2) / 2) * 200;
   else
      power += sch1 * 200;

   power += scast * 50;
   if (apply_intel)
      power = (power * intel) / 10;
   power = stepdown_value(power / 100, 50, 50, 200);

   // Cap the power.
    if (pcap > 0)
      if (power > pcap)
         power = pcap;

    return power;
}

int stepdown_value(int base_value, int stepping, int first_step,
                   int ceiling_value)
{
    if (ceiling_value && ceiling_value < first_step)
      if (base_value > ceiling_value)
         return ceiling_value;
      else
         return base_value;
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping,
                           ceiling_value ? ceiling_value - diff : 0);
}

double stepdown(double value, double stepping)
{
    return stepping * log2(1 + value / stepping);
}

int stepdown(int value, int step, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    return ret;
}

That's everything except the spell_fail() function.

Adding only this:
  Code:
int spell_fail(int dlev, int intel, double scast, double sch1, double sch2, double sch3)
{
    int chance = 60;

    // Don't cap power or apply intel for failure rate purposes.
    chance -= 6 * calc_spell_power(intel, scast, sch1, sch2, sch3, false, 0);
    chance -= intel * 2;

    switch (dlev)
    {
    case  1: chance +=   3; break;
    case  2: chance +=  15; break;
    case  3: chance +=  35; break;
    case  4: chance +=  70; break;
    case  5: chance += 100; break;
    case  6: chance += 150; break;
    case  7: chance += 200; break;
    case  8: chance += 260; break;
    case  9: chance += 330; break;
    case 10: chance += 420; break;
    case 11: chance += 500; break;
    case 12: chance += 600; break;
    default: chance += 750; break;
    }

    int chance2 = chance;

    const int chance_breaks[][2] =
    {
        {45, 45}, {42, 43}, {38, 41}, {35, 40}, {32, 38}, {28, 36},
        {22, 34}, {16, 32}, {10, 30}, {2, 28}, {-7, 26}, {-12, 24},
        {-18, 22}, {-24, 20}, {-30, 18}, {-38, 16}, {-46, 14},
        {-60, 12}, {-80, 10}, {-100, 8}, {-120, 6}, {-140, 4},
        {-160, 2}, {-180, 0}
    };

    for (unsigned int i = 0; i < 24; ++i)
        if (chance < chance_breaks[i][0])
            chance2 = chance_breaks[i][1];

    if (chance2 > 100)
        chance2 = 100;

    return chance2;
}

breaks it, giving me that ridiculous error message when I try to compile. It makes zero sense, but at least I'm making some headway.
User avatar

Pandemonium Purger

Posts: 1298

Joined: Wednesday, 11th April 2012, 02:42

Location: Sydney, Australia

Post Wednesday, 30th July 2014, 04:07

Re: Spellcasting Fail Rate Calculator

Did you try Ye Olde Google Search For Error Message (praying to god that someone else had the same problem as you)?
https://www.google.com.au/search?q=___g ... 0&ie=UTF-8
It looks promising.

For this message the author Patashu has received thanks:
Aule

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Wednesday, 30th July 2014, 04:19

Re: Spellcasting Fail Rate Calculator

well, I'll be... TYVM. My googling led to different answers in different places involving complex option settings for proprietary development programs, very little of which I understood. [sigh]

Just using the g++ compiler works great. :) Spellcasting across top, int down the left side:
  Code:
     1   2   3   4   5   6   7   8   9  10  11  12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
1  100 100 100 100 100 100 100 100 100 100 100  98 98 92 92 86 86 80 80 74 74 68 68 62 62 56 56
2  100 100 100 100 100 100 100 100 100 100 100  96 96 90 90 84 84 78 78 72 72 66 66 60 60 54 54
3  100 100 100 100 100 100 100 100 100 100 100  94 94 88 88 82 82 76 76 70 70 64 64 58 58 52 52
4  100 100 100 100 100 100 100 100 100  98  98  92 92 86 86 80 80 74 74 68 68 62 62 56 56 50 50
5  100 100 100 100 100 100 100 100 100  96  96  90 90 84 84 78 78 72 72 66 66 60 60 54 54 48 48
6  100 100 100 100 100 100 100 100 100  94  94  88 88 82 82 76 76 70 70 64 64 58 58 52 52 46 46
7  100 100 100 100 100 100 100  98  98  92  92  86 86 80 80 74 74 68 68 62 62 56 56 50 50 45 45
8  100 100 100 100 100 100 100  96  96  90  90  84 84 78 78 72 72 66 66 60 60 54 54 48 48 45 45
9  100 100 100 100 100 100 100  94  94  88  88  82 82 76 76 70 70 64 64 58 58 52 52 46 46 43 43
10 100 100 100 100 100  98  98  92  92  86  86  80 80 74 74 68 68 62 62 56 56 50 50 45 45 43 43
11 100 100 100 100 100  96  96  90  90  84  84  78 78 72 72 66 66 60 60 54 54 48 48 45 45 41 41
12 100 100 100 100 100  94  94  88  88  82  82  76 76 70 70 64 64 58 58 52 52 46 46 43 43 40 40
13 100 100 100  98  98  92  92  86  86  80  80  74 74 68 68 62 62 56 56 50 50 45 45 43 43 40 40
14 100 100 100  96  96  90  90  84  84  78  78  72 72 66 66 60 60 54 54 48 48 45 45 41 41 38 38
15 100 100 100  94  94  88  88  82  82  76  76  70 70 64 64 58 58 52 52 46 46 43 43 40 40 38 38
16  98  98  98  92  92  86  86  80  80  74  74  68 68 62 62 56 56 50 50 45 45 43 43 40 40 36 36
17  96  96  96  90  90  84  84  78  78  72  72  66 66 60 60 54 54 48 48 45 45 41 41 38 38 36 36
18  94  94  94  88  88  82  82  76  76  70  70  64 64 58 58 52 52 46 46 43 43 40 40 38 38 36 36
19  92  92  92  86  86  80  80  74  74  68  68  62 62 56 56 50 50 45 45 43 43 40 40 36 36 34 34
20  90  90  90  84  84  78  78  72  72  66  66  60 60 54 54 48 48 45 45 41 41 38 38 36 36 34 34
21  88  88  88  82  82  76  76  70  70  64  64  58 58 52 52 46 46 43 43 40 40 38 38 36 36 34 34
22  86  86  86  80  80  74  74  68  68  62  62  56 56 50 50 45 45 43 43 40 40 36 36 34 34 32 32
23  84  84  84  78  78  72  72  66  66  60  60  54 54 48 48 45 45 41 41 38 38 36 36 34 34 32 32
24  82  82  82  76  76  70  70  64  64  58  58  52 52 46 46 43 43 40 40 38 38 36 36 34 34 32 32
25  80  80  80  74  74  68  68  62  62  56  56  50 50 45 45 43 43 40 40 36 36 34 34 32 32 30 30
26  78  78  78  72  72  66  66  60  60  54  54  48 48 45 45 41 41 38 38 36 36 34 34 32 32 30 30
27  76  76  76  70  70  64  64  58  58  52  52  46 46 43 43 40 40 38 38 36 36 34 34 32 32 30 30


with this code:
  Code:
#include <stdio.h>
#include <math.h>

int spell_fail(int dlev, int intel, double scast, double sch1, double sch2, double sch3);
int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap);
int stepdown_value(int base_value, int stepping, int first_step, int ceiling_value);
int stepdown(int value, int step, int max);
double stepdown(double value, double stepping);

int main()
{
   int i, j;
   FILE* table = fopen("fail_table.txt","w");

   fprintf(table, "\t");
   for(i = 1; i <= 27; i++)
   {
      fprintf(table, "%d\t", i);
   }
   fprintf(table, "\n");

   for(i = 1; i <= 27; i++)
   {
      fprintf(table, "%d\t", i);
      for (j = 1; j <= 27; j++)
         fprintf(table, "%d\t", spell_fail(4, i, j, 1, -1, -1));
      fprintf(table, "\n");
   }
}

int spell_fail(int dlev, int intel, double scast, double sch1, double sch2, double sch3)
{
    int chance = 60;

    // Don't cap power or apply intel for failure rate purposes.
    chance -= 6 * calc_spell_power(intel, scast, sch1, sch2, sch3, false, 0);
    chance -= intel * 2;

    switch (dlev)
    {
    case  1: chance +=   3; break;
    case  2: chance +=  15; break;
    case  3: chance +=  35; break;
    case  4: chance +=  70; break;
    case  5: chance += 100; break;
    case  6: chance += 150; break;
    case  7: chance += 200; break;
    case  8: chance += 260; break;
    case  9: chance += 330; break;
    case 10: chance += 420; break;
    case 11: chance += 500; break;
    case 12: chance += 600; break;
    default: chance += 750; break;
    }

    int chance2 = chance;

    const int chance_breaks[][2] =
    {
        {45, 45}, {42, 43}, {38, 41}, {35, 40}, {32, 38}, {28, 36},
        {22, 34}, {16, 32}, {10, 30}, {2, 28}, {-7, 26}, {-12, 24},
        {-18, 22}, {-24, 20}, {-30, 18}, {-38, 16}, {-46, 14},
        {-60, 12}, {-80, 10}, {-100, 8}, {-120, 6}, {-140, 4},
        {-160, 2}, {-180, 0}
    };

    for (unsigned int i = 0; i < 24; ++i)
        if (chance < chance_breaks[i][0])
            chance2 = chance_breaks[i][1];

    if (chance2 > 100)
        chance2 = 100;

    return chance2;
}

int calc_spell_power(int intel, double scast,
                  double sch1, double sch2, double sch3,
                  bool apply_intel, int pcap)
{
    int power = 0;

   if (sch3 == -1 && sch2 == -1)
      power += ((sch1 + sch2 + sch3) / 3) * 200;
   else if (sch3 == -1)
      power += ((sch1 + sch2) / 2) * 200;
   else
      power += sch1 * 200;

   power += scast * 50;
   if (apply_intel)
      power = (power * intel) / 10;
   power = stepdown_value(power / 100, 50, 50, 200);

   // Cap the power.
    if (pcap > 0)
      if (power > pcap)
         power = pcap;

    return power;
}

int stepdown_value(int base_value, int stepping, int first_step,
                   int ceiling_value)
{
    if (ceiling_value && ceiling_value < first_step)
      if (base_value > ceiling_value)
         return ceiling_value;
      else
         return base_value;
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping,
                           ceiling_value ? ceiling_value - diff : 0);
}

double stepdown(double value, double stepping)
{
    return stepping * log2(1 + value / stepping);
}

int stepdown(int value, int step, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    return ret;
}

But it still doesn't match Irvs. :/

[Edit: Bah, I was ordering for school level 1 instead of 4, but even the table with the same data is different. Must. Get. It.]
  Code:
Airstrike Spell: Difficulty Level = 4
Air Magic school skill training = 4.0
Spellcasting > | Intelligence V

     0   1   2   3   4   5   6   7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
1  100 100 100 100 100 100 100 100 98 98 92 92 86 86 80 80 74 74 68 68 62 62 56 56 50 50 45 45
2  100 100 100 100 100 100 100 100 96 96 90 90 84 84 78 78 72 72 66 66 60 60 54 54 48 48 45 45
3  100 100 100 100 100 100 100 100 94 94 88 88 82 82 76 76 70 70 64 64 58 58 52 52 46 46 43 43
4  100 100 100 100 100 100  98  98 92 92 86 86 80 80 74 74 68 68 62 62 56 56 50 50 45 45 43 43
5  100 100 100 100 100 100  96  96 90 90 84 84 78 78 72 72 66 66 60 60 54 54 48 48 45 45 41 41
6  100 100 100 100 100 100  94  94 88 88 82 82 76 76 70 70 64 64 58 58 52 52 46 46 43 43 40 40
7  100 100 100 100  98  98  92  92 86 86 80 80 74 74 68 68 62 62 56 56 50 50 45 45 43 43 40 40
8  100 100 100 100  96  96  90  90 84 84 78 78 72 72 66 66 60 60 54 54 48 48 45 45 41 41 38 38
9  100 100 100 100  94  94  88  88 82 82 76 76 70 70 64 64 58 58 52 52 46 46 43 43 40 40 38 38
10 100 100  98  98  92  92  86  86 80 80 74 74 68 68 62 62 56 56 50 50 45 45 43 43 40 40 36 36
11 100 100  96  96  90  90  84  84 78 78 72 72 66 66 60 60 54 54 48 48 45 45 41 41 38 38 36 36
12 100 100  94  94  88  88  82  82 76 76 70 70 64 64 58 58 52 52 46 46 43 43 40 40 38 38 36 36
13  98  98  92  92  86  86  80  80 74 74 68 68 62 62 56 56 50 50 45 45 43 43 40 40 36 36 34 34
14  96  96  90  90  84  84  78  78 72 72 66 66 60 60 54 54 48 48 45 45 41 41 38 38 36 36 34 34
15  94  94  88  88  82  82  76  76 70 70 64 64 58 58 52 52 46 46 43 43 40 40 38 38 36 36 34 34
16  92  92  86  86  80  80  74  74 68 68 62 62 56 56 50 50 45 45 43 43 40 40 36 36 34 34 32 32
17  90  90  84  84  78  78  72  72 66 66 60 60 54 54 48 48 45 45 41 41 38 38 36 36 34 34 32 32
18  88  88  82  82  76  76  70  70 64 64 58 58 52 52 46 46 43 43 40 40 38 38 36 36 34 34 32 32
19  86  86  80  80  74  74  68  68 62 62 56 56 50 50 45 45 43 43 40 40 36 36 34 34 32 32 30 30
20  84  84  78  78  72  72  66  66 60 60 54 54 48 48 45 45 41 41 38 38 36 36 34 34 32 32 30 30
21  82  82  76  76  70  70  64  64 58 58 52 52 46 46 43 43 40 40 38 38 36 36 34 34 32 32 30 30
22  80  80  74  74  68  68  62  62 56 56 50 50 45 45 43 43 40 40 36 36 34 34 32 32 30 30 30 30
23  78  78  72  72  66  66  60  60 54 54 48 48 45 45 41 41 38 38 36 36 34 34 32 32 30 30 28 28
24  76  76  70  70  64  64  58  58 52 52 46 46 43 43 40 40 38 38 36 36 34 34 32 32 30 30 28 28
25  74  74  68  68  62  62  56  56 50 50 45 45 43 43 40 40 36 36 34 34 32 32 30 30 30 30 28 28
26  72  72  66  66  60  60  54  54 48 48 45 45 41 41 38 38 36 36 34 34 32 32 30 30 28 28 28 28
27  70  70  64  64  58  58  52  52 46 46 43 43 40 40 38 38 36 36 34 34 32 32 30 30 28 28 26 26
28  68  68  62  62  56  56  50  50 45 45 43 43 40 40 36 36 34 34 32 32 30 30 30 30 28 28 26 26
29  66  66  60  60  54  54  48  48 45 45 41 41 38 38 36 36 34 34 32 32 30 30 28 28 28 28 26 26
30  64  64  58  58  52  52  46  46 43 43 40 40 38 38 36 36 34 34 32 32 30 30 28 28 26 26 24 24
31  62  62  56  56  50  50  45  45 43 43 40 40 36 36 34 34 32 32 30 30 30 30 28 28 26 26 24 24
32  60  60  54  54  48  48  45  45 41 41 38 38 36 36 34 34 32 32 30 30 28 28 28 28 26 26 24 24
33  58  58  52  52  46  46  43  43 40 40 38 38 36 36 34 34 32 32 30 30 28 28 26 26 24 24 22 22
34  56  56  50  50  45  45  43  43 40 40 36 36 34 34 32 32 30 30 30 30 28 28 26 26 24 24 22 22
35  54  54  48  48  45  45  41  41 38 38 36 36 34 34 32 32 30 30 28 28 28 28 26 26 24 24 22 22
36  52  52  46  46  43  43  40  40 38 38 36 36 34 34 32 32 30 30 28 28 26 26 24 24 22 22 20 20
37  50  50  45  45  43  43  40  40 36 36 34 34 32 32 30 30 30 30 28 28 26 26 24 24 22 22 20 20
38  48  48  45  45  41  41  38  38 36 36 34 34 32 32 30 30 28 28 28 28 26 26 24 24 22 22 20 20
39  46  46  43  43  40  40  38  38 36 36 34 34 32 32 30 30 28 28 26 26 24 24 22 22 20 20 18 18
40  45  45  43  43  40  40  36  36 34 34 32 32 30 30 30 30 28 28 26 26 24 24 22 22 20 20 18 18

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Wednesday, 30th July 2014, 05:13

Re: Spellcasting Fail Rate Calculator

Okay, starting from scratch: the stepdown function.

I started by knocking it down into this code:
  Code:
#include <stdio.h>
#include <math.h>

int stepdown_value(int base_value, int stepping, int first_step,
                     int ceiling_value);
double stepdown(double value, double stepping);
int stepdown(int value, int step, int max);

int main()
{
   int i;
   FILE* table = fopen("stepdown.txt", "w");

   for (i=1; i<=300; i++)
      fprintf(table, "Input: %d   Output: %d\n", i, stepdown_value(i, 50, 50, 200));
}

int stepdown_value(int base_value, int stepping, int first_step,
                   int ceiling_value)
{
    if (ceiling_value && ceiling_value < first_step)
      if (base_value > ceiling_value)
         return ceiling_value;
      else
         return base_value;
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping,
                           ceiling_value ? ceiling_value - diff : 0);
}

double stepdown(double value, double stepping)
{
    return stepping * log2(1 + value / stepping);
}

int stepdown(int value, int step, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    return ret;
}


And that produces this:
  Code:
Input: 1   Output: 1
Input: 2   Output: 2
Input: 3   Output: 3
Input: 4   Output: 4
Input: 5   Output: 5
Input: 6   Output: 6
Input: 7   Output: 7
Input: 8   Output: 8
Input: 9   Output: 9
Input: 10   Output: 10
Input: 11   Output: 11
Input: 12   Output: 12
Input: 13   Output: 13
Input: 14   Output: 14
Input: 15   Output: 15
Input: 16   Output: 16
Input: 17   Output: 17
Input: 18   Output: 18
Input: 19   Output: 19
Input: 20   Output: 20
Input: 21   Output: 21
Input: 22   Output: 22
Input: 23   Output: 23
Input: 24   Output: 24
Input: 25   Output: 25
Input: 26   Output: 26
Input: 27   Output: 27
Input: 28   Output: 28
Input: 29   Output: 29
Input: 30   Output: 30
Input: 31   Output: 31
Input: 32   Output: 32
Input: 33   Output: 33
Input: 34   Output: 34
Input: 35   Output: 35
Input: 36   Output: 36
Input: 37   Output: 37
Input: 38   Output: 38
Input: 39   Output: 39
Input: 40   Output: 40
Input: 41   Output: 41
Input: 42   Output: 42
Input: 43   Output: 43
Input: 44   Output: 44
Input: 45   Output: 45
Input: 46   Output: 46
Input: 47   Output: 47
Input: 48   Output: 48
Input: 49   Output: 49
Input: 50   Output: 50
Input: 51   Output: 50
Input: 52   Output: 51
Input: 53   Output: 52
Input: 54   Output: 52
Input: 55   Output: 53
Input: 56   Output: 54
Input: 57   Output: 54
Input: 58   Output: 55
Input: 59   Output: 56
Input: 60   Output: 56
Input: 61   Output: 57
Input: 62   Output: 58
Input: 63   Output: 58
Input: 64   Output: 59
Input: 65   Output: 60
Input: 66   Output: 60
Input: 67   Output: 61
Input: 68   Output: 61
Input: 69   Output: 62
Input: 70   Output: 63
Input: 71   Output: 63
Input: 72   Output: 64
Input: 73   Output: 64
Input: 74   Output: 65
Input: 75   Output: 66
Input: 76   Output: 66
Input: 77   Output: 67
Input: 78   Output: 67
Input: 79   Output: 68
Input: 80   Output: 68
Input: 81   Output: 69
Input: 82   Output: 70
Input: 83   Output: 70
Input: 84   Output: 71
Input: 85   Output: 71
Input: 86   Output: 72
Input: 87   Output: 72
Input: 88   Output: 73
Input: 89   Output: 73
Input: 90   Output: 74
Input: 91   Output: 74
Input: 92   Output: 75
Input: 93   Output: 75
Input: 94   Output: 76
Input: 95   Output: 76
Input: 96   Output: 77
Input: 97   Output: 77
Input: 98   Output: 78
Input: 99   Output: 78
Input: 100   Output: 79
Input: 101   Output: 79
Input: 102   Output: 80
Input: 103   Output: 80
Input: 104   Output: 81
Input: 105   Output: 81
Input: 106   Output: 82
Input: 107   Output: 82
Input: 108   Output: 82
Input: 109   Output: 83
Input: 110   Output: 83
Input: 111   Output: 84
Input: 112   Output: 84
Input: 113   Output: 85
Input: 114   Output: 85
Input: 115   Output: 86
Input: 116   Output: 86
Input: 117   Output: 86
Input: 118   Output: 87
Input: 119   Output: 87
Input: 120   Output: 88
Input: 121   Output: 88
Input: 122   Output: 89
Input: 123   Output: 89
Input: 124   Output: 89
Input: 125   Output: 90
Input: 126   Output: 90
Input: 127   Output: 91
Input: 128   Output: 91
Input: 129   Output: 91
Input: 130   Output: 92
Input: 131   Output: 92
Input: 132   Output: 93
Input: 133   Output: 93
Input: 134   Output: 93
Input: 135   Output: 94
Input: 136   Output: 94
Input: 137   Output: 95
Input: 138   Output: 95
Input: 139   Output: 95
Input: 140   Output: 96
Input: 141   Output: 96
Input: 142   Output: 97
Input: 143   Output: 97
Input: 144   Output: 97
Input: 145   Output: 98
Input: 146   Output: 98
Input: 147   Output: 98
Input: 148   Output: 99
Input: 149   Output: 99
Input: 150   Output: 100
Input: 151   Output: 100
Input: 152   Output: 100
Input: 153   Output: 101
Input: 154   Output: 101
Input: 155   Output: 101
Input: 156   Output: 102
Input: 157   Output: 102
Input: 158   Output: 102
Input: 159   Output: 103
Input: 160   Output: 103
Input: 161   Output: 103
Input: 162   Output: 104
Input: 163   Output: 104
Input: 164   Output: 104
Input: 165   Output: 105
Input: 166   Output: 105
Input: 167   Output: 105
Input: 168   Output: 106
Input: 169   Output: 106
Input: 170   Output: 106
Input: 171   Output: 107
Input: 172   Output: 107
Input: 173   Output: 107
Input: 174   Output: 108
Input: 175   Output: 108
Input: 176   Output: 108
Input: 177   Output: 109
Input: 178   Output: 109
Input: 179   Output: 109
Input: 180   Output: 110
Input: 181   Output: 110
Input: 182   Output: 110
Input: 183   Output: 111
Input: 184   Output: 111
Input: 185   Output: 111
Input: 186   Output: 111
Input: 187   Output: 112
Input: 188   Output: 112
Input: 189   Output: 112
Input: 190   Output: 113
Input: 191   Output: 113
Input: 192   Output: 113
Input: 193   Output: 114
Input: 194   Output: 114
Input: 195   Output: 114
Input: 196   Output: 114
Input: 197   Output: 115
Input: 198   Output: 115
Input: 199   Output: 115
Input: 200   Output: 116
Input: 201   Output: 116
Input: 202   Output: 116
Input: 203   Output: 116
Input: 204   Output: 117
Input: 205   Output: 117
Input: 206   Output: 117
Input: 207   Output: 118
Input: 208   Output: 118
Input: 209   Output: 118
Input: 210   Output: 118
Input: 211   Output: 119
Input: 212   Output: 119
Input: 213   Output: 119
Input: 214   Output: 120
Input: 215   Output: 120
Input: 216   Output: 120
Input: 217   Output: 120
Input: 218   Output: 121
Input: 219   Output: 121
Input: 220   Output: 121
Input: 221   Output: 121
Input: 222   Output: 122
Input: 223   Output: 122
Input: 224   Output: 122
Input: 225   Output: 122
Input: 226   Output: 123
Input: 227   Output: 123
Input: 228   Output: 123
Input: 229   Output: 124
Input: 230   Output: 124
Input: 231   Output: 124
Input: 232   Output: 124
Input: 233   Output: 125
Input: 234   Output: 125
Input: 235   Output: 125
Input: 236   Output: 125
Input: 237   Output: 126
Input: 238   Output: 126
Input: 239   Output: 126
Input: 240   Output: 126
Input: 241   Output: 127
Input: 242   Output: 127
Input: 243   Output: 127
Input: 244   Output: 127
Input: 245   Output: 128
Input: 246   Output: 128
Input: 247   Output: 128
Input: 248   Output: 128
Input: 249   Output: 129
Input: 250   Output: 129
Input: 251   Output: 129
Input: 252   Output: 129
Input: 253   Output: 129
Input: 254   Output: 130
Input: 255   Output: 130
Input: 256   Output: 130
Input: 257   Output: 130
Input: 258   Output: 131
Input: 259   Output: 131
Input: 260   Output: 131
Input: 261   Output: 131
Input: 262   Output: 132
Input: 263   Output: 132
Input: 264   Output: 132
Input: 265   Output: 132
Input: 266   Output: 132
Input: 267   Output: 133
Input: 268   Output: 133
Input: 269   Output: 133
Input: 270   Output: 133
Input: 271   Output: 134
Input: 272   Output: 134
Input: 273   Output: 134
Input: 274   Output: 134
Input: 275   Output: 135
Input: 276   Output: 135
Input: 277   Output: 135
Input: 278   Output: 135
Input: 279   Output: 135
Input: 280   Output: 136
Input: 281   Output: 136
Input: 282   Output: 136
Input: 283   Output: 136
Input: 284   Output: 136
Input: 285   Output: 137
Input: 286   Output: 137
Input: 287   Output: 137
Input: 288   Output: 137
Input: 289   Output: 138
Input: 290   Output: 138
Input: 291   Output: 138
Input: 292   Output: 138
Input: 293   Output: 138
Input: 294   Output: 139
Input: 295   Output: 139
Input: 296   Output: 139
Input: 297   Output: 139
Input: 298   Output: 139
Input: 299   Output: 140
Input: 300   Output: 140


If this is not accurate, nothing else will be.

Next, I added calc_spell_power:
  Code:
#include <stdio.h>
#include <math.h>

int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap);
int stepdown_value(int base_value, int stepping, int first_step, int ceiling_value);
int stepdown(int value, int step, int max);
double stepdown(double value, double stepping);

int main()
{
   int i, j;
   FILE* table = fopen("spell_power.txt","w");

   fprintf(table, "  ");
   for(i = 0; i <= 27; i++)
   {
      fprintf(table, "%d ", i);
   }
   fprintf(table, "\n");

   for(i = 1; i < 40; i++)
   {
      fprintf(table, "%d ", i);
      for (j = 0; j <= 27; j++)
         fprintf(table, "%d ", calc_spell_power(i, j, 4, -1, -1, true, 200));
      fprintf(table, "\n");
   }
}

int calc_spell_power(int intel, double scast,
                  double sch1, double sch2, double sch3,
                  bool apply_intel, int pcap)
{
    int power = 0;

   if (sch3 == -1 && sch2 == -1)
      power += sch1 * 200;
   else if (sch3 == -1)
      power += ((sch1 + sch2) / 2) * 200;
   else
      power += ((sch1 + sch2 + sch3) / 3) * 200;

   power += scast * 50;
   if (apply_intel)
      power = (power * intel) / 10;
   power = stepdown_value(power / 100, 50, 50, 200);

   // Cap the power.
    if (pcap > 0)
      if (power > pcap)
         power = pcap;

    return power;
}

int stepdown_value(int base_value, int stepping, int first_step,
                   int ceiling_value)
{
    if (ceiling_value && ceiling_value < first_step)
      if (base_value > ceiling_value)
         return ceiling_value;
      else
         return base_value;
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping,
                           ceiling_value ? ceiling_value - diff : 0);
}

double stepdown(double value, double stepping)
{
    return stepping * log2(1 + value / stepping);
}

int stepdown(int value, int step, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    return ret;
}

That, for a single-school spell 4.0 skill points invested in that school, gave me this:
  Code:
    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 1  0  0  0  0  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  2  2  2  2
 2  1  1  1  1  2  2  2  2  2  2  2  2  2  2  3  3  3  3  3  3  3  3  3  3  4  4  4  4
 3  2  2  2  2  3  3  3  3  3  3  3  4  4  4  4  4  4  4  5  5  5  5  5  5  6  6  6  6
 4  3  3  3  3  4  4  4  4  4  5  5  5  5  5  6  6  6  6  6  7  7  7  7  7  8  8  8  8
 5  4  4  4  4  5  5  5  5  6  6  6  6  7  7  7  7  8  8  8  8  9  9  9  9 10 10 10 10
 6  4  5  5  5  6  6  6  6  7  7  7  8  8  8  9  9  9  9 10 10 10 11 11 11 12 12 12 12
 7  5  5  6  6  7  7  7  8  8  8  9  9  9 10 10 10 11 11 11 12 12 12 13 13 14 14 14 15
 8  6  6  7  7  8  8  8  9  9 10 10 10 11 11 12 12 12 13 13 14 14 14 15 15 16 16 16 17
 9  7  7  8  8  9  9  9 10 10 11 11 12 12 13 13 13 14 14 15 15 16 16 17 17 18 18 18 19
10  8  8  9  9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21
11  8  9  9 10 11 11 12 12 13 13 14 14 15 15 16 17 17 18 18 19 19 20 20 21 22 22 23 23
12  9 10 10 11 12 12 13 13 14 15 15 16 16 17 18 18 19 19 20 21 21 22 22 23 24 24 25 25
13 10 11 11 12 13 13 14 14 15 16 16 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 27
14 11 11 12 13 14 14 15 16 16 17 18 18 19 20 21 21 22 23 23 24 25 25 26 27 28 28 29 30
15 12 12 13 14 15 15 16 17 18 18 19 20 21 21 22 23 24 24 25 26 27 27 28 29 30 30 31 32
16 12 13 14 15 16 16 17 18 19 20 20 21 22 23 24 24 25 26 27 28 28 29 30 31 32 32 33 34
17 13 14 15 16 17 17 18 19 20 21 22 22 23 24 25 26 27 28 28 29 30 31 32 33 34 34 35 36
18 14 15 16 17 18 18 19 20 21 22 23 24 25 26 27 27 28 29 30 31 32 33 34 35 36 36 37 38
19 15 16 17 18 19 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 38 39 40
20 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
21 16 17 18 19 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 42 43 44 45
22 17 18 19 20 22 23 24 25 26 27 28 29 30 31 33 34 35 36 37 38 39 40 41 42 44 45 46 47
23 18 19 20 21 23 24 25 26 27 28 29 31 32 33 34 35 36 37 39 40 41 42 43 44 46 47 48 49
24 19 20 21 22 24 25 26 27 28 30 31 32 33 34 36 37 38 39 40 42 43 44 45 46 48 49 50 50
25 20 21 22 23 25 26 27 28 30 31 32 33 35 36 37 38 40 41 42 43 45 46 47 48 50 50 51 52
26 20 22 23 24 26 27 28 29 31 32 33 35 36 37 39 40 41 42 44 45 46 48 49 50 51 52 52 53
27 21 22 24 25 27 28 29 31 32 33 35 36 37 39 40 41 43 44 45 47 48 49 50 51 52 53 54 55
28 22 23 25 26 28 29 30 32 33 35 36 37 39 40 42 43 44 46 47 49 50 50 52 52 54 54 55 56
29 23 24 26 27 29 30 31 33 34 36 37 39 40 42 43 44 46 47 49 50 51 52 53 54 55 56 56 58
30 24 25 27 28 30 31 33 34 36 37 39 40 42 43 45 46 48 49 50 51 52 53 54 55 56 57 58 59
31 24 26 27 29 31 32 34 35 37 38 40 41 43 44 46 48 49 50 51 52 53 54 55 56 58 58 60 60
32 25 27 28 30 32 33 35 36 38 40 41 43 44 46 48 49 50 51 52 54 54 56 56 58 59 60 61 61
33 26 28 29 31 33 34 36 37 39 41 42 44 46 47 49 50 51 52 54 54 56 57 58 59 60 61 62 63
34 27 28 30 32 34 35 37 39 40 42 44 45 47 49 50 51 52 54 54 56 57 58 59 60 61 62 63 64
35 28 29 31 33 35 36 38 40 42 43 45 47 49 50 51 52 54 54 56 57 58 59 60 61 63 63 64 66
36 28 30 32 34 36 37 39 41 43 45 46 48 50 51 52 53 54 56 57 58 59 60 61 63 64 64 66 67
37 29 31 33 35 37 38 40 42 44 46 48 49 50 52 53 54 56 57 58 59 60 61 63 64 65 66 67 68
38 30 32 34 36 38 39 41 43 45 47 49 50 52 53 54 55 56 58 59 60 61 63 64 65 66 67 68 69
39 31 33 35 37 39 40 42 44 46 48 50 51 52 54 55 56 58 59 60 61 63 64 65 66 67 68 69 70

Which, again, must be accurate for failure to have a hope of being not a failure.

But wizmode tells me that a spellcasting of 27 and Air Magic of 4 on an Int 27 character is a 40 spell power for Airstrike, so clearly this fails, unless these formulae have changed dramatically since 0.13

These things seem so straightforward, and yet they're failing. I'm still missing something.

[Edit: I found something I'd missed and fixed it while posting this: my averaging logic was backwards; but that didn't fix the inaccuracy of the table, just made it inaccurate differently. Mabye it's in the stepdown function.]
User avatar

Pandemonium Purger

Posts: 1298

Joined: Wednesday, 11th April 2012, 02:42

Location: Sydney, Australia

Post Wednesday, 30th July 2014, 05:37

Re: Spellcasting Fail Rate Calculator

Suggestion: Recompile DCSS to add debugging output (dprf, iirc) in functions that look useful/that you would love to know what numbers that produce, then wizmode that.

For this message the author Patashu has received thanks:
Aule

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Wednesday, 30th July 2014, 05:44

Re: Spellcasting Fail Rate Calculator

Patashu wrote:Suggestion: Recompile DCSS to add debugging output

That's a pretty big leap for someone who's found no end to the number of ways he can be incorrect, but I'll try.
User avatar

Pandemonium Purger

Posts: 1298

Joined: Wednesday, 11th April 2012, 02:42

Location: Sydney, Australia

Post Wednesday, 30th July 2014, 07:05

Re: Spellcasting Fail Rate Calculator

DCSS is really easy to compile. If you're on Windows, read INSTALL.txt and do the msysgit approach, NOT the cygwin approach (it won't work, period).

For this message the author Patashu has received thanks:
Aule

Lair Larrikin

Posts: 25

Joined: Saturday, 26th July 2014, 22:01

Post Wednesday, 30th July 2014, 11:32

Re: Spellcasting Fail Rate Calculator

But wizmode tells me that a spellcasting of 27 and Air Magic of 4 on an Int 27 character is a 40 spell power for Airstrike, so clearly this fails, unless these formulae have changed dramatically since 0.13


I tried this and it gives me 55 power, the calc_spell_power returns the same value.

The source code I posted is from 14.1 version, not from trunk, so use this to test.

I'm also confused as to how the spell power calc without intel gets the right numbers. Did intel drop from that calculation?


From spell_fail it's called with apply_intel=false, that's why I uncommented that part.

Thanks for any continued thought and effort on this. What did you compile yours with?


I used g++ on windows from mingw project, gcc version 4.5.2.

But it still doesn't match Irvs. :/


You didn't use the _get_true_fail_rate procedure in that code, wasn't this the difference?

For this message the author lrvs has received thanks:
Aule

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Wednesday, 30th July 2014, 20:57

Re: Spellcasting Fail Rate Calculator

lrvs wrote:
But wizmode tells me that a spellcasting of 27 and Air Magic of 4 on an Int 27 character is a 40 spell power for Airstrike, so clearly this fails, unless these formulae have changed dramatically since 0.13


I tried this and it gives me 55 power, the calc_spell_power returns the same value.

I swear to god, am I insane? I tested this, looked it over three times, saw 40, and now today after reading this, I started over, new char, set the values, and got 55. So I went back to look at the other one I made yesterday, and it says the same thing. And there's nothing there that's 40, so I'm just losing it, I guess. How truly bizarre.

From spell_fail it's called with apply_intel=false, that's why I uncommented that part.

I figured that part out. :oops:

I used g++ on windows from mingw project, gcc version 4.5.2.

I finally got it to work with that based on Patashu's search results. I think I tried all the compilers in that collection except that one, or gave up when like four of them produced the exact same message. :steam:

You didn't use the _get_true_fail_rate procedure in that code, wasn't this the difference?

Well, I'll be. Yes, because it was hidden in fail_rate_to_int which is hidden in fail_rate_to_string, and in simplifying the problem I left out a function that I thought only converts a number to a string because printf could do that. But obviously it's doing more than just converting the data type. That's misleading.

So putting _get_true_fail_rate() back in should make it work as expected, now. Indeed, for the most part it already was, and I'm just... fail.

Thanks.

Then I can go back to smoking DEWzs. (In case you wondered what I've been smoking... Lots of DEWzs.)

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Thursday, 31st July 2014, 00:29

Re: Spellcasting Fail Rate Calculator

No dice.
  Code:
#include <stdio.h>
#include <math.h>

int spell_fail(int dlev, int intel, double scast, double sch1, double sch2, double sch3);
static double _get_true_fail_rate(int raw_fail);
static int _tetrahedral_number(int n);
int failure_rate_to_int(int fail);
int min(int a, int b);
int max(int a, int b);
int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap);
int stepdown_value(int base_value, int stepping, int first_step, int ceiling_value);
int stepdown(int value, int step, int max);
double stepdown(double value, double stepping);

int main()
{
   int f, i, j;
   FILE* table = fopen("fail_table.txt","w");

   fprintf(table, "  ");
   for(i = 0; i <= 27; i++)
   {
      fprintf(table, "%d ", i);
   }
   fprintf(table, "\n");

   for(i = 1; i <= 40; i++)
   {
      fprintf(table, "%d ", i);
      for (j = 0; j <= 27; j++)
      {
         f = spell_fail(4, i, j, 4, -1, -1);
         fprintf(table, "%d ", failure_rate_to_int(f));
      }
      fprintf(table, "\n");
   }
}

int spell_fail(int dlev, int intel, double scast, double sch1, double sch2, double sch3)
{
    int chance = 60;

    // Don't cap power or apply intel for failure rate purposes.
    chance -= 6 * calc_spell_power(intel, scast, sch1, sch2, sch3, false, 0);
    chance -= intel * 2;

    switch (dlev)
    {
    case  1: chance +=   3; break;
    case  2: chance +=  15; break;
    case  3: chance +=  35; break;
    case  4: chance +=  70; break;
    case  5: chance += 100; break;
    case  6: chance += 150; break;
    case  7: chance += 200; break;
    case  8: chance += 260; break;
    case  9: chance += 330; break;
    case 10: chance += 420; break;
    case 11: chance += 500; break;
    case 12: chance += 600; break;
    default: chance += 750; break;
    }

    int chance2 = chance;

    const int chance_breaks[][2] =
    {
        {45, 45}, {42, 43}, {38, 41}, {35, 40}, {32, 38}, {28, 36},
        {22, 34}, {16, 32}, {10, 30}, {2, 28}, {-7, 26}, {-12, 24},
        {-18, 22}, {-24, 20}, {-30, 18}, {-38, 16}, {-46, 14},
        {-60, 12}, {-80, 10}, {-100, 8}, {-120, 6}, {-140, 4},
        {-160, 2}, {-180, 0}
    };

    for (unsigned int i = 0; i < 24; ++i)
        if (chance < chance_breaks[i][0])
            chance2 = chance_breaks[i][1];

    if (chance2 > 100)
        chance2 = 100;

    return chance2;
}

int failure_rate_to_int(int fail)
{
    if (fail <= 0)
        return 0;
    else if (fail >= 100)
        return (fail + 100) / 2;
    else
        return max(1, (int) (100 * _get_true_fail_rate(fail)));
}

static double _get_true_fail_rate(int raw_fail)
{
    int target = raw_fail * 3;

    if (target <= 100)
        return (double) _tetrahedral_number(target)/1020100;
    if (target <= 200)
    {
        return (double) (_tetrahedral_number(target)
                         - 2*_tetrahedral_number(target - 101)
                         - _tetrahedral_number(target - 100)) / 1020100;
    }
    return (double) (1020100 - _tetrahedral_number(300 - target)) / 1020100;
}

static int _tetrahedral_number(int n)
{
    return n * (n+1) * (n+2) / 6;
}

int max(int a, int b)
{
   if (a > b)
      return a;
   else
      return b;
}

int min(int a, int b)
{
   if (a < b)
      return a;
   else
      return b;
}

int calc_spell_power(int intel, double scast,
                  double sch1, double sch2, double sch3,
                  bool apply_intel, int pcap)
{
    int power = 0;

   if (sch3 == -1 && sch2 == -1)
      power += ((sch1 + sch2 + sch3) / 3) * 200;
   else if (sch3 == -1)
      power += ((sch1 + sch2) / 2) * 200;
   else
      power += sch1 * 200;

   power += scast * 50;
   if (apply_intel)
      power = (power * intel) / 10;
   power = stepdown_value(power / 100, 50, 50, 200);

   // Cap the power.
    if (pcap > 0)
      if (power > pcap)
         power = pcap;

    return power;
}

int stepdown_value(int base_value, int stepping, int first_step,
                   int ceiling_value)
{
    if (ceiling_value && ceiling_value < first_step)
      if (base_value > ceiling_value)
         return ceiling_value;
      else
         return base_value;
    if (base_value < first_step)
        return base_value;

    const int diff = first_step - stepping;
    // Since diff < first_step, we can assume here that ceiling_value > diff
    // or ceiling_value == 0.
    return diff + stepdown(base_value - diff, stepping,
                           ceiling_value ? ceiling_value - diff : 0);
}

double stepdown(double value, double stepping)
{
    return stepping * log2(1 + value / stepping);
}

int stepdown(int value, int step, int max)
{
    double ret = stepdown((double) value, double(step));

    if (max > 0 && ret > max)
        return max;

    return ret;
}
produced
  Code:
     0   1   2   3   4   5   6   7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 1 100 100 100 100 100 100 100 100 99 99 99 99 98 98 96 96 91 91 85 85 75 75 63 63 50 50 38 38
 2 100 100 100 100 100 100 100 100 99 99 99 99 98 98 95 95 89 89 82 82 71 71 58 58 45 45 38 38
 3 100 100 100 100 100 100 100 100 99 99 99 99 97 97 93 93 87 87 78 78 67 67 54 54 41 41 34 34
 4 100 100 100 100 100 100  99  99 99 99 98 98 96 96 91 91 85 85 75 75 63 63 50 50 38 38 34 34
 5 100 100 100 100 100 100  99  99 99 99 98 98 95 95 89 89 82 82 71 71 58 58 45 45 38 38 30 30
 6 100 100 100 100 100 100  99  99 99 99 97 97 93 93 87 87 78 78 67 67 54 54 41 41 34 34 28 28
 7 100 100 100 100  99  99  99  99 98 98 96 96 91 91 85 85 75 75 63 63 50 50 38 38 34 34 28 28
 8 100 100 100 100  99  99  99  99 98 98 95 95 89 89 82 82 71 71 58 58 45 45 38 38 30 30 24 24
 9 100 100 100 100  99  99  99  99 97 97 93 93 87 87 78 78 67 67 54 54 41 41 34 34 28 28 24 24
10 100 100  99  99  99  99  98  98 96 96 91 91 85 85 75 75 63 63 50 50 38 38 34 34 28 28 21 21
11 100 100  99  99  99  99  98  98 95 95 89 89 82 82 71 71 58 58 45 45 38 38 30 30 24 24 21 21
12 100 100  99  99  99  99  97  97 93 93 87 87 78 78 67 67 54 54 41 41 34 34 28 28 24 24 21 21
13  99  99  99  99  98  98  96  96 91 91 85 85 75 75 63 63 50 50 38 38 34 34 28 28 21 21 17 17
14  99  99  99  99  98  98  95  95 89 89 82 82 71 71 58 58 45 45 38 38 30 30 24 24 21 21 17 17
15  99  99  99  99  97  97  93  93 87 87 78 78 67 67 54 54 41 41 34 34 28 28 24 24 21 21 17 17
16  99  99  98  98  96  96  91  91 85 85 75 75 63 63 50 50 38 38 34 34 28 28 21 21 17 17 14 14
17  99  99  98  98  95  95  89  89 82 82 71 71 58 58 45 45 38 38 30 30 24 24 21 21 17 17 14 14
18  99  99  97  97  93  93  87  87 78 78 67 67 54 54 41 41 34 34 28 28 24 24 21 21 17 17 14 14
19  98  98  96  96  91  91  85  85 75 75 63 63 50 50 38 38 34 34 28 28 21 21 17 17 14 14 12 12
20  98  98  95  95  89  89  82  82 71 71 58 58 45 45 38 38 30 30 24 24 21 21 17 17 14 14 12 12
21  97  97  93  93  87  87  78  78 67 67 54 54 41 41 34 34 28 28 24 24 21 21 17 17 14 14 12 12
22  96  96  91  91  85  85  75  75 63 63 50 50 38 38 34 34 28 28 21 21 17 17 14 14 12 12 12 12
23  95  95  89  89  82  82  71  71 58 58 45 45 38 38 30 30 24 24 21 21 17 17 14 14 12 12 10 10
24  93  93  87  87  78  78  67  67 54 54 41 41 34 34 28 28 24 24 21 21 17 17 14 14 12 12 10 10
25  91  91  85  85  75  75  63  63 50 50 38 38 34 34 28 28 21 21 17 17 14 14 12 12 12 12 10 10
26  89  89  82  82  71  71  58  58 45 45 38 38 30 30 24 24 21 21 17 17 14 14 12 12 10 10 10 10
27  87  87  78  78  67  67  54  54 41 41 34 34 28 28 24 24 21 21 17 17 14 14 12 12 10 10  8  8
28  85  85  75  75  63  63  50  50 38 38 34 34 28 28 21 21 17 17 14 14 12 12 12 12 10 10  8  8
29  82  82  71  71  58  58  45  45 38 38 30 30 24 24 21 21 17 17 14 14 12 12 10 10 10 10  8  8
30  78  78  67  67  54  54  41  41 34 34 28 28 24 24 21 21 17 17 14 14 12 12 10 10  8  8  6  6
31  75  75  63  63  50  50  38  38 34 34 28 28 21 21 17 17 14 14 12 12 12 12 10 10  8  8  6  6
32  71  71  58  58  45  45  38  38 30 30 24 24 21 21 17 17 14 14 12 12 10 10 10 10  8  8  6  6
33  67  67  54  54  41  41  34  34 28 28 24 24 21 21 17 17 14 14 12 12 10 10  8  8  6  6  4  4
34  63  63  50  50  38  38  34  34 28 28 21 21 17 17 14 14 12 12 12 12 10 10  8  8  6  6  4  4
35  58  58  45  45  38  38  30  30 24 24 21 21 17 17 14 14 12 12 10 10 10 10  8  8  6  6  4  4
36  54  54  41  41  34  34  28  28 24 24 21 21 17 17 14 14 12 12 10 10  8  8  6  6  4  4  3  3
37  50  50  38  38  34  34  28  28 21 21 17 17 14 14 12 12 12 12 10 10  8  8  6  6  4  4  3  3
38  45  45  38  38  30  30  24  24 21 21 17 17 14 14 12 12 10 10 10 10  8  8  6  6  4  4  3  3
39  41  41  34  34  28  28  24  24 21 21 17 17 14 14 12 12 10 10  8  8  6  6  4  4  3  3  2  2
40  38  38  34  34  28  28  21  21 17 17 14 14 12 12 12 12 10 10  8  8  6  6  4  4  3  3  2  2

that matched neither Irvs nor wizmode.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Thursday, 31st July 2014, 01:55

Re: Spellcasting Fail Rate Calculator

I think I got it, now. Started with Irvs, and worked my way with that, removing extraneous stuff and checking each step with a new compile, comparing the resulting table as I went.

I think I can... I think I can...

Extraneous = randomized rounding (not used in the hard-coded call to stepdown_value, since the ROUND_DOWN conditionals don't call it. I couldn't believe the RNG would be utilized in a straightforward spell failure calculation, and it's not. I guess it's there for the miscast chance calls to the function, which aren't being used here. Removing it had no effect on the resulting table.

I'm gonna get there. I'll post the worksheet here when I get a finished and debugged version. It'll be available in Excel or OpenOffice Calc.

Crypt Cleanser

Posts: 723

Joined: Monday, 9th June 2014, 13:39

Post Thursday, 31st July 2014, 05:06

Re: Spellcasting Fail Rate Calculator

This all works: I've pared it down to a single function for fail, incorporating fail_rate_to_int, fail_rate_to_string, and get_true_fail_rate into one function for my smaller structure. I also rewrote any C-specific syntax that doesn't have a standard analogue in Basic, and expanded the function parameters. It still prints out the correct data, even after all that. (At least, that what I seem be be hallucinating today.)
  Code:
#include <stdio.h>
#include <math.h>

int spell_fail(int spell_lvl, int intel, double scast, double sch1, double sch2, double sch3, int pcap);
int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap);
int stepdown_value(int base_value, int stepping, int first_step, int ceiling_value);
int stepdown(int value, int step, int max);
double tetranum(int n);
int min(int a, int b);
int max(int a, int b);

int main()
{
   FILE* table=fopen("spell_code_13.txt", "w");

   int i, j;
   int sc_min, sc_max;
   int int_min, int_max;
   double sch1, sch2, sch3;

   sc_min = 0;
   sc_max = 27;
   int_min = 1;
   int_max = 40;

   // Airstrike
   int dlvl = 4;
   int pcap = 200;
   sch1 = 1;
   sch2 = -1;
   sch3 = -1;

   fprintf(table, "\t");
   for(i = sc_min; i <= sc_max; i++)
   {
      fprintf(table, "%d", i);
      if (i < sc_max)
         fprintf(table, "\t");
   }
   fprintf(table, "\n");

   for(i = int_min; i <= int_max; i++)
   {
      fprintf(table, "%d\t", i);
      for(j = sc_min; j <= sc_max; j++)
      {
         fprintf(table, "%d", spell_fail(dlvl, i, j, sch1, sch2, sch3, pcap));
         if (j < sc_max)
            fprintf(table, "\t");
      }
      fprintf(table, "\n");
   }
}

int spell_fail(int dlvl, int intel, double scast, double sch1, double sch2, double sch3, int pcap)
{
   int chance = 60;

   // Don't cap power for failure rate purposes.
   chance -= 6 * calc_spell_power(intel, scast, sch1, sch2, sch3, false, pcap);
   chance -= (intel * 2);

   switch (dlvl)
   {
   case  1: chance +=   3; break;
   case  2: chance +=  15; break;
   case  3: chance +=  35; break;
   case  4: chance +=  70; break;
   case  5: chance += 100; break;
   case  6: chance += 150; break;
   case  7: chance += 200; break;
   case  8: chance += 260; break;
   case  9: chance += 330; break;
   case 10: chance += 420; break;
   case 11: chance += 500; break;
   case 12: chance += 600; break;
   default: chance += 750; break;
   }

   int chance2 = chance;

   const int chance_breaks[][2] =
   {
      {45, 45}, {42, 43}, {38, 41}, {35, 40}, {32, 38}, {28, 36},
      {22, 34}, {16, 32}, {10, 30}, {2, 28}, {-7, 26}, {-12, 24},
      {-18, 22}, {-24, 20}, {-30, 18}, {-38, 16}, {-46, 14},
      {-60, 12}, {-80, 10}, {-100, 8}, {-120, 6}, {-140, 4},
      {-160, 2}, {-180, 0}
   };

   for(unsigned int i = 0; i < 24; ++i)
      if (chance < chance_breaks[i][0])
         chance2 = chance_breaks[i][1];

   if (chance2 > 100)
      chance2 = 100;
   
   if (chance2 <= 0)
      chance2 = 0;
   else
   {
      int target = chance2 * 3;
      double chance3;

      if (target <= 100)
         chance3 = tetranum(target) / 1020100;
      else if (target <= 200)
         chance3 = (tetranum(target) - 2 * tetranum(target - 101) - tetranum(target - 100)) / 1020100;
      else
         chance3 = (1020100 - tetranum(300 - target)) / 1020100;

      return max(1, (int) 100 * chance3);
   }

   return chance2;
}

int calc_spell_power(int intel, double scast, double sch1, double sch2, double sch3, bool apply_intel, int pcap)
{
   int power = 0;

   if (sch3 == -1 && sch2 == -1)
      power += sch1 * 200;
   else if (sch3 == -1)
      power += ((sch1 + sch2) / 2) * 200;
   else
      power += ((sch1 + sch2 + sch3) / 3) * 200;

   power += scast * 50;
   if (apply_intel)
      power = (power * intel) / 10;
   power = stepdown_value(power / 100, 50, 50, 200);

   // Cap the power.
   if (pcap > 0)
      if (power > pcap)
         power = pcap;

   return power;
}

int stepdown(int value, int step, int max)
{
   double ret = step * log2(1 + value / step);

   if (max > 0 && ret > max)
      return max;

   return ret;
}

int stepdown_value(int base_value, int stepping, int first_step,
                  int ceiling_value)
{
   if (ceiling_value < 0)
      ceiling_value = 0;

   if (ceiling_value && ceiling_value < first_step)
      return min(base_value, ceiling_value);
   if (base_value < first_step)
      return base_value;

   const int diff = first_step - stepping;
   int maxval = 0;

   if (ceiling_value)
      maxval = ceiling_value - diff;

   return diff + stepdown(base_value - diff, stepping, maxval);
}

double tetranum(int n)
{
   return n * (n+1) * (n+2) / 6;
}

int max(int a, int b)
{
   if (a > b)
      return a;
   else
      return b;
}

int min(int a, int b)
{
   if (a < b)
      return a;
   else
      return b;
}

Lair Larrikin

Posts: 25

Joined: Saturday, 26th July 2014, 22:01

Post Thursday, 31st July 2014, 09:12

Re: Spellcasting Fail Rate Calculator

Congratulations!

  Code:
Extraneous = randomized rounding (not used in the hard-coded call to stepdown_value, since the ROUND_DOWN conditionals don't call it. I couldn't believe the RNG would be utilized in a straightforward spell failure calculation, and it's not. I guess it's there for the miscast chance calls to the function, which aren't being used here. Removing it had no effect on the resulting table.


Nice catch I didn't notice this at all. Random rounding also bothered me there. It doesn't have to anymore since it's not used there at all.


you.skill() is in player.cc if anyone is interested in that.

For this message the author lrvs has received thanks:
Aule

Return to Coding

Who is online

Users browsing this forum: No registered users and 8 guests

cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.