Feature - Implemented Initiative Calculations

Percent chance of gaining initiative (capped at 0 if less than 0 or 100 if greater than 100).
Code:
 Initiative (in %) = (100 - Monster Base Init) 
   + Init Modifiers 
   + max(0, Mainstat - Adjusted Monster Attack (including MCDs and Slimetube Squeezes))
   - Extra Monster Level Penalty

Extra Monster Level Penalty (does not include MCDs or Slimetube Squeezes):
+0% per +1 ML for 0-20
+1% per +1 ML for 21-40
+2% per +1 ML for 41-60
+3% per +1 ML for 61-80
+4% per +1 ML for 81-100
+5% per +1 ML for 100+
This can be easily expressed in code like so (ML in this code refers to only +ML, not total ML):
Code:
int penalty = 0;
if(ML > 20) {
   penalty = ML-20;
   if(ML > 40) {
      penalty += ML-40;
      if(ML > 60) {
         penalty += ML-60;
         if(ML > 80) {
            penalty += ML-80;
            if(ML > 100) {
               penalty += ML-100;
            }
         }
      }
   }
}

I suppose that the only thing that can really be done is to show the Init in the main GUI as your +init modifiers minus the ML penalty, since actual initiative is monster-dependent.

Then perhaps in the Location Details thingy, a spot for calculating initiative versus the specific monsters, if mafia even tracks monster's base init? If that'd be too much of a pain (as, if it's not in there, that'd be a ton of work, i think), then I wouldn't worry about it, and would just do the calculation for the main GUI.
 

slyz

Developer
Mafia currently doesn't do any kind of initiative calculation, it only tracks the +init modifiers. This would be a nice addition to the location details though.
 

Rinn

Developer
This can be easily expressed in code like so (ML in this code refers to only +ML, not total ML):
Code:
int penalty = 0;
if(ML > 20) {
   penalty = ML-20;
   if(ML > 40) {
      penalty += ML-40;
      if(ML > 60) {
         penalty += ML-60;
         if(ML > 80) {
            penalty += ML-80;
            if(ML > 100) {
               penalty += ML-100;
            }
         }
      }
   }
}

This is a bit nicer then nested if statements:
Code:
int penalty = min(0, ml-20) + (2 * min(0, ml-40)) + (3 * min(0, ml-60)) + (4 * min(0, ml-80)) + (5 * min(0, ml-100));
I wonder if there's a more elegant expression then this.
 
Last edited:

lostcalpolydude

Developer
Staff member
Even if the min() expression is how it's written rather than a bunch of if statements, the 2*, 3*, etc shouldn't be there.
 

Rinn

Developer
Oh you know what I wrote it wrong min is not what I wanted, it would need clamp each value between 0 to 20 before multiplying, otherwise it would be correct. (I don't know if java has a clamp function in Math)

Code:
int penalty = clamp(ml-20, 0, 20) + (2 * clamp(ml-40, 0, 20)) + (3 * clamp(ml-60, 0, 20)) + (4 * clamp(ml-80, 0, 20)) + (5 * clamp(ml-100, 0, 20));
For an ml value of 101 this would return 20 + (2 * 20) + (3 * 20) + (4 * 20) + (5 * 1), or 20 + 40 + 60 + 80 + 5 which equals 205, which is expected from the initiative page.
 
Last edited:

lostcalpolydude

Developer
Staff member
Oh, I should have noticed this before, it would be max instead of min, drop the multipliers, and then there's no need for clamp(). I've even typed the formula out in that form before, so I should have realized it sooner.
 
Oh you know what I wrote it wrong min is not what I wanted, it would need clamp each value between 0 to 20 before multiplying, otherwise it would be correct. (I don't know if java has a clamp function in Math)

Code:
int penalty = clamp(ml-20, 0, 20) + (2 * clamp(ml-40, 0, 20)) + (3 * clamp(ml-60, 0, 20)) + (4 * clamp(ml-80, 0, 20)) + (5 * clamp(ml-100, 0, 20));
For an ml value of 101 this would return 20 + (2 * 20) + (3 * 20) + (4 * 20) + (5 * 1), or 20 + 40 + 60 + 80 + 5 which equals 205, which is expected from the initiative page.

Plug in ML = 200. Do you get 700? Seems more like 300.

If you really want to express it in that form (which, uh, why bother, when I gave you a perfectly reasonable way to do it?), then you need to have it do:
Code:
int penalty = max(0, ml-20) + max(0, ml-40) + max(0, ml-60) + max(0, ml-80) + max(0, ml-100)

Which, uhh.. why? It's more efficient to have the nested ifs like i've got them anyway, it's also just as readable (to me, anyway), since that's not doing a bunch of function calls which also do comparisons that may not even be necessary. Why is this even a discussion, your formula was broken from the start, and mine was not.
 

Rinn

Developer
The clamp on my expression for the +100 ml isn't needed since that can scale to whatever, but you're right the max expression works better. Either way I don't think 5 nested if statement are ever really reasonable, we're just not going to agree on that so I'll drop it.
 
Last edited:

Bale

Minion
I don't think 5 nested if statement are ever really reasonable, we're just not going to agree on that so I'll drop it.

Each of your max() functions contains a conditional; each clamp() function contains two. How is that more reasonable? I actually found the 5 nested if statements to be somewhat elegant. It is certainly more efficient in that unlike your method, it does not require every if statement to be evaluated unless ML is over 100.
 

Roquen

New member
Ideally this function should only be called when +ML changes and the value cached. Thus the frequency of calling is statistically zero. Therefore clairity should trump speed. If you wanted to be anal, a simple speed up would be to convert it into divide and conq form. But even that make the assumption that +ML usage is unform across the ranges. Mathematically the function is log related...let's no go there. It could also be expressed in terms of division and mod 20...not so good either.
 

Bale

Minion
I'm afraid I cannot tell if the preceding post is serious or satirical. o_O;;

Edit: I'm gonna go with satirical 'cause it was rather funny.
 

Roquen

New member
I was taking the piss...other than there's no point in optimizing. You could do the following...but why?

Code:
  public static final int bar(int ML)
  {
    int x = ML / 20;
    
    if (x > 5) x = 5;
    
    return x*(ML-(x+1)*10);
  }

(edit: My first post really should have used exp & log gamma, boo on me)
 
Last edited:
really cool formula

Hah. I like it. I've never been much for converting into wacky "where'd that come from?" formulas like that. Mostly because I like being able to read my own code :p

I do agree with your previous point, that clarity is better than optimizing (especially in the case where the clear form is still extremely efficient and fast). Getting the thing right, then worrying about optimization if you have to has typically been the way I operate in general.
 

fronobulax

Developer
Staff member
Ooo! Ooo! Holy Wars!!!

I tend to favor functions in the mathematical sense (no embedded conditionals) because they are easier for me to analyze. I understand that they are almost never the most efficient way to implement something. Speaking of which, I have very little tolerance for people who worship at the Altar of Efficiency to the exclusion of all else. Jon Bentley taught me that it is much easier to make a working program fast than it is to make a fast program work, and any number of smart people will tell you that optimization is something that should only be done when there is a resource constraint and a means to measure the effect of any change.

So I'll pile on and vote for clarity.
 

zarqon

Well-known member
Oh why not?

Code:
min(ML / 20, 5)*(ML-(min(ML / 20, 5)+1)*10)

Now you don't even need a separate function because it's a single expression! And as an added benefit, someone else looking at the code would have to spend extra time figuring out what the heck it does.
 

Roquen

New member
What could be more clear than this:

Code:
  {
    int a = ML * 0xCCCD;
    int b = a >>> 20;
    int c = (100-ML)>>31;
    int d = (b & ~c) | (5 & c);
    int e = d*(ML-(d<<3)-(d+d)-10);
    
    return e;
}
 
Top