Module:CalcStat

From Lotro-Wiki.com
Jump to navigation Jump to search

Overview

Calculates game stats based on the Standard Progression and other progressions.

See: CalcStat on LoTROInterface

Current version is: 2.3.4f

Installation

First you need to download the source from LotroInterface (see link above) or install the plugin by using LOTRO Plugin Compendium. You will find the sources in the zip file or in your plugins directory under Giseldah\CalcStat.
The Wiki Lua code needs to be compiled from the source in calcstat.csv. Start the compiler script statdcmp.vbs under Windows and choose output option 6: Lua-script (Lotro-Wiki Module). Next choose option 1 to include all stats. The resulting CalcStat.lua file is the code for Module:CalcStat.

Usage

Usage: {{#invoke:CalcStat|calc|StatName or Expression|Level|NorC|Format|Display}}

Standard Parameters

  • StatName: reference to the stat to be calculated. See stat sections below for some of the possibilities. The calcstat.csv file contains the complete list (best viewed with a spreadsheet application), but be warned that it's very complex and some stats are only internal calculations.

---> Instead of a Statname, CalcStat now also accepts a CalcStat Expression.

  • Level: can be a character level, item level, virtue rank, etc.
  • NorC: optional parameter. can be either number or text, depending on stat.

Specific parameters for Wiki use

Assuming a value of 12345.016:
  1. %'d displays a thousand separated number for main stats (whole numbers; rounded down when fractured) like: 12,345
  2. %'+d displays a thousand separated number for main stats (whole numbers; rounded down when fractured) with a forced sign like: +12,345
  3. %.0f (default) displays a number for rating stats (fractured numbers; normal rounding to given precision 0 decimals) like: 12345
  4. %+.0f displays a number for rating stats (fractured numbers; normal rounding to given precision 0 decimals) with a forced sign like: +12345
  5. %'.1f displays a thousand separated number for DPS (fractured numbers; normal rounding to given precision 1 decimal) like: 12,345.0
  6. %'.0.1f displays a thousand separated number (fractured numbers; normal rounding to given precision maximum 1 decimal / removing trailing zeroes up to minimum precision 0 ) like: 12,345
  7. %'.1.2f displays a thousand separated number (fractured numbers; normal rounding to given precision maximum 2 decimal / removing trailing zeroes up to minimum precision 1 ) like: 12,345.02
  • Display: option for display of percentages and other:
  1. AddP: Display Additive Percentage (with a 0.0002 correction).
  2. AddP100: Mutltiply by 100 & display as Additive Percentage (with a 0.0002 correction).
  3. MultiP: Display Multiplier Percentage (with a 0.0002 correction).
  4. MultiP100: Mutltiply by 100 & display as Multiplier Percentage (with a 0.0002 correction).
  5. Worth: Displays value in gold/silver/copper (from number value in format ..ggggssscc).
  6. Corr: Correction. 0.0002 is added to any number (this is the default for numbers).
  7. NoAdj: No adjustments - to override any defaults.

Expressions

Introduction

A StatName is an identifier in the shape of a series of letters and digits(but never at the start or end) which connects to an internal CalcStat expression.
With Expressions you can now make your own ones. You can for example do some simple calculations:

{{#invoke:CalcStat|calc|1+1}}

2

{{#invoke:CalcStat|calc|5*-3^2^-2+28*(4/6+1)+1/3*2|||%.0.8f|NoAdj}}

40.75296327

Magic Words

Note that in Wiki the pipe character '|' and equal sign '=' are processed as part of the #invoke argument parsing. If you want to use these in your Expressions code then you need to use {{!}} or {{=}} respectively.

Operators

In expressions you can use the same operators as used in Lua version 5.1, minus the '#'. They are also processed in the same order of priority and direction.
Syntax in expressions is not case-sensitive, so AND and Or are fine.
From low to high priority:

Operators Processing direction Notes
or
and
< > <= >= ~= ==
.. string concatenation
+ -
* / % % is modulo/remainder
not - unary -
^

Of course you can also use parentheses () and what is in-between will have priority above all else.

Constants/values

Numbers

Accepted as valid numbers are:

  • a series of digits. (like 123)
  • a series of digits including a decimal dot '.', but not at the edges. (like 0.123, but not .123)

Strings

Strings are encapsulated between double quotes: "tekst".
Accepted escape characters in strings are:

  • \q or \" double quote
  • \\ backslash
  • \n new line

Booleans

Booleans are True and False, non-case-sensitive.

Variables

In CalcStat you have variables which can be used in expressions:

  • L - stands for some kind of level, rank, etc. It's value is equal to the parameter which you supply in the template.
  • N - an extra number value defined in the NorC parameter. N is automatically detected when NorC can be converted to a number.
  • C - a text string from the NorC parameter: anything which is not a number.

These variables can be used in expressions by prefixing a $ sign, so like $L, $N, $C.

{{#invoke:CalcStat|calc|"(L)evel {{=}} "..$L.." and (N)umber {{=}} "..$N|5|9.5}} ('=' between {{}} to avoid processing of '=' characters by Wiki)

(L)evel = 5 and (N)umber = 9.5

{{#invoke:CalcStat|calc|$L*($N+1)+5.30106}|5|9.5|%.1.2f|NoAdj}}

57.8

Using Stats

You can use CalcStat stat values in your own expression by using the name of the stat with the @ prefix. Any number attached at the back is interpreted as being the $L to pass to the stat calculation (current $L is passed by default if nothing is specified).

{{#invoke:CalcStat|calc|"1 point of player level Might at level 130: "..@MightT130}}

1 point of player level Might at level 130: 300

{{#invoke:CalcStat|calc|"1 point of item level Might at ilvl 130: "..@Might130}}

1 point of item level Might at ilvl 130: 50

You can also pass a $N parameter to the stat by attaching a # sign followed by a number for the $N to pass. If you only attach a # with no number after it then current $N is passed to the stat.

{{#invoke:CalcStat|calc|"2.6 points of player level Critical Rating at level 100: "..@CritHitT100#2.6}}

2.6 points of player level Critical Rating at level 100: 1180

{{#invoke:CalcStat|calc|"2.6 points of item level Critical Rating at ilvl 100: "..@CritHit100#2.6}}

2.6 points of item level Critical Rating at ilvl 100: 538.33333333333

Instead of a number for $L and $N, you might want to pass an expression. In that case just use parentheses () instead of the numbers.
This is also the way that you can pass a tekst parameter $C (any string expression containing things like constants "tekst", current $C or a stat which returns a string)

{{#invoke:CalcStat|calc|"1/2 points of item level Critical Rating at ilvl "..$L..": "..@CritHit#(1/2)|123}}

1/2 points of item level Critical Rating at ilvl 123: 131.675

{{#invoke:CalcStat|calc|"Armour value for heavy incomparable boots at ilvl "..$L..": "..@Armour#($C)|412|HBT}}

Armour value for heavy incomparable boots at ilvl 412: 2344

{{#invoke:CalcStat|calc|"At ilvl "..$L..", @Vitality#2 is "..@Vitality#2.." and 2*@Vitality#1 equals "..2*@Vitality#1.."... "..iif(@Vitality#2{{=}}{{=}}2*@Vitality#1,"Ok.","It's not the same!")|468}}

At ilvl 468, @Vitality#2 is 863 and 2*@Vitality#1 equals 862... It's not the same!

Functions

Adding functions is an ongoing process. These are the functions currently supported:

Name Notes
Abs(<number expression>) Absolute value (make positive).
Afd(<number expression>, <display option string expression>) Adjust for display. See Specific parameters for Wiki use. Default is "Corr".
Afd(<number expression>)
CalcStat(<Stat name string expression>, <Level number expression>, <NorC expression>) Can be used instead of the shortcut @StatName(Level)#(NorC).
CalcStat(<Stat name string expression>, <Level number expression>)
CalcStat(<Stat name string expression>)
Ceil(<number expression>) Rounds value up to whole number.
Choose(<index number expression>, <parameter list>) Chooses a parameter (any expression), based on the first which is the index.
Floor(<number expression>) Rounds value down to whole number.
Format(<expression>, "format string") Format to specific text output. See also Specific parameters for Wiki use. Default is "%.0f" for numbers.
Format(<expression>)
IIf(<logical expression>, <expression1>, <expression2>) If the logical expression is true then returns expression1, otherwise expression2.
Log10(<number expression>) Gives the base-10 logarithm.
Min(<number expression1>, <number expression2>) Returns the smallest of 2 numbers.
Max(<number expression1>, <number expression2>) Returns the largest of 2 numbers.
Replace(<string expression1>, <string expression2, <string expression3>) Replaces all occurrences of string2 in string1 with string3.
SESel(<test expression>, <interval expression1>, <result expression1>, ..etc, <otherwise expression>) Smaller-Equal Select: see below.
Sqrt(<number expression>) Gives the square root.
Switch(<test expression>, case <comparison expression1>: <result expression1>, case..etc, default: <otherwise expression>) Returns a value when a comparison is true.
Until(<initial variable assignment list>: <loop variable assignment list>: <loop termination condition logical expression>: <result expression>) Executes an Until loop until a termination condition is met and returns a processing result.
While(<initial variable assignment list>: <loop execution condition logical expression>: <loop variable assignment list>: <result expression>) Executes a While loop while an execution condition is met and returns a processing result.
With(<variable assignment list>:<result expression>) Assigns values to (custom) variables and returns a value based on these.

Choose

The first parameter is the index into the remaining parameters. An index value of 1 selects parameter 2 etc. Gives an error when the index is out of bounce.

{{#invoke:CalcStat|calc|
Choose(
     $L,
          "Adam",
          "Cindy",
          "Sandy",
          "Thom"
)
|2}}

Cindy

Replace

Replaces text parts inside a text with other texts.

{{#invoke:CalcStat|calc|
Replace("Rune-keeper","-","")
}}

Runekeeper

SESel

Smaller-Equal Select. This function works like Switch, but is more focused on breaking up a range into intervals. It behaves like a Switch(operand1, case <= operand2: operand3, case <= operand4: operand5, etc default: operandn) with the last parameter being the default (value for the remaining/top interval).

{{#invoke:CalcStat|calc|
SESel(
     $L,
         75, 1,
        100, 2,
        105, 3,
        120, 4,
        130, 5,
             6
)
|121}}

5

Switch

You can combine multiple cases for one result value/expression, like with <100 and >120 in this example. Note that after 'default' nothing will be processed.
Also, in Expressions only the parts which need to be processed are being processed, so comparisons are executed top-down until true and then the single result value is evaluated.
The same for the IIf function: only the condition is being evaluated and then one of the results will be processed depending on the outcome.

{{#invoke:CalcStat|calc|
$L..": "..
switch(
    $L,
        case < 20:
            iif($L < 10, "smaller than 10", "smaller than 20, but equal or larger than 10"),
        case < 30:
            "smaller than 30",
        case < 100:
        case > 120:
            "smaller than 100 or larger than 120",
        default:
            "in the range of 100 to 120"
)
|15}}

15: smaller than 20, but equal or larger than 10

Until

This is a Do..Until loop so the loop condition is checked after processing the variable assignment list inside the loop and the loop cycles until the termination condition becomes true.
You can use the initial variable assignments to setup a loop control variable, like a counter, and a result variable, which you can change inside the loop and return at the end of the processing.
The Until function has a counterpart in While(), which checks for an execution condition to be true before each cycle is run.
The maximum number of cycles is limited to 1000.

{{#invoke:CalcStat|calc|
Until(
     $NameRows{{=}}"", $NameIdx{{=}}1:
          $Name{{=}}Choose($NameIdx,"Rose","William","Kees",""),
          $NameRows{{=}}$NameRows..Iif($Name{{=}}{{=}}"","",
               $NameIdx..". "..$Name.."<br>"
          ),
          $NameIdx{{=}}$NameIdx+1:
     $Name{{=}}{{=}}"":
     $NameRows
)
}}

1. Rose
2. William
3. Kees

While

This is a While..Do loop so the loop condition is checked before processing the variable assignment list inside the loop and the loop cycles while the execution condition stays true.
You can use the initial variable assignments to setup a loop control variable, like a counter, and a result variable, which you can change inside the loop and return at the end of the processing.
The While function has a counterpart in Until(), which checks for a termination condition to be true at the end of each cycle.
The maximum number of cycles is limited to 1000.

{{#invoke:CalcStat|calc|
With(
     $iLvl{{=}}512:
          "<u>Item Stats at iLvl "..$iLvl.."</u><br>"..
          While(
               $Result{{=}}"", $Index{{=}}1:
               $Index<{{=}}5:
                    $StatName{{=}}Choose($Index,"Agility","Fate","Might","Vitality","Will"),
                    $Result{{=}}$Result..$Index..". "..$StatName..": "..CalcStat($StatName,$iLvl).."<br>",
                    $Index{{=}}$Index+1:
               $Result
          )
)
}}

Item Stats at iLvl 512
1. Agility: 823
2. Fate: 675
3. Might: 823
4. Vitality: 801
5. Will: 823

With

You can assign values to multiple variables separated by a comma, which you can name anything you like(only alphabetical characters). The With function returns the value of the expression after the ':'.

{{#invoke:CalcStat|calc|
With(
    $LplusTen {{=}} $L+10,
    $LminusFive {{=}} $L-5:
        $LplusTen*2+$LminusFive*3
)
|8}}

45
Note that no such thing as a variable scope exists in these expressions, so all variables are 'global'. This means that these variables are permanent and do exist outside the With function.
Also, nothing stands in the way of changing predefined variables as $L with the same impact. Avoid doing this as it may lead to unpredictable results.

{{#invoke:CalcStat|calc|
With(
    $L {{=}} $L+1:
        $L
)
+2*$L
|3}}

12

Stats

These (most of the normalized)stats are only a part of the collection. A full list can be found in the calcstat.csv file, which is in the ..\The Lord of the Rings Online\Plugins\Giseldah\CalcStat directory when you have installed the plugin.

Rating to Percentage and vice versa

All rating percentages related stat names kind of look the same. The first part of the name is the type of percentage and the part at the end selects the data or calculation for it.

First Part Notes
Block Block Chance
BPE Block/Parry/Evade Chance (general reference)
CritDef Critical Defence
CritHit Critical Hit Chance
CritMagn Critical/Devastating Hit Magnitude
DevHit Devastating Hit Chance
Evade Evade Chance
Finesse Finesse
InDmg Another ring was made.. (depreciated)
InHeal Incoming Healing
MitHeavy Mitigation Heavy classes (general reference)
MitLight Mitigation Light classes (general reference)
MitMedium Mitigation Medium classes (general reference)
OutDmg Outgoing Damage (general reference)
OutHeal Outgoing Healing
Parry Parry Chance
PartBlock Partial Block Chance
PartBlockMit Partial Block Mitigation
PartBPE Partial Block/Parry/Evade Chance (general reference)
PartEvade Partial Evade Chance
PartEvadeMit Partial Evade Mitigation
PartMit Partial Block/Parry/Evade Mitigation (general reference)
PartParry Partial Parry Chance
PartParryMit Partial Parry Mitigation
PhyDmg Physical Damage
PhyMitH Physical Mitigation Heavy classes
PhyMitL Physical Mitigation Light classes
PhyMitM Physical Mitigation Medium classes
Resist Resistance
TacDmg Tactical Damage
TacMitH Tactical Mitigation Heavy classes
TacMitL Tactical Mitigation Light classes
TacMitM Tactical Mitigation Medium classes
End Part L NorC Notes
PBonus PlayerLvl Percentage Bonus
PPRat PlayerLvl N=percentage Percentage to Rating
PRatP PlayerLvl N=rating Rating to Percentage
PRatPA PlayerLvl A
PRatPB PlayerLvl B-rating
PRatPC PlayerLvl C (curve constant)
PRatPCap PlayerLvl Percentage Cap
PRatPCapR PlayerLvl Percentage Cap Rating (rating required)

General references are not preferred to be used. However, if you want to refer to BPE chances in general without being specific about one of the three then go ahead.

Examples

Calculating the basic Evade Chance percentage for 30000 Evade rating at player level 107.

{{#invoke:CalcStat|calc|EvadePRatP|107|30000|%.1f%%|AddP}}

13.0%

You should also add the percentage bonus like with Partial Evade Mitigation (Partial Mitigations are currently the only one with a 0.1 bonus):

{{#invoke:CalcStat|calc|@PartEvadeMitPRatP#+@PartEvadeMitPBonus|107|30000|%.1f%%|AddP}}

35.1%

Calculating the Evade rating required to reach 10.5% Evade Chance (without accounting for any PBONUS) at player level 120.

{{#invoke:CalcStat|calc|EvadePPRat|120|10.5|%f|NoAdj}}

16578.947368

The previous rating should be rounded up, so you could use the expression:

{{#invoke:CalcStat|calc|Ceil(@EvadePPRat#)|120|10.5|%f|NoAdj}}

16579

Main stats

Many stats have a player level and an item level version. I first created calculations for item stats, so the names for those are the most straightforward. For player stats I appended a 'T' at the name, which stands for Traits. That category is much too narrow though: these stats are used anywhere where stats are player level related like in Effects.
Notes:

  • Stat Main is the general reference here. This stat is equal to Agility, Fate, Might and Will. Vitality stats are currently on a different progression.
  • The N parameter should contain the number of stat points. Default for N is 1, so if you don't supply a specific number then you get the standard 1 point. Note that, in general, because of internal 3 digit rounding introduced a while ago, N * (1 point of Stat) is not same as (N points of Stat) anymore.
  • Main stat values are always whole numbers. Module:CalcStatTable tries to apply format %'d, so whole number format with thousand separator, based on the statname. Module:CalcStat treats them like any other number.
Item level stat
StatName L NorC Notes
Agility ItemLvl N=points
Fate ItemLvl N=points
Main ItemLvl N=points (general reference)
Might ItemLvl N=points
Vitality ItemLvl N=points
Will ItemLvl N=points
Player level stat
StatName L NorC Notes
AgilityT PlayerLvl N=points
FateT PlayerLvl N=points
MainT PlayerLvl N=points (general reference)
MightT PlayerLvl N=points
VitalityT PlayerLvl N=points
WillT PlayerLvl N=points

Rating stats

Notes:

  • The N parameter should contain the number of stat points. Default for N is 1, so if you don't supply a specific number then you get the standard 1 point. Note that, in general, because of internal 3 digit rounding introduced a while ago, N * (1 point of Stat) is not same as (N points of Stat) anymore.
  • Rating stat values are fractured numbers. Module:CalcStat applies the format %.0f as default, so fractured number format rounded to 0 decimals.
Item level stat
StatName L NorC Notes
AcidMit ItemLvl N=points Acid Mitigation
Armour ItemLvl C=code See Armour section.
ArmourLow ItemLvl C=code (Decrepit) See Armour section.
-
Block ItemLvl N=points Block Rating
BPE ItemLvl N=points Block/Parry/Evade Rating (general reference)
CritDef ItemLvl N=points Critical Defence
CritHit ItemLvl N=points Critical Rating
-
-
DmgTypeMit ItemLvl N=points (Acid/Fire/etc) Mitigation (general reference)
Evade ItemLvl N=points Evade Rating
-
Finesse ItemLvl N=points Finesse Rating
FireMit ItemLvl N=points Fire Mitigation
FrostMit ItemLvl N=points Frost Mitigation
InHeal ItemLvl N=points Incoming Healing Rating
LightMit ItemLvl N=points Light Mitigation
LightningMit ItemLvl N=points Lightning Mitigation
Mastery ItemLvl N=points Mastery Rating (general reference)
OutHeal ItemLvl N=points Outgoing Healing Rating
Parry ItemLvl N=points Parry Rating
PhyMas ItemLvl N=points Physical Mastery Rating
PhyMit ItemLvl N=points Physical Mitigation
-
-
Resist ItemLvl N=points Resistance Rating
-
ShadowMit ItemLvl N=points Shadow Mitigation
-
TacMas ItemLvl N=points Tactical Mastery Rating
TacMit ItemLvl N=points Tactical Mitigation
-
-
Player level stat
StatName L NorC Notes
AcidMitT PlayerLvl N=points Acid Mitigation
ArmourT PlayerLvl N=points Armour Value
-
ArmourPenT PlayerLvl N=points Armour Penetration
BlockT PlayerLvl N=points Block Rating
BPET PlayerLvl N=points Block/Parry/Evade Rating (general reference)
CritDefT PlayerLvl N=points Critical Defence
CritHitT PlayerLvl N=points Critical Rating
CryResistT PlayerLvl N=points Cry Resist Rating
DiseaseResistT PlayerLvl N=points Disease Resist Rating (not in use yet)
DmgTypeMitT PlayerLvl N=points (Acid/Fire/etc) Mitigation (general reference)
EvadeT PlayerLvl N=points Evade Rating
FearResistT PlayerLvl N=points Fear Resist Rating
FinesseT PlayerLvl N=points Finesse Rating
FireMitT PlayerLvl N=points Fire Mitigation
FrostMitT PlayerLvl N=points Frost Mitigation
InHealT PlayerLvl N=points Incoming Healing Rating
LightMitT PlayerLvl N=points Light Mitigation
LightningMitT PlayerLvl N=points Lightning Mitigation
MasteryT PlayerLvl N=points Mastery Rating (general reference)
OutHealT PlayerLvl N=points Outgoing Healing Rating
ParryT PlayerLvl N=points Parry Rating
PhyMasT PlayerLvl N=points Physical Mastery Rating
PhyMitT PlayerLvl N=points Physical Mitigation
PhyResistT PlayerLvl N=points Physical Resist Rating
PoisonResistT PlayerLvl N=points Poison Resist Rating
ResistT PlayerLvl N=points Resistance Rating
ResistAddT PlayerLvl N=points (Cry/Song/etc) Resist Rating (general reference)
ShadowMitT PlayerLvl N=points Shadow Mitigation
SongResistT PlayerLvl N=points Song Resist Rating
TacMasT PlayerLvl N=points Tactical Mastery Rating
TacMitT PlayerLvl N=points Tactical Mitigation
TacResistT PlayerLvl N=points Tactical Resist Rating
WoundResistT PlayerLvl N=points Wound Resist Rating

Health & Energy

Notes:

  • The N parameter should contain the number of stat points. Default for N is 1, so if you don't supply a specific number then you get the standard 1 point.
  • Health & Energy stat values are fractured numbers. Module:CalcStat applies the format %.0f as default, so fractured number format rounded to 0 decimals.
Item level stat
StatName L NorC Notes
Morale ItemLvl N=points Maximum Morale
ICMR ItemLvl N=points In-Combat Morale Regeneration
NCMR ItemLvl N=points Non-Combat Morale Regeneration
Power ItemLvl N=points Maximum Power
ICPR ItemLvl N=points In-Combat Power Regeneration
NCPR ItemLvl N=points Non-Combat Power Regeneration
Player level stat
StatName L NorC Notes
MoraleT PlayerLvl N=points Maximum Morale
ICMRT PlayerLvl N=points In-Combat Morale Regeneration
NCMRT PlayerLvl N=points Non-Combat Morale Regeneration
PowerT PlayerLvl N=points Maximum Power
ICPRT PlayerLvl N=points In-Combat Power Regeneration
NCPRT PlayerLvl N=points Non-Combat Power Regeneration
SkillPowerCost PlayerLvl N=points Skill use Power Cost[1]
  1. See Skill Power Cost Calculation for a table with cost values. If you know the value in the skill's tooltip then you can look it up in this table and determine the amount of points it represents.

Examples

Showing 3.5 points worth of Skill Power Cost at level cap.

[{{#invoke:CalcStat|calc|SkillPowerCost|{{Level Cap}}|3.5}} at Level {{Level Cap}}]

[471 at Level 150]

Showing Skill Power Cost at level cap for a channeled skill needs an additional format, because it needs to be rounded down (d takes the integer/whole number part only):

[{{#invoke:CalcStat|calc|SkillPowerCost|{{Level Cap}}|0.05|%'d}} at Level {{Level Cap}}]

[7 at Level 150]

Armour (on wearable items)

For armour on items we have 2 normalized stats, of which Armour is the most common used by far. Some lower level items can have a type which I call 'decrepit' armour. A kind of half functioning armour whatever. An example is this item: Item:Dannasen's Shirt. The StatName for this type of armour is ArmourLow. Furthermore, we have a 3rd depreciated / old stat armour which has the StatName 'ClothArmour'.

Item level stat
StatName L NorC Notes
Armour ItemLvl C=code Normal armour
ArmourLow ItemLvl C=code Decrepit armour
ClothArmour ItemLvl Id 1879073002

The normalized stats work with an 'ArmourCode', which is passed by using the C parameter (NorC). It's a letter code which consists out of 3 parts as shown in the table below. You need to choose one of the options for each position and just put them together in sequence. For example, rare medium gloves has the code MGP. A heavy incomparable shield is HShT.
Notes:

  • A special case is the CLoak/back item. This item is currently always medium(used to be light) and therefore doesn't have a category attached. These items are like CLP, CLG, etc.
  • The ArmourLow/Decrepit armour uses only 2 positions. It has it's own unique quality, so position 3 is omitted. Codes for these are like MC, HB, etc.
  • Armour on items is always a whole number (and should be displayed with a thousand separator, which should be specified in the format: %'d). The player level counterpart ArmourT behaves more like a rating and gives a fractured result (default format will be fine).
  • ClothArmour only needs the item level. No armour codes required. It's a very simple Armour value = item level up to a maximum of 50.
  • Be aware that the armour code for an item is not directly linked to how the item is displayed. Sometimes, SSG can make an error or wants to give less armour than is appropriate for the item. For instance, it has happened that gold cloaks (CLG) received the armour values for incomparable versions (CLT). I can't remember more than one quality level difference.
  • For shields: MSh, Medium Shield aka Warden Shield. LSh, Light Shield aka Shield (as for minstrels and captains). HSh, Heavy Shield.. yes.

Armour codes:

Position 1:
Category
L ight
M edium
H eavy

nothing for CLoak
Position 2:
Type/Slot
H elmet (head)
S houlders
CL oak (back)
C hest
G loves (hands)
L eggings (legs)
B oots (feet)
Sh ield
Position 3:
Quality
W hite (normal)
Y ellow (uncommon)
P urple (rare)
T eal (incomparable)
G old (epic)

nothing for Decrepit

Weapon Stats

These stats cover most weapons. Some low level weapons are on other progressions.

Item level stat
StatName L NorC Notes
CombatBaseTacDPS ItemLvl (Li2)Tactical Damage Rating
CombatBaseTacHPS ItemLvl (Li2)Tactical Healing Rating
CombatInHeal ItemLvl (Li2)Incoming Healing Rating (currently: @InHeal#2)
WpnDmgMax ItemLvl C=code (Physical) Weapon Damage Maximum
WpnDmgMin ItemLvl C=code (Physical) Weapon Damage Minimum
WpnDPS ItemLvl C=code (Physical) Weapon DPS

The physical weapon damage stats work with a 'WeaponCode', which is passed by using the C parameter (NorC). It's a letter code which consists out of 3 parts as shown in the table below. You need to choose one of the options for each position and just put them together in sequence. For example, a Li2(Legendary Item new style) bow has the code HBG.
Notes:

  • DPS for a bow is the same as for a two-hander. The difference is the larger variance (difference between min and max damage) in damage.
  • These weapon stats are all fractured numbers. Module:CalcStatTable applies format %'.0f, so fractured number format with thousand separator, to both WpnDmg stats. WpnDPS gets %'.1f which is like the others but with one decimal. Module:CalcStat treats them like any other number.

Weapon codes:

Position 1:
Category
L ight
H eavy
Position 2:
Type
B ow
O ne-handed
T wo-handed
Position 3:
Quality
W hite (normal)
Y ellow (uncommon)
P urple (rare)
T eal (incomparable)
G old (epic)

Class Data

CalcStat can provide various class related data/stats. The stats can be accessed by using a class name plus 'CD' (Class Data) as a prefix.
The following names are being used:

Class Name
Beorning
Brawler
Burglar
Captain
Champion
Guardian
Hunter
LoreMaster
Mariner
Minstrel
RuneKeeper
Warden

So for example, the correct prefix for a Rune-keeper would be: RuneKeeperCD

Class Data is usually provided in a flexible open way. For instance, a class might have some rating contribution from a main stat, but maybe it hasn't. CalcStat always returns a 0 value when a stat doesn't exists.
Statname postfixes are in a pattern. You need to provide (main) stat and rating stat names like they are in use elsewhere.

Last Part/Postfix Pattern L NorC Notes
<Stat1>To<Stat2> PlayerLvl Stat contribution factor to an other stat. Like MightToBlock, TacMasToOutHeal, FateToCritHit, VitalityToMorale, ArmourToTacMit, etc.
Base<Stat> PlayerLvl Base Stats are stats which you automatically get based on your level. Like BaseAgility, BasePower, BaseMorale, BaseICMR, etc.
HasPower PlayerLvl Normally 1, except for Beorning: 0.

Examples

Calculating the Fate to Critical Rating contribution factor for a Lore-master at player level 91.

{{#invoke:CalcStat|calc|LoreMasterCDFateToCritHit|91||%.0.2f|NoAdj}}

0

Calculating the Base ICMR for a Champion at player level 12.

{{#invoke:CalcStat|calc|ChampionCDBaseICMR|12||%.0.2f|NoAdj}}

0.2

Race Data

CalcStat can also provide a few race related data/stats. The stats can be accessed by using a race name plus 'RD' (Race Data) as a prefix.
The following names are being used:

Race Name
Beorning
Dwarf
Elf
HighElf
Hobbit
Man
Hunter
StoutAxe

So for example, the correct prefix for a Stout-axe would be: StoutAxeRD

Race Data is query based like Class Data.
Statname postfixes are in a pattern. You need to provide (main) stat and rating stat names like they are in use elsewhere.

Last Part/Postfix Pattern L NorC Notes
Trait<Stat> PlayerLvl These stats are an accumulation based on (passive) Racial Skills / Characteristics. Examples are TraitFate, TraitVitality, etc.

Examples

Calculating the Trait ICMR for a Dwarf at player level 10.

{{#invoke:CalcStat|calc|DwarfRDTraitICMR|10||%.0.2f|NoAdj}}

0.17

This stat is based on  Unwearying in Battle which can also be calculated with:

{{#invoke:CalcStat|calc|DwarfUnwearBattleICMR|10||%.0.2f|NoAdj}}

0.17


-- Created by Giseldah

local p = {}; --p stands for package

-- ****************************** Start CalcStat ******************************

-- Floating point numbers bring errors into the calculation, both inside the Lotro-client and in this function collection. This is why a 100% match with the stats in Lotro is impossible.
-- Anyway, to compensate for some errors, we use a calculation deviation correction value. This makes for instance 24.49999999 round to 25, as it's assumed that 24.5 was intended as outcome of a formula.
DblCalcDev = 0.00000001;

function CalcStat(SName, SLvl, SParam)

	-- process parameters and parameter defaults

	if type(SName) ~= "string" then
		return "Missing stat name";
	end
	local SN = string.match(SName:upper(),"^%s*(-?%a+%d*%a+)%s*$"); -- allow nested digits in stat name and a starting -
	if SN == nil then
		SN = string.match(SName,"^%s*(-?%a+)%s*$"); -- to allow single character stat name
		if SN == nil then
			return "Illegal stat name";
		end
	end
	SN = string.upper(SN);

	local L = 1; -- default L
	if type(SLvl) == "number" then
		L = SLvl;
	elseif type(SLvl) ~= "nil" then
		return "Illegal level";
	end
	local Lm = L-DblCalcDev;
	local Lp = L+DblCalcDev;

	local N = 1; -- default N
	local C = ""; -- default C
	if type(SParam) == "number" then
		N = SParam;
	elseif type(SParam) == "string" then
		C = SParam;
	elseif type(SParam) ~= "nil" then
		return "Illegal N or C";
	end

	-- binary search tree (generated code)

	if SN < "MINSTRELCDCALCTYPECOMPHYMIT" then
		if SN < "CREEPAUDACITYCOSTBASE" then
			if SN < "BRGTRICKCNTDEFBPE" then
				if SN < "BEORNINGCDBASEPOWER" then
					if SN < "AWARDILVLED" then
						if SN < "ARMQTYMP" then
							if SN < "ARMOURADJBYTYPE" then
								if SN < "ADJUMBARTRAITMIT" then
									if SN < "ACIDMITT" then
										if SN > "-VERSION" then
											if SN == "ACIDMIT" then
												return CalcStat("DmgTypeMit",L,N);
											else
												return 0;
											end
										elseif SN == "-VERSION" then
											return "2.3.4f";
										else
											return 0;
										end
									elseif SN > "ACIDMITT" then
										if SN < "ADJUMBARITEMMIT" then
											if SN == "ADJUMBARITEM" then
												if Lm <= 499 then
													return 1;
												else
													return 0.9;
												end
											else
												return 0;
											end
										elseif SN > "ADJUMBARITEMMIT" then
											if SN == "ADJUMBARTRAIT" then
												if Lm <= 140 then
													return 1;
												elseif Lm <= 150 then
													return 0.9;
												else
													return 1;
												end
											else
												return 0;
											end
										else
											if Lm <= 499 then
												return 1;
											elseif Lm <= 500 then
												return 0.78;
											else
												return 0.7;
											end
										end
									else
										return CalcStat("DmgTypeMitT",L,N);
									end
								elseif SN > "ADJUMBARTRAITMIT" then
									if SN < "ARMCATMP" then
										if SN < "AGILITYC" then
											if SN == "AGILITY" then
												return CalcStat("Main",L,N);
											else
												return 0;
											end
										elseif SN > "AGILITYC" then
											if SN == "AGILITYT" then
												return CalcStat("MainT",L,N);
											else
												return 0;
											end
										else
											return CalcStat("MainC",L,N);
										end
									elseif SN > "ARMCATMP" then
										if SN < "ARMOUR" then
											if SN == "ARMCATPROGB" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 1 then
													return CalcStat("ProgBArmourHeavy",N);
												elseif Lm <= 2 then
													return CalcStat("ProgBArmourMedium",N);
												else
													return CalcStat("ProgBArmourLight",N);
												end
											else
												return 0;
											end
										elseif SN > "ARMOUR" then
											if SN == "ARMOURADJ" then
												return CalcStat("ArmourAdjByType",ArmCodeIndex(C,2),L);
											else
												return 0;
											end
										else
											return RoundDblDown(StatLinInter("ArmourPntMP","ItemPntS","ArmourProgB","ArmourAdj",L,C,0));
										end
									else
										return CalcStat("PntMPArmour",L);
									end
								else
									if Lm <= 140 then
										return 1;
									elseif Lm <= 141 then
										return 0.78;
									else
										return 0.7;
									end
								end
							elseif SN > "ARMOURADJBYTYPE" then
								if SN < "ARMOURPENT" then
									if SN < "ARMOURC" then
										if SN < "ARMOURADJTYPEOTHER" then
											if SN == "ARMOURADJTYPECLOAK" then
												return CalcStat("AdjUmbarItemMit",L);
											else
												return 0;
											end
										elseif SN > "ARMOURADJTYPEOTHER" then
											if SN == "ARMOURADJTYPESHIELD" then
												return CalcStat("AdjUmbarItemMit",L);
											else
												return 0;
											end
										else
											return CalcStat("AdjUmbarItemMit",L);
										end
									elseif SN > "ARMOURC" then
										if SN < "ARMOURLOW" then
											if SN == "ARMOURCRAW" then
												return StatLinInter("PntMPArmourC","CreepPntS","ProgBArmourC","",L,N,99);
											else
												return 0;
											end
										elseif SN > "ARMOURLOW" then
											if SN == "ARMOURLOWPNTMP" then
												return CalcStat("ArmTypeMP",ArmCodeIndex(C,2))*CalcStat("ArmQtyLowMP",ArmCodeIndex(C,2))*CalcStat("ArmCatMP",ArmCodeIndex(C,1));
											else
												return 0;
											end
										else
											return RoundDblDown(StatLinInter("ArmourLowPntMP","ItemPntS","ArmourProgB","ArmourAdj",L,C,0));
										end
									else
										return StatLinInter("PntMPArmourC","CreepPntS","ProgBArmourC","",L,N,0);
									end
								elseif SN > "ARMOURPENT" then
									if SN < "ARMQTYCOMMMP" then
										if SN < "ARMOURPROGB" then
											if SN == "ARMOURPNTMP" then
												return CalcStat("ArmTypeMP",ArmCodeIndex(C,2))*CalcStat("ArmQtyMP",ArmCodeIndex(C,3),ArmCodeIndex(C,2))*CalcStat("ArmCatMP",ArmCodeIndex(C,1));
											else
												return 0;
											end
										elseif SN > "ARMOURPROGB" then
											if SN == "ARMOURT" then
												return StatLinInter("PntMPArmourT","TraitPntS","ProgBArmour","AdjUmbarTraitMit",L,N,0);
											else
												return 0;
											end
										else
											return CalcStat("ArmCatProgB",ArmCodeIndex(C,1),L);
										end
									elseif SN > "ARMQTYCOMMMP" then
										if SN < "ARMQTYINCOMPMP" then
											if SN == "ARMQTYEPICMP" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,1,1,1,1,1.002,1,1},L);
												end
											else
												return 0;
											end
										elseif SN > "ARMQTYINCOMPMP" then
											if SN == "ARMQTYLOWMP" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({0.3635,0.3635,0.3635,0.3635,0.3635,0.36215,0.3635,0.3635},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({28/30,28/30,0.95,0.95,0.94,0.948,0.95,0.95},L);
											end
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return DataTableValue({22/30,22/30,0.8,0.8,0.76,0.804,0.8,0.7},L);
										end
									end
								else
									return StatLinInter("PntMPArmourPenT","TraitPntS","ProgBArmour","",L,N,0);
								end
							else
								if 3 <= Lp and Lm <= 3 then
									return CalcStat("ArmourAdjTypeCloak",N);
								elseif 8 <= Lp and Lm <= 8 then
									return CalcStat("ArmourAdjTypeShield",N);
								else
									return CalcStat("ArmourAdjTypeOther",N);
								end
							end
						elseif SN > "ARMQTYMP" then
							if SN < "AWARDILVLCC" then
								if SN < "AWARDILVLAC" then
									if SN < "AUTOLVLTOILVL" then
										if SN < "ARMQTYUNCOMMP" then
											if SN == "ARMQTYRAREMP" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({26/30,26/30,0.9,0.9,0.88,0.9,0.9,0.8},L);
												end
											else
												return 0;
											end
										elseif SN > "ARMQTYUNCOMMP" then
											if SN == "ARMTYPEMP" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({9,9,20,30,15,25,12,32.726},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({22/30,22/30,0.85,0.85,0.82,0.852,0.85,0.75},L);
											end
										end
									elseif SN > "AUTOLVLTOILVL" then
										if SN < "AWARDILVLAA" then
											if SN == "AWARDILVLA" then
												if Lm <= 75 then
													return L;
												elseif Lm <= 94 then
													return 5*L-304;
												elseif Lm <= 95 then
													return 173;
												elseif Lm <= 100 then
													return 5*L-304;
												elseif Lm <= 101 then
													return 197;
												elseif Lm <= 104 then
													return 4*L-206;
												elseif Lm <= 105 then
													return 218;
												elseif Lm <= 110 then
													return RoundDbl(LinFmod(1,295,303.8,106,110,L));
												elseif Lm <= 115 then
													return 304;
												elseif Lm <= 119 then
													return RoundDbl(LinFmod(1,345,357,116,119,L));
												elseif Lm <= 120 then
													return 359;
												elseif Lm <= 130 then
													return 395;
												elseif Lm <= 140 then
													return RoundDbl(LinFmod(1,445.4,455.4,131,140,L));
												elseif Lm <= 150 then
													return RoundDbl(LinFmod(1,479.4,491.4,141,150,L));
												else
													return CalcStat("AwardILvlA",150);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLAA" then
											if SN == "AWARDILVLAB" then
												if 75 <= Lp and Lm <= 75 then
													return CalcStat("AwardILvlA",L)+1;
												else
													return CalcStat("AwardILvlA",L);
												end
											else
												return 0;
											end
										else
											if 75 <= Lp and Lm <= 75 then
												return CalcStat("AwardILvlA",L)+3;
											else
												return CalcStat("AwardILvlA",L);
											end
										end
									else
										return CalcStat("AwardILvlCC",L);
									end
								elseif SN > "AWARDILVLAC" then
									if SN < "AWARDILVLBOLD" then
										if SN < "AWARDILVLB" then
											if SN == "AWARDILVLAOLD" then
												return CalcStat("AwardILvlA",L);
											else
												return 0;
											end
										elseif SN > "AWARDILVLB" then
											if SN == "AWARDILVLBA" then
												return CalcStat("AwardILvlB",L);
											else
												return 0;
											end
										else
											if Lm <= 4 then
												return CalcStat("AwardILvlA",1);
											elseif Lm <= 50 then
												return CalcStat("AwardILvlA",L-4);
											elseif Lm <= 54 then
												return CalcStat("AwardILvlA",51);
											elseif Lm <= 75 then
												return CalcStat("AwardILvlA",L-4);
											elseif Lm <= 95 then
												return CalcStat("AwardILvlA",L)+4;
											else
												return CalcStat("AwardILvlA",L);
											end
										end
									elseif SN > "AWARDILVLBOLD" then
										if SN < "AWARDILVLCA" then
											if SN == "AWARDILVLC" then
												if Lm <= 75 then
													return CalcStat("AwardILvlB",L);
												else
													return CalcStat("AwardILvlA",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLCA" then
											if SN == "AWARDILVLCB" then
												if 96 <= Lp and Lm <= 99 then
													return CalcStat("AwardILvlC",L)+4;
												elseif 100 <= Lp and Lm <= 100 then
													return CalcStat("AwardILvlC",L)+6;
												else
													return CalcStat("AwardILvlC",L);
												end
											else
												return 0;
											end
										else
											if 96 <= Lp and Lm <= 100 then
												return CalcStat("AwardILvlC",L)+4;
											else
												return CalcStat("AwardILvlC",L);
											end
										end
									else
										return CalcStat("AwardILvlB",L);
									end
								else
									if 75 <= Lp and Lm <= 75 then
										return CalcStat("AwardILvlA",L)+2;
									else
										return CalcStat("AwardILvlA",L);
									end
								end
							elseif SN > "AWARDILVLCC" then
								if SN < "AWARDILVLDD" then
									if SN < "AWARDILVLD" then
										if SN < "AWARDILVLCE" then
											if SN == "AWARDILVLCD" then
												if 101 <= Lp and Lm <= 105 then
													return CalcStat("AwardILvlC",L)+4;
												else
													return CalcStat("AwardILvlC",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLCE" then
											if SN == "AWARDILVLCF" then
												if Lm <= 140 then
													return CalcStat("AwardILvlC",L);
												elseif Lm <= 150 then
													return RoundDbl(LinFmod(1,500.4,517.4,141,150,L));
												else
													return CalcStat("AwardILvlCF",150);
												end
											else
												return 0;
											end
										else
											if Lm <= 140 then
												return CalcStat("AwardILvlC",L);
											elseif Lm <= 150 then
												return RoundDbl(LinFmod(1,500.4,512.4,141,150,L));
											else
												return CalcStat("AwardILvlCE",150);
											end
										end
									elseif SN > "AWARDILVLD" then
										if SN < "AWARDILVLDB" then
											if SN == "AWARDILVLDA" then
												if 106 <= Lp and Lm <= 115 then
													return RoundDbl(LinFmod(1,300,336.5,106,115,L));
												else
													return CalcStat("AwardILvlD",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLDB" then
											if SN == "AWARDILVLDC" then
												if 106 <= Lp and Lm <= 110 then
													return RoundDbl(LinFmod(1,300,320,106,115,L));
												elseif 111 <= Lp and Lm <= 115 then
													return CalcStat("AwardILvlDC",110);
												else
													return CalcStat("AwardILvlD",L);
												end
											else
												return 0;
											end
										else
											if 106 <= Lp and Lm <= 115 then
												return RoundDbl(LinFmod(1,300,345,106,115,L));
											else
												return CalcStat("AwardILvlD",L);
											end
										end
									else
										if Lm <= 105 then
											return CalcStat("AwardILvlC",L);
										elseif Lm <= 115 then
											return 300;
										else
											return CalcStat("AwardILvlA",L);
										end
									end
								elseif SN > "AWARDILVLDD" then
									if SN < "AWARDILVLE" then
										if SN < "AWARDILVLDF" then
											if SN == "AWARDILVLDE" then
												if 106 <= Lp and Lm <= 115 then
													return RoundDbl(LinFmod(1,300.4,326.4,106,115,L));
												else
													return CalcStat("AwardILvlD",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLDF" then
											if SN == "AWARDILVLDG" then
												if 106 <= Lp and Lm <= 114 then
													return RoundDbl(LinFmod(1,300,336,106,115,L));
												elseif 115 <= Lp and Lm <= 115 then
													return CalcStat("AwardILvlD",115)+40;
												else
													return CalcStat("AwardILvlD",L);
												end
											else
												return 0;
											end
										else
											if 106 <= Lp and Lm <= 110 then
												return CalcStat("AwardILvlDF",111);
											elseif 111 <= Lp and Lm <= 115 then
												return RoundDbl(LinFmod(1,299.5,320.5,106,115,L));
											else
												return CalcStat("AwardILvlD",L);
											end
										end
									elseif SN > "AWARDILVLE" then
										if SN < "AWARDILVLEB" then
											if SN == "AWARDILVLEA" then
												if 116 <= Lp and Lm <= 119 then
													return RoundDbl(LinFmod(1,350,378,116,120,L));
												elseif 120 <= Lp and Lm <= 120 then
													return CalcStat("AwardILvlE",120)+26;
												else
													return CalcStat("AwardILvlE",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLEB" then
											if SN == "AWARDILVLEC" then
												if 116 <= Lp and Lm <= 120 then
													return RoundDbl(LinFmod(1,350,382,116,120,L));
												else
													return CalcStat("AwardILvlE",L);
												end
											else
												return 0;
											end
										else
											if 116 <= Lp and Lm <= 119 then
												return RoundDbl(LinFmod(1,350,390,116,120,L));
											elseif 120 <= Lp and Lm <= 120 then
												return CalcStat("AwardILvlE",120)+38;
											else
												return CalcStat("AwardILvlE",L);
											end
										end
									else
										if Lm <= 115 then
											return CalcStat("AwardILvlC",L);
										elseif Lm <= 120 then
											return 350;
										else
											return CalcStat("AwardILvlA",L);
										end
									end
								else
									if 106 <= Lp and Lm <= 114 then
										return RoundDbl(LinFmod(1,300,327,106,115,L));
									elseif 115 <= Lp and Lm <= 115 then
										return CalcStat("AwardILvlD",115)+30;
									else
										return CalcStat("AwardILvlD",L);
									end
								end
							else
								return CalcStat("AwardILvlC",L);
							end
						else
							if Lm <= 0 then
								return 0;
							elseif Lm <= 1 then
								return CalcStat("ArmQtyCommMP",N);
							elseif Lm <= 2 then
								return CalcStat("ArmQtyUncomMP",N);
							elseif Lm <= 3 then
								return CalcStat("ArmQtyRareMP",N);
							elseif Lm <= 4 then
								return CalcStat("ArmQtyIncompMP",N);
							else
								return CalcStat("ArmQtyEpicMP",N);
							end
						end
					elseif SN > "AWARDILVLED" then
						if SN < "BASEMAINPROG" then
							if SN < "AWARDILVLJ" then
								if SN < "AWARDILVLGB" then
									if SN < "AWARDILVLFA" then
										if SN > "AWARDILVLEE" then
											if SN == "AWARDILVLF" then
												if Lm <= 40 then
													return LinFmod(1,1,40,1,40,L);
												elseif Lm <= 41 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 49 then
													return LinFmod(1,41,48,42,49,L);
												elseif Lm <= 50 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 55 then
													return LinFmod(1,51,55,51,55,L);
												elseif Lm <= 56 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 59 then
													return LinFmod(1,56,58,57,59,L);
												elseif Lm <= 60 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 64 then
													return RoundDbl(LinFmod(1,60.6,63,61,64,L));
												elseif Lm <= 65 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 70 then
													return LinFmod(1,66,70,66,70,L);
												elseif Lm <= 71 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 74 then
													return LinFmod(1,71,73,72,74,L);
												elseif Lm <= 75 then
													return CalcStat("AwardILvlF",L-1);
												elseif Lm <= 85 then
													return RoundDbl(LinFmod(1,80.4,123.4,76,85,L));
												elseif Lm <= 94 then
													return RoundDbl(LinFmod(1,130,169,86,94,L));
												elseif Lm <= 100 then
													return RoundDbl(LinFmod(1,175,198.4,95,100,L));
												elseif Lm <= 104 then
													return LinFmod(1,201,213,101,104,L);
												elseif Lm <= 105 then
													return 220;
												elseif Lm <= 114 then
													return RoundDbl(LinFmod(1,300,323,106,114,L));
												elseif Lm <= 115 then
													return 324;
												elseif Lm <= 119 then
													return RoundDbl(LinFmod(1,349.6,368.4,116,120,L));
												elseif Lm <= 120 then
													return 380;
												elseif Lm <= 125 then
													return RoundDbl(LinFmod(1,400.4,416.4,121,125,L));
												elseif Lm <= 129 then
													return RoundDbl(LinFmod(1,418.4,430.4,126,129,L));
												elseif Lm <= 130 then
													return 432;
												elseif Lm <= 135 then
													return RoundDbl(LinFmod(1,450.4,463.8,131,135,L));
												elseif Lm <= 138 then
													return RoundDbl(LinFmod(1,466,472.5,136,138,L));
												else
													return 475;
												end
											else
												return 0;
											end
										elseif SN == "AWARDILVLEE" then
											if 116 <= Lp and Lm <= 119 then
												return RoundDbl(LinFmod(1,350,366,116,120,L));
											elseif 120 <= Lp and Lm <= 120 then
												return CalcStat("AwardILvlE",120)+14;
											else
												return CalcStat("AwardILvlE",L);
											end
										else
											return 0;
										end
									elseif SN > "AWARDILVLFA" then
										if SN < "AWARDILVLG" then
											if SN == "AWARDILVLFB" then
												if Lm <= 140 then
													return CalcStat("AwardILvlF",L);
												elseif Lm <= 150 then
													return RoundDbl(LinFmod(1,500.4,513.4,141,150,L));
												else
													return CalcStat("AwardILvlFB",150);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLG" then
											if SN == "AWARDILVLGA" then
												if 121 <= Lp and Lm <= 130 then
													return RoundDbl(LinFmod(1,400.4,412.4,121,130,L));
												else
													return CalcStat("AwardILvlG",L);
												end
											else
												return 0;
											end
										else
											if Lm <= 120 then
												return CalcStat("AwardILvlC",L);
											elseif Lm <= 130 then
												return 400;
											else
												return CalcStat("AwardILvlA",L);
											end
										end
									else
										if Lm <= 140 then
											return CalcStat("AwardILvlF",L);
										else
											return 500;
										end
									end
								elseif SN > "AWARDILVLGB" then
									if SN < "AWARDILVLGF" then
										if SN < "AWARDILVLGD" then
											if SN == "AWARDILVLGC" then
												if 121 <= Lp and Lm <= 130 then
													return RoundDbl(LinFmod(1,400.4,408.3,121,130,L));
												else
													return CalcStat("AwardILvlG",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLGD" then
											if SN == "AWARDILVLGE" then
												if 121 <= Lp and Lm <= 130 then
													return RoundDbl(LinFmod(1,400.4,434.4,121,130,L));
												else
													return CalcStat("AwardILvlG",L);
												end
											else
												return 0;
											end
										else
											if 121 <= Lp and Lm <= 130 then
												return RoundDbl(LinFmod(1,400.4,426.4,121,130,L));
											else
												return CalcStat("AwardILvlG",L);
											end
										end
									elseif SN > "AWARDILVLGF" then
										if SN < "AWARDILVLI" then
											if SN == "AWARDILVLH" then
												if Lm <= 4 then
													return CalcStat("AwardILvlA",1);
												elseif Lm <= 50 then
													return CalcStat("AwardILvlA",L-4);
												elseif Lm <= 54 then
													return CalcStat("AwardILvlA",51);
												elseif Lm <= 75 then
													return CalcStat("AwardILvlA",L-4);
												else
													return L-4;
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLI" then
											if SN == "AWARDILVLIA" then
												if Lm <= 44 then
													return CalcStat("AwardILvlI",L);
												elseif Lm <= 55 then
													return RoundDblDown((L-45)/6)+51;
												elseif Lm <= 90 then
													return CalcStat("AwardILvlI",L);
												elseif Lm <= 104 then
													return RoundDblDown((L-91)/5)*25+165;
												elseif Lm <= 105 then
													return CalcStat("LvlToILvl",L);
												elseif Lm <= 110 then
													return CalcStat("LvlToILvl",106)+15;
												elseif Lm <= 115 then
													return CalcStat("LvlToILvl",115)-20;
												elseif Lm <= 120 then
													return CalcStat("LvlToILvl",116)+15;
												elseif Lm <= 125 then
													return CalcStat("LvlToILvl",121)+15;
												elseif Lm <= 130 then
													return CalcStat("LvlToILvl",130)-20;
												elseif Lm <= 135 then
													return CalcStat("LvlToILvl",131)+15;
												elseif Lm <= 140 then
													return CalcStat("LvlToILvl",140)-4;
												elseif Lm <= 150 then
													return CalcStat("LvlToILvl",141)+15;
												else
													return CalcStat("AwardILvlIA",150);
												end
											else
												return 0;
											end
										else
											if Lm <= 44 then
												return 1;
											elseif Lm <= 55 then
												return 52;
											elseif Lm <= 75 then
												return RoundDblDown((L-56)/5)*5+60;
											elseif Lm <= 85 then
												return RoundDblDown((L-76)/5)*29+100;
											elseif Lm <= 95 then
												return RoundDblDown((L-86)/5)*20+155;
											elseif Lm <= 100 then
												return RoundDblDown((L-96)/4)*10+190;
											elseif Lm <= 105 then
												return RoundDblDown((L-101)/4)*35+215;
											elseif Lm <= 110 then
												return CalcStat("LvlToILvl",106)+15;
											elseif Lm <= 115 then
												return CalcStat("LvlToILvl",115);
											elseif Lm <= 119 then
												return CalcStat("LvlToILvl",116)+15;
											elseif Lm <= 120 then
												return CalcStat("LvlToILvl",120);
											elseif Lm <= 125 then
												return CalcStat("LvlToILvl",121)+15;
											elseif Lm <= 130 then
												return CalcStat("LvlToILvl",130);
											elseif Lm <= 135 then
												return CalcStat("LvlToILvl",131)+15;
											elseif Lm <= 140 then
												return CalcStat("LvlToILvl",140);
											elseif Lm <= 145 then
												return CalcStat("LvlToILvl",141)+15;
											elseif Lm <= 150 then
												return CalcStat("LvlToILvl",150);
											else
												return CalcStat("AwardILvlI",150);
											end
										end
									else
										if 121 <= Lp and Lm <= 130 then
											return RoundDbl(LinFmod(1,400.4,440.4,121,130,L));
										else
											return CalcStat("AwardILvlG",L);
										end
									end
								else
									if 121 <= Lp and Lm <= 130 then
										return RoundDbl(LinFmod(1,400.4,418.4,121,130,L));
									else
										return CalcStat("AwardILvlG",L);
									end
								end
							elseif SN > "AWARDILVLJ" then
								if SN < "AXEARMRENDPOS" then
									if SN < "AWARDILVLJD" then
										if SN < "AWARDILVLJB" then
											if SN == "AWARDILVLJA" then
												if 131 <= Lp and Lm <= 140 then
													return RoundDbl(LinFmod(1,450.4,465.4,131,140,L));
												else
													return CalcStat("AwardILvlJ",L);
												end
											else
												return 0;
											end
										elseif SN > "AWARDILVLJB" then
											if SN == "AWARDILVLJC" then
												if 131 <= Lp and Lm <= 140 then
													return RoundDbl(LinFmod(1,450.4,475.4,131,140,L));
												else
													return CalcStat("AwardILvlJ",L);
												end
											else
												return 0;
											end
										else
											if 131 <= Lp and Lm <= 140 then
												return RoundDbl(LinFmod(1,450.4,470.4,131,140,L));
											else
												return CalcStat("AwardILvlJ",L);
											end
										end
									elseif SN > "AWARDILVLJD" then
										if SN < "AWARDLVLTOILVL" then
											if SN == "AWARDLVLCAP" then
												return 150;
											else
												return 0;
											end
										elseif SN > "AWARDLVLTOILVL" then
											if SN == "AXEARMOURREND" then
												return -CalcStat("AxeArmRendPos",L);
											else
												return 0;
											end
										else
											return CalcStat("AwardILvlC",L);
										end
									else
										if 131 <= Lp and Lm <= 140 then
											return RoundDbl(LinFmod(1,450.4,480.4,131,140,L));
										else
											return CalcStat("AwardILvlJ",L);
										end
									end
								elseif SN > "AXEARMRENDPOS" then
									if SN < "BASEAGILITY" then
										if SN < "BALANCEOFMANEVADE" then
											if SN == "BALANCEOFMANBLOCK" then
												return CalcStat("BlockT",L,0.8);
											else
												return 0;
											end
										elseif SN > "BALANCEOFMANEVADE" then
											if SN == "BALANCEOFMANPARRY" then
												return CalcStat("ParryT",L,0.8);
											else
												return 0;
											end
										else
											return CalcStat("EvadeT",L,1.0);
										end
									elseif SN > "BASEAGILITY" then
										if SN < "BASEFATE" then
											if SN == "BASEARMOUR" then
												if Lm <= 50 then
													return RoundDblUp(LinFmod(1,1,10,1,50,L)*N);
												elseif Lm <= 60 then
													return RoundDblUp(LinFmod(1,10,15,50,60,L)*N);
												elseif Lm <= 65 then
													return RoundDblUp(LinFmod(1,15,20,60,65,L)*N);
												elseif Lm <= 75 then
													return RoundDblUp(LinFmod(1,20,30,65,75,L)*N);
												elseif Lm <= 85 then
													return RoundDblUp(LinFmod(1,30,45,75,85,L)*N);
												elseif Lm <= 95 then
													return RoundDblUp(LinFmod(1,45,65,85,95,L)*N);
												elseif Lm <= 100 then
													return RoundDblUp(LinFmod(1,65,100,95,100,L)*N);
												elseif Lm <= 105 then
													return RoundDblUp(LinFmod(1,100,130,100,105,L)*N);
												elseif Lm <= 115 then
													return RoundDblUp(LinFmod(1,143,200,106,115,L,0)*N);
												elseif Lm <= 120 then
													return RoundDblUp(LinFmod(1,230,250,116,120,L,0)*N);
												elseif Lm <= 130 then
													return RoundDblUp(LinFmod(1,288,380,121,130,L,0)*N);
												elseif Lm <= 140 then
													return RoundDblUp(LinFmod(1,440,750,131,140,L,0)*N);
												else
													return CalcStat("BaseArmour",140,N);
												end
											else
												return 0;
											end
										elseif SN > "BASEFATE" then
											if SN == "BASEMAIN" then
												if Lm <= 50 then
													return RoundDbl(CalcStat("BaseMainProg",L)*1*N);
												elseif Lm <= 95 then
													return RoundDbl(CalcStat("BaseMainProg",L)*1*N);
												else
													return RoundDbl(CalcStat("BaseMainProg",L)*1*N);
												end
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return RoundDbl(CalcStat("ProgBEnergy",L)*3.5);
											elseif Lm <= 95 then
												return RoundDbl(CalcStat("ProgBEnergy",L)*3.5);
											else
												return RoundDbl(CalcStat("BasePower",L)*0.7);
											end
										end
									else
										return CalcStat("BaseMain",L,N);
									end
								else
									if Lm <= 7 then
										return RoundDbl(LinFmod(1,0.5,3.25,1,7,L));
									elseif Lm <= 14 then
										return RoundDbl(LinFmod(1,3.75,8.5,8,14,L));
									elseif Lm <= 30 then
										return RoundDbl(LinFmod(1,9,24.7,15,30,L));
									elseif Lm <= 39 then
										return RoundDbl(LinFmod(1,26.5,37,31,39,L));
									elseif Lm <= 50 then
										return RoundDbl(LinFmod(1,38.5,53,40,50,L));
									elseif Lm <= 52 then
										return 53;
									elseif Lm <= 60 then
										return RoundDbl(LinFmod(1,53.2,64.8,53,60,L));
									elseif Lm <= 77 then
										return RoundDbl(LinFmod(1,66.15,94.8,61,77,L));
									elseif Lm <= 113 then
										return RoundDbl(RoundDbl(L/3-0.5)*1.95+44.1);
									elseif Lm <= 141 then
										return 116;
									elseif Lm <= 181 then
										return RoundDbl(RoundDbl(L/4)*2+46);
									elseif Lm <= 217 then
										return RoundDbl(RoundDbl(L/4)*2+45);
									elseif Lm <= 221 then
										return 153;
									elseif Lm <= 299 then
										return 155;
									elseif Lm <= 308 then
										return RoundDbl(RoundDbl(L/2.6-0.4)*2-73);
									elseif Lm <= 317 then
										return RoundDbl(RoundDbl(L/2.74-0.75)*2-60);
									elseif Lm <= 325 then
										return 172;
									elseif Lm <= 326 then
										return 174;
									elseif Lm <= 599 then
										return ExpFmod(CalcStat("AxeArmRendPos",326),327,1,L,1);
									else
										return CalcStat("AxeArmRendPos",599);
									end
								end
							else
								if Lm <= 130 then
									return CalcStat("AwardILvlC",L);
								elseif Lm <= 140 then
									return RoundDbl(LinFmod(1,450.4,460.4,131,140,L));
								else
									return CalcStat("AwardILvlA",L);
								end
							end
						elseif SN > "BASEMAINPROG" then
							if SN < "BEORNINGCDAGILITYTOEVADE" then
								if SN < "BATTLELORETACMAS" then
									if SN < "BASEVITALITY" then
										if SN < "BASEMORALE" then
											if SN == "BASEMIGHT" then
												return CalcStat("BaseMain",L,N);
											else
												return 0;
											end
										elseif SN > "BASEMORALE" then
											if SN == "BASEPOWER" then
												if Lm <= 50 then
													return RoundDblDown(CalcStat("ProgBEnergy",L)*5);
												elseif Lm <= 95 then
													return RoundDblDown(CalcStat("ProgBEnergy",L)*5);
												else
													return RoundDbl(CalcStat("ProgBEnergy",L)*5);
												end
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return RoundDblDown(CalcStat("ProgBHealth",L)*5);
											elseif Lm <= 95 then
												return RoundDbl(CalcStat("ProgBHealth",L)*5);
											else
												return RoundDbl(CalcStat("ProgBHealth",L)*5,-1);
											end
										end
									elseif SN > "BASEVITALITY" then
										if SN < "BATTLELOREMAS" then
											if SN == "BASEWILL" then
												return CalcStat("BaseMain",L,N);
											else
												return 0;
											end
										elseif SN > "BATTLELOREMAS" then
											if SN == "BATTLELOREPHYMAS" then
												return CalcStat("BattleLoreMas",L);
											else
												return 0;
											end
										else
											if Lm <= 105 then
												return CalcStat("Mastery",L,2.5);
											elseif Lm <= 119 then
												return CalcStat("MasteryT",L,1.2);
											elseif Lm <= 120 then
												return CalcStat("MasteryT",L,1.6);
											elseif Lm <= 129 then
												return CalcStat("MasteryT",L,1.2);
											elseif Lm <= 130 then
												return CalcStat("MasteryT",L,1.6);
											elseif Lm <= 139 then
												return CalcStat("MasteryT",L,1.2);
											else
												return CalcStat("MasteryT",L,1.6);
											end
										end
									else
										if Lm <= 50 then
											return RoundDbl(CalcStat("ProgBHealth",L)*0.75);
										elseif Lm <= 95 then
											return RoundDbl(CalcStat("ProgBHealth",L)*0.75);
										else
											return RoundDbl(CalcStat("BaseMorale",L)*0.15);
										end
									end
								elseif SN > "BATTLELORETACMAS" then
									if SN < "BEOFERALPRESFATE" then
										if SN < "BEOEMISSARYFATE" then
											if SN == "BEOBEARFORMCRITDEF" then
												return CalcStat("CritDefT",L,0.4);
											else
												return 0;
											end
										elseif SN > "BEOEMISSARYFATE" then
											if SN == "BEOFATE" then
												return CalcStat("FateT",L,CalcStat("Trait567810Choice",N)*0.4);
											else
												return 0;
											end
										else
											return CalcStat("FateT",L,1.0);
										end
									elseif SN > "BEOFERALPRESFATE" then
										if SN < "BEOMIGHTOFTHEWILDMIGHT" then
											if SN == "BEOFEWINNUMBERFATE" then
												return -CalcStat("FateT",L,0.4);
											else
												return 0;
											end
										elseif SN > "BEOMIGHTOFTHEWILDMIGHT" then
											if SN == "BEORNINGCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										else
											return CalcStat("MightT",L,1.0);
										end
									else
										return CalcStat("FateT",L,1.0);
									end
								else
									return CalcStat("BattleLoreMas",L);
								end
							elseif SN > "BEORNINGCDAGILITYTOEVADE" then
								if SN < "BEORNINGCDBASEAGILITY" then
									if SN < "BEORNINGCDARMOURTOCOMPHYMIT" then
										if SN < "BEORNINGCDAGILITYTOOUTHEAL" then
											if SN == "BEORNINGCDAGILITYTOFINESSE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDAGILITYTOOUTHEAL" then
											if SN == "BEORNINGCDAGILITYTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "BEORNINGCDARMOURTOCOMPHYMIT" then
										if SN < "BEORNINGCDARMOURTOTACMIT" then
											if SN == "BEORNINGCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDARMOURTOTACMIT" then
											if SN == "BEORNINGCDARMOURTYPE" then
												return 3;
											else
												return 0;
											end
										else
											return 0.2;
										end
									else
										return 1;
									end
								elseif SN > "BEORNINGCDBASEAGILITY" then
									if SN < "BEORNINGCDBASEMIGHT" then
										if SN < "BEORNINGCDBASEICMR" then
											if SN == "BEORNINGCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										elseif SN > "BEORNINGCDBASEICMR" then
											if SN == "BEORNINGCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICMRM",L);
										end
									elseif SN > "BEORNINGCDBASEMIGHT" then
										if SN < "BEORNINGCDBASENCMR" then
											if SN == "BEORNINGCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										elseif SN > "BEORNINGCDBASENCMR" then
											if SN == "BEORNINGCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCMRM",L);
										end
									else
										return CalcStat("ClassBaseMightM",L);
									end
								else
									return CalcStat("ClassBaseAgilityM",L);
								end
							else
								return 1;
							end
						else
							if Lm <= 95 then
								return CalcStat("StdProg",L,1.0);
							elseif Lm <= 140 then
								return RoundDbl(CalcStat("StdProg",L,1.0));
							else
								return RoundDbl(LinFmod(1,780,1360,141,150,L));
							end
						end
					else
						if 116 <= Lp and Lm <= 120 then
							return RoundDbl(LinFmod(1,350,370,116,120,L));
						else
							return CalcStat("AwardILvlE",L);
						end
					end
				elseif SN > "BEORNINGCDBASEPOWER" then
					if SN < "BPET" then
						if SN < "BEORNINGRDPSVTWONAME" then
							if SN < "BEORNINGCDMIGHTTOPHYMIT" then
								if SN < "BEORNINGCDFATETOICMR" then
									if SN < "BEORNINGCDCALCTYPECOMPHYMIT" then
										if SN > "BEORNINGCDBASEVITALITY" then
											if SN == "BEORNINGCDBASEWILL" then
												return CalcStat("ClassBaseWillM",L);
											else
												return 0;
											end
										elseif SN == "BEORNINGCDBASEVITALITY" then
											return CalcStat("ClassBaseVitality",L);
										else
											return 0;
										end
									elseif SN > "BEORNINGCDCALCTYPECOMPHYMIT" then
										if SN < "BEORNINGCDCALCTYPETACMIT" then
											if SN == "BEORNINGCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDCALCTYPETACMIT" then
											if SN == "BEORNINGCDCANBLOCK" then
												if Lm <= 5 then
													return 0;
												else
													return 1;
												end
											else
												return 0;
											end
										else
											return 27;
										end
									else
										return 14;
									end
								elseif SN > "BEORNINGCDFATETOICMR" then
									if SN < "BEORNINGCDMIGHTTOEVADE" then
										if SN < "BEORNINGCDFATETONCMR" then
											if SN == "BEORNINGCDFATETOMORALE" then
												return 2.5;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDFATETONCMR" then
											if SN == "BEORNINGCDMIGHTTOCRITHIT" then
												return 1;
											else
												return 0;
											end
										else
											return 0.12;
										end
									elseif SN > "BEORNINGCDMIGHTTOEVADE" then
										if SN < "BEORNINGCDMIGHTTOPARRY" then
											if SN == "BEORNINGCDMIGHTTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDMIGHTTOPARRY" then
											if SN == "BEORNINGCDMIGHTTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 2;
									end
								else
									return 0.04;
								end
							elseif SN > "BEORNINGCDMIGHTTOPHYMIT" then
								if SN < "BEORNINGCDWILLTOFINESSE" then
									if SN < "BEORNINGCDTACMASTOOUTHEAL" then
										if SN < "BEORNINGCDPHYMITTOCOMPHYMIT" then
											if SN == "BEORNINGCDMIGHTTOTACMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDPHYMITTOCOMPHYMIT" then
											if SN == "BEORNINGCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BEORNINGCDTACMASTOOUTHEAL" then
										if SN < "BEORNINGCDVITALITYTOMORALE" then
											if SN == "BEORNINGCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDVITALITYTOMORALE" then
											if SN == "BEORNINGCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										else
											return 4.5;
										end
									else
										return 1;
									end
								elseif SN > "BEORNINGCDWILLTOFINESSE" then
									if SN < "BEORNINGCDWILLTORESIST" then
										if SN < "BEORNINGCDWILLTOPHYMAS" then
											if SN == "BEORNINGCDWILLTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BEORNINGCDWILLTOPHYMAS" then
											if SN == "BEORNINGCDWILLTOPHYMIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BEORNINGCDWILLTORESIST" then
										if SN < "BEORNINGRDPSVONEFATE" then
											if SN == "BEORNINGCDWILLTOTACMIT" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "BEORNINGRDPSVONEFATE" then
											if SN == "BEORNINGRDPSVONENAME" then
												return "Emissary";
											else
												return 0;
											end
										else
											return CalcStat("BeoEmissaryFate",L);
										end
									else
										return 1;
									end
								else
									return 1;
								end
							else
								return 1;
							end
						elseif SN > "BEORNINGRDPSVTWONAME" then
							if SN < "BLOCKPRATPA" then
								if SN < "BLACKARROWCDCALCTYPENONPHYMIT" then
									if SN < "BEOTHICKHIDEVITALITY" then
										if SN < "BEORNINGRDTRAITMIGHT" then
											if SN == "BEORNINGRDTRAITFATE" then
												return CalcStat("BeoFewinNumberFate",L);
											else
												return 0;
											end
										elseif SN > "BEORNINGRDTRAITMIGHT" then
											if SN == "BEORNINGRDTRAITVITALITY" then
												return CalcStat("BeoThickHideVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("BeoMightoftheWildMight",L);
										end
									elseif SN > "BEOTHICKHIDEVITALITY" then
										if SN < "BLACKARROWCANBLOCK" then
											if SN == "BEOVITALITYINCREASE" then
												return CalcStat("VitalityT",L,CalcStat("Trait567810Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "BLACKARROWCANBLOCK" then
											if SN == "BLACKARROWCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return CalcStat("VitalityT",L,1.0);
									end
								elseif SN > "BLACKARROWCDCALCTYPENONPHYMIT" then
									if SN < "BLOCKC" then
										if SN < "BLACKARROWCDHASPOWER" then
											if SN == "BLACKARROWCDCALCTYPETACMIT" then
												return 27;
											else
												return 0;
											end
										elseif SN > "BLACKARROWCDHASPOWER" then
											if SN == "BLOCK" then
												return CalcStat("BPE",L,N);
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BLOCKC" then
										if SN < "BLOCKPPRAT" then
											if SN == "BLOCKPBONUS" then
												return CalcStat("BPEPBonus",L);
											else
												return 0;
											end
										elseif SN > "BLOCKPPRAT" then
											if SN == "BLOCKPRATP" then
												return CalcStat("BPEPRatP",L,N);
											else
												return 0;
											end
										else
											return CalcStat("BPEPPRat",L,N);
										end
									else
										return CalcStat("BPEC",L,N);
									end
								else
									return 14;
								end
							elseif SN > "BLOCKPRATPA" then
								if SN < "BPEPBONUS" then
									if SN < "BLOCKPRATPCAPR" then
										if SN < "BLOCKPRATPC" then
											if SN == "BLOCKPRATPB" then
												return CalcStat("BPEPRatPB",L);
											else
												return 0;
											end
										elseif SN > "BLOCKPRATPC" then
											if SN == "BLOCKPRATPCAP" then
												return CalcStat("BPEPRatPCap",L);
											else
												return 0;
											end
										else
											return CalcStat("BPEPRatPC",L);
										end
									elseif SN > "BLOCKPRATPCAPR" then
										if SN < "BPE" then
											if SN == "BLOCKT" then
												return CalcStat("BPET",L,N);
											else
												return 0;
											end
										elseif SN > "BPE" then
											if SN == "BPEC" then
												return StatLinInter("PntMPBPEC","CreepPntS","ProgBBPEC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPBPE","ItemPntS","ProgBBPE","AdjUmbarItem",L,N,0);
										end
									else
										return CalcStat("BPEPRatPCapR",L);
									end
								elseif SN > "BPEPBONUS" then
									if SN < "BPEPRATPB" then
										if SN < "BPEPRATP" then
											if SN == "BPEPPRAT" then
												return CalcRatAB(CalcStat("BPEPRatPA",L),CalcStat("BPEPRatPB",L),CalcStat("BPEPRatPCapR",L),N);
											else
												return 0;
											end
										elseif SN > "BPEPRATP" then
											if SN == "BPEPRATPA" then
												return 39;
											else
												return 0;
											end
										else
											return CalcPercAB(CalcStat("BPEPRatPA",L),CalcStat("BPEPRatPB",L),CalcStat("BPEPRatPCap",L),N);
										end
									elseif SN > "BPEPRATPB" then
										if SN < "BPEPRATPCAP" then
											if SN == "BPEPRATPC" then
												return 0.5;
											else
												return 0;
											end
										elseif SN > "BPEPRATPCAP" then
											if SN == "BPEPRATPCAPR" then
												return CalcStat("BPEPRatPB",L)*CalcStat("BPEPRatPC",L);
											else
												return 0;
											end
										else
											return 13;
										end
									else
										return CalcStat("BRatRounded",L,"BRatStandard");
									end
								else
									return 0;
								end
							else
								return CalcStat("BPEPRatPA",L);
							end
						else
							return "";
						end
					elseif SN > "BPET" then
						if SN < "BRAWLERCDBASEVITALITY" then
							if SN < "BRAWLERCDAGILITYTOFINESSE" then
								if SN < "BRATMITMEDIUM" then
									if SN < "BRATEXTRA" then
										if SN > "BRATCRITMAGN" then
											if SN == "BRATDEVHIT" then
												return CalcStat("StdProg",L,400);
											else
												return 0;
											end
										elseif SN == "BRATCRITMAGN" then
											return CalcStat("StdProg",L,600);
										else
											return 0;
										end
									elseif SN > "BRATEXTRA" then
										if SN < "BRATMITIGATIONS" then
											if SN == "BRATMITHEAVY" then
												return CalcStat("BRatStandard",L);
											else
												return 0;
											end
										elseif SN > "BRATMITIGATIONS" then
											if SN == "BRATMITLIGHT" then
												return CalcStat("BRatMitigations",L,0.666);
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return LinFmod(1,(N*CalcStat("BRatStandard",1))*7/6-50.4,N*CalcStat("BRatStandard",50),1,50,L,"P");
											else
												return StatLinInter("","StdPntS","BRatStandard","",L,N,3);
											end
										end
									else
										return CalcStat("StdProg",L,300);
									end
								elseif SN > "BRATMITMEDIUM" then
									if SN < "BRATROUNDED" then
										if SN < "BRATPARTBPE" then
											if SN == "BRATOUTHEAL" then
												return CalcStat("StdProg",L,450);
											else
												return 0;
											end
										elseif SN > "BRATPARTBPE" then
											if SN == "BRATPROGB" then
												if Lm <= 50 then
													return RoundDbl(CalcStat(C,L));
												else
													return CalcStat(C,L);
												end
											else
												return 0;
											end
										else
											return CalcStat("StdProg",L,350);
										end
									elseif SN > "BRATROUNDED" then
										if SN < "BRAWLERCDAGILITYTOCRITHIT" then
											if SN == "BRATSTANDARD" then
												return CalcStat("StdProg",L,200);
											else
												return 0;
											end
										elseif SN > "BRAWLERCDAGILITYTOCRITHIT" then
											if SN == "BRAWLERCDAGILITYTOEVADE" then
												return 2;
											else
												return 0;
											end
										else
											return 2;
										end
									else
										if Lm <= 50 then
											return RoundDbl(CalcStat(C,L));
										elseif Lm <= 105 then
											return RoundDbl(CalcStat(C,L),-1);
										elseif Lm <= 115 then
											return RoundDbl(CalcStat(C,L),-2);
										elseif Lm <= 130 then
											return RoundDbl(CalcStat(C,L),-1);
										elseif Lm <= 150 then
											return RoundDbl(CalcStat(C,L),-2);
										else
											return RoundDbl(CalcStat(C,L));
										end
									end
								else
									return CalcStat("BRatMitigations",L,0.833);
								end
							elseif SN > "BRAWLERCDAGILITYTOFINESSE" then
								if SN < "BRAWLERCDBASEFATE" then
									if SN < "BRAWLERCDARMOURTONONPHYMIT" then
										if SN < "BRAWLERCDAGILITYTOPHYMAS" then
											if SN == "BRAWLERCDAGILITYTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDAGILITYTOPHYMAS" then
											if SN == "BRAWLERCDARMOURTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "BRAWLERCDARMOURTONONPHYMIT" then
										if SN < "BRAWLERCDARMOURTYPE" then
											if SN == "BRAWLERCDARMOURTOTACMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDARMOURTYPE" then
											if SN == "BRAWLERCDBASEAGILITY" then
												return CalcStat("ClassBaseAgilityM",L);
											else
												return 0;
											end
										else
											return 3;
										end
									else
										return 0.2;
									end
								elseif SN > "BRAWLERCDBASEFATE" then
									if SN < "BRAWLERCDBASEMORALE" then
										if SN < "BRAWLERCDBASEICPR" then
											if SN == "BRAWLERCDBASEICMR" then
												return CalcStat("ClassBaseICMRL",L);
											else
												return 0;
											end
										elseif SN > "BRAWLERCDBASEICPR" then
											if SN == "BRAWLERCDBASEMIGHT" then
												return CalcStat("ClassBaseMightH",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICPR",L);
										end
									elseif SN > "BRAWLERCDBASEMORALE" then
										if SN < "BRAWLERCDBASENCPR" then
											if SN == "BRAWLERCDBASENCMR" then
												return CalcStat("ClassBaseNCMRL",L);
											else
												return 0;
											end
										elseif SN > "BRAWLERCDBASENCPR" then
											if SN == "BRAWLERCDBASEPOWER" then
												return CalcStat("ClassBasePower",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCPR",L);
										end
									else
										return CalcStat("ClassBaseMorale",L);
									end
								else
									return CalcStat("ClassBaseFate",L);
								end
							else
								return 1;
							end
						elseif SN > "BRAWLERCDBASEVITALITY" then
							if SN < "BRAWLERCDPHYMITTONONPHYMIT" then
								if SN < "BRAWLERCDMIGHTTOCRITHIT" then
									if SN < "BRAWLERCDCALCTYPETACMIT" then
										if SN < "BRAWLERCDCALCTYPECOMPHYMIT" then
											if SN == "BRAWLERCDBASEWILL" then
												return CalcStat("ClassBaseWillL",L);
											else
												return 0;
											end
										elseif SN > "BRAWLERCDCALCTYPECOMPHYMIT" then
											if SN == "BRAWLERCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										else
											return 14;
										end
									elseif SN > "BRAWLERCDCALCTYPETACMIT" then
										if SN < "BRAWLERCDFATETOPOWER" then
											if SN == "BRAWLERCDFATETONCPR" then
												return 0.07;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDFATETOPOWER" then
											if SN == "BRAWLERCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 27;
									end
								elseif SN > "BRAWLERCDMIGHTTOCRITHIT" then
									if SN < "BRAWLERCDMIGHTTOPHYMAS" then
										if SN < "BRAWLERCDMIGHTTOOUTHEAL" then
											if SN == "BRAWLERCDMIGHTTOEVADE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDMIGHTTOOUTHEAL" then
											if SN == "BRAWLERCDMIGHTTOPARRY" then
												return 1;
											else
												return 0;
											end
										else
											return 3;
										end
									elseif SN > "BRAWLERCDMIGHTTOPHYMAS" then
										if SN < "BRAWLERCDMIGHTTOTACMIT" then
											if SN == "BRAWLERCDMIGHTTOPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDMIGHTTOTACMIT" then
											if SN == "BRAWLERCDPHYMITTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 3;
									end
								else
									return 1;
								end
							elseif SN > "BRAWLERCDPHYMITTONONPHYMIT" then
								if SN < "BRAWLERCDWILLTOPHYMIT" then
									if SN < "BRAWLERCDVITALITYTONCMR" then
										if SN < "BRAWLERCDVITALITYTOICMR" then
											if SN == "BRAWLERCDTACMASTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDVITALITYTOICMR" then
											if SN == "BRAWLERCDVITALITYTOMORALE" then
												return 4.5;
											else
												return 0;
											end
										else
											return 0.012;
										end
									elseif SN > "BRAWLERCDVITALITYTONCMR" then
										if SN < "BRAWLERCDWILLTOOUTHEAL" then
											if SN == "BRAWLERCDWILLTOFINESSE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDWILLTOOUTHEAL" then
											if SN == "BRAWLERCDWILLTOPHYMAS" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 0.12;
									end
								elseif SN > "BRAWLERCDWILLTOPHYMIT" then
									if SN < "BRGALLINONEXPFINESSE" then
										if SN < "BRAWLERCDWILLTOTACMIT" then
											if SN == "BRAWLERCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BRAWLERCDWILLTOTACMIT" then
											if SN == "BRGALLINFINESSE" then
												return CalcStat("Finesse",L,2);
											else
												return 0;
											end
										else
											return 1.5;
										end
									elseif SN > "BRGALLINONEXPFINESSE" then
										if SN < "BRGREVWEAKNFINESSE" then
											if SN == "BRGREVWEAKNCRITDEF" then
												return -CalcStat("CritDefT",L,0.4);
											else
												return 0;
											end
										elseif SN > "BRGREVWEAKNFINESSE" then
											if SN == "BRGREVWEAKNRESIST" then
												return -CalcStat("ResistT",L,0.4);
											else
												return 0;
											end
										else
											return -CalcStat("FinesseT",L,0.4);
										end
									else
										return -CalcStat("Finesse",L,2);
									end
								else
									return 1.5;
								end
							else
								return 1;
							end
						else
							return CalcStat("ClassBaseVitality",L);
						end
					else
						return StatLinInter("PntMPBPE","TraitPntS","ProgBBPE","AdjUmbarTrait",L,N,0);
					end
				else
					return 10;
				end
			elseif SN > "BRGTRICKCNTDEFBPE" then
				if SN < "CHAMPIONCDBASEWILL" then
					if SN < "CAPTAINCDAGILITYTOPHYMAS" then
						if SN < "BURGLARCDBASENCMR" then
							if SN < "BURGLARCDAGILITYTOEVADE" then
								if SN < "BRWMIGHTINCREASE" then
									if SN < "BRWDEFPOSTUREPHYMAS" then
										if SN > "BRGTRICKCNTDEFCRITDEF" then
											if SN == "BRWAGGPOSTUREPHYMIT" then
												return -CalcStat("PhyMitT",L,3);
											else
												return 0;
											end
										elseif SN == "BRGTRICKCNTDEFCRITDEF" then
											return -CalcStat("CritDefT",L,0.8);
										else
											return 0;
										end
									elseif SN > "BRWDEFPOSTUREPHYMAS" then
										if SN < "BRWINNSTRPRECISIONCRITHIT" then
											if SN == "BRWINNSTRCLEVTECHFINESSE" then
												return CalcStat("FinesseT",L,CalcStat("Trait13510Choice",N)*0.2);
											else
												return 0;
											end
										elseif SN > "BRWINNSTRPRECISIONCRITHIT" then
											if SN == "BRWMAELSTROMMIGHT" then
												return CalcStat("MightT",L,2);
											else
												return 0;
											end
										else
											return CalcStat("CritHitT",L,CalcStat("Trait13510Choice",N)*0.2);
										end
									else
										return -CalcStat("PhyMasT",L,4);
									end
								elseif SN > "BRWMIGHTINCREASE" then
									if SN < "BRWSHAREISHEAVYCRITHIT" then
										if SN < "BRWRETPRECISIONFINESSE" then
											if SN == "BRWRETINTENSITYCRITHIT" then
												return CalcStat("CritHitT",L,CalcStat("Trait234Choice",N));
											else
												return 0;
											end
										elseif SN > "BRWRETPRECISIONFINESSE" then
											if SN == "BRWSHAREISBALANCEFINESSE" then
												return CalcStat("BrwInnStrClevTechFinesse",L,3);
											else
												return 0;
											end
										else
											return CalcStat("FinesseT",L,CalcStat("Trait234Choice",N));
										end
									elseif SN > "BRWSHAREISHEAVYCRITHIT" then
										if SN < "BRWVITALITYINCREASE" then
											if SN == "BRWTACMIT" then
												return CalcStat("TacMitT",L,CalcStat("Trait12345Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "BRWVITALITYINCREASE" then
											if SN == "BURGLARCDAGILITYTOCRITHIT" then
												return 1;
											else
												return 0;
											end
										else
											return CalcStat("VitalityT",L,CalcStat("Trait567810Choice",N)*0.4);
										end
									else
										return CalcStat("BrwInnStrPrecisionCritHit",L,3);
									end
								else
									return CalcStat("MightT",L,CalcStat("Trait567810Choice",N)*0.4);
								end
							elseif SN > "BURGLARCDAGILITYTOEVADE" then
								if SN < "BURGLARCDARMOURTOTACMIT" then
									if SN < "BURGLARCDAGILITYTOPHYMIT" then
										if SN < "BURGLARCDAGILITYTOPARRY" then
											if SN == "BURGLARCDAGILITYTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN > "BURGLARCDAGILITYTOPARRY" then
											if SN == "BURGLARCDAGILITYTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BURGLARCDAGILITYTOPHYMIT" then
										if SN < "BURGLARCDARMOURTOCOMPHYMIT" then
											if SN == "BURGLARCDAGILITYTOTACMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BURGLARCDARMOURTOCOMPHYMIT" then
											if SN == "BURGLARCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "BURGLARCDARMOURTOTACMIT" then
									if SN < "BURGLARCDBASEICMR" then
										if SN < "BURGLARCDBASEAGILITY" then
											if SN == "BURGLARCDARMOURTYPE" then
												return 2;
											else
												return 0;
											end
										elseif SN > "BURGLARCDBASEAGILITY" then
											if SN == "BURGLARCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseAgilityH",L);
										end
									elseif SN > "BURGLARCDBASEICMR" then
										if SN < "BURGLARCDBASEMIGHT" then
											if SN == "BURGLARCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										elseif SN > "BURGLARCDBASEMIGHT" then
											if SN == "BURGLARCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMightM",L);
										end
									else
										return CalcStat("ClassBaseICMRL",L);
									end
								else
									return 0.2;
								end
							else
								return 2;
							end
						elseif SN > "BURGLARCDBASENCMR" then
							if SN < "BURGLARCDPHYMITTOCOMPHYMIT" then
								if SN < "BURGLARCDFATETONCPR" then
									if SN < "BURGLARCDBASEWILL" then
										if SN < "BURGLARCDBASEPOWER" then
											if SN == "BURGLARCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										elseif SN > "BURGLARCDBASEPOWER" then
											if SN == "BURGLARCDBASEVITALITY" then
												return CalcStat("ClassBaseVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBasePower",L);
										end
									elseif SN > "BURGLARCDBASEWILL" then
										if SN < "BURGLARCDCALCTYPENONPHYMIT" then
											if SN == "BURGLARCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										elseif SN > "BURGLARCDCALCTYPENONPHYMIT" then
											if SN == "BURGLARCDCALCTYPETACMIT" then
												return 26;
											else
												return 0;
											end
										else
											return 13;
										end
									else
										return CalcStat("ClassBaseWillL",L);
									end
								elseif SN > "BURGLARCDFATETONCPR" then
									if SN < "BURGLARCDMIGHTTOEVADE" then
										if SN < "BURGLARCDHASPOWER" then
											if SN == "BURGLARCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BURGLARCDHASPOWER" then
											if SN == "BURGLARCDMIGHTTOCRITHIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BURGLARCDMIGHTTOEVADE" then
										if SN < "BURGLARCDMIGHTTOOUTHEAL" then
											if SN == "BURGLARCDMIGHTTOFINESSE" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "BURGLARCDMIGHTTOOUTHEAL" then
											if SN == "BURGLARCDMIGHTTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										else
											return 2;
										end
									else
										return 1;
									end
								else
									return 0.07;
								end
							elseif SN > "BURGLARCDPHYMITTOCOMPHYMIT" then
								if SN < "BURGLARCDWILLTOOUTHEAL" then
									if SN < "BURGLARCDVITALITYTOMORALE" then
										if SN < "BURGLARCDTACMASTOOUTHEAL" then
											if SN == "BURGLARCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "BURGLARCDTACMASTOOUTHEAL" then
											if SN == "BURGLARCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "BURGLARCDVITALITYTOMORALE" then
										if SN < "BURGLARCDWILLTOCRITHIT" then
											if SN == "BURGLARCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										elseif SN > "BURGLARCDWILLTOCRITHIT" then
											if SN == "BURGLARCDWILLTOFINESSE" then
												return 1.5;
											else
												return 0;
											end
										else
											return 0.5;
										end
									else
										return 4.5;
									end
								elseif SN > "BURGLARCDWILLTOOUTHEAL" then
									if SN < "C" then
										if SN < "BURGLARCDWILLTOPHYMIT" then
											if SN == "BURGLARCDWILLTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										elseif SN > "BURGLARCDWILLTOPHYMIT" then
											if SN == "BURGLARCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "C" then
										if SN < "CAPTAINCDAGILITYTOFINESSE" then
											if SN == "CAPTAINCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDAGILITYTOFINESSE" then
											if SN == "CAPTAINCDAGILITYTOPARRY" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return C;
									end
								else
									return 2;
								end
							else
								return 1;
							end
						else
							return CalcStat("ClassBaseNCMRL",L);
						end
					elseif SN > "CAPTAINCDAGILITYTOPHYMAS" then
						if SN < "CAPTAINCDPHYMITTOCOMPHYMIT" then
							if SN < "CAPTAINCDBASEVITALITY" then
								if SN < "CAPTAINCDBASEFATE" then
									if SN < "CAPTAINCDARMOURTONONPHYMIT" then
										if SN > "CAPTAINCDAGILITYTOTACMAS" then
											if SN == "CAPTAINCDARMOURTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN == "CAPTAINCDAGILITYTOTACMAS" then
											return 2;
										else
											return 0;
										end
									elseif SN > "CAPTAINCDARMOURTONONPHYMIT" then
										if SN < "CAPTAINCDARMOURTYPE" then
											if SN == "CAPTAINCDARMOURTOTACMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDARMOURTYPE" then
											if SN == "CAPTAINCDBASEAGILITY" then
												return CalcStat("ClassBaseAgilityL",L);
											else
												return 0;
											end
										else
											return 3;
										end
									else
										return 0.2;
									end
								elseif SN > "CAPTAINCDBASEFATE" then
									if SN < "CAPTAINCDBASEMORALE" then
										if SN < "CAPTAINCDBASEICPR" then
											if SN == "CAPTAINCDBASEICMR" then
												return CalcStat("ClassBaseICMRM",L);
											else
												return 0;
											end
										elseif SN > "CAPTAINCDBASEICPR" then
											if SN == "CAPTAINCDBASEMIGHT" then
												return CalcStat("ClassBaseMightH",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICPR",L);
										end
									elseif SN > "CAPTAINCDBASEMORALE" then
										if SN < "CAPTAINCDBASENCPR" then
											if SN == "CAPTAINCDBASENCMR" then
												return CalcStat("ClassBaseNCMRM",L);
											else
												return 0;
											end
										elseif SN > "CAPTAINCDBASENCPR" then
											if SN == "CAPTAINCDBASEPOWER" then
												return CalcStat("ClassBasePower",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCPR",L);
										end
									else
										return CalcStat("ClassBaseMorale",L);
									end
								else
									return CalcStat("ClassBaseFate",L);
								end
							elseif SN > "CAPTAINCDBASEVITALITY" then
								if SN < "CAPTAINCDHASPOWER" then
									if SN < "CAPTAINCDCALCTYPETACMIT" then
										if SN < "CAPTAINCDCALCTYPECOMPHYMIT" then
											if SN == "CAPTAINCDBASEWILL" then
												return CalcStat("ClassBaseWillM",L);
											else
												return 0;
											end
										elseif SN > "CAPTAINCDCALCTYPECOMPHYMIT" then
											if SN == "CAPTAINCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										else
											return 14;
										end
									elseif SN > "CAPTAINCDCALCTYPETACMIT" then
										if SN < "CAPTAINCDFATETONCPR" then
											if SN == "CAPTAINCDCANBLOCK" then
												if Lm <= 14 then
													return 0;
												else
													return 1;
												end
											else
												return 0;
											end
										elseif SN > "CAPTAINCDFATETONCPR" then
											if SN == "CAPTAINCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 0.07;
										end
									else
										return 27;
									end
								elseif SN > "CAPTAINCDHASPOWER" then
									if SN < "CAPTAINCDMIGHTTOPHYMAS" then
										if SN < "CAPTAINCDMIGHTTOCRITHIT" then
											if SN == "CAPTAINCDMIGHTTOBLOCK" then
												return 2;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDMIGHTTOCRITHIT" then
											if SN == "CAPTAINCDMIGHTTOPARRY" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "CAPTAINCDMIGHTTOPHYMAS" then
										if SN < "CAPTAINCDMIGHTTOTACMAS" then
											if SN == "CAPTAINCDMIGHTTOPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDMIGHTTOTACMAS" then
											if SN == "CAPTAINCDMIGHTTOTACMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 3;
										end
									else
										return 3;
									end
								else
									return 1;
								end
							else
								return CalcStat("ClassBaseVitality",L);
							end
						elseif SN > "CAPTAINCDPHYMITTOCOMPHYMIT" then
							if SN < "CHAMPIONCDAGILITYTOPARRY" then
								if SN < "CAPTAINCDWILLTOPHYMIT" then
									if SN < "CAPTAINCDVITALITYTOMORALE" then
										if SN < "CAPTAINCDTACMASTOOUTHEAL" then
											if SN == "CAPTAINCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDTACMASTOOUTHEAL" then
											if SN == "CAPTAINCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "CAPTAINCDVITALITYTOMORALE" then
										if SN < "CAPTAINCDWILLTOFINESSE" then
											if SN == "CAPTAINCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDWILLTOFINESSE" then
											if SN == "CAPTAINCDWILLTOPHYMAS" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 4.5;
									end
								elseif SN > "CAPTAINCDWILLTOPHYMIT" then
									if SN < "CATMINTBEARARMOUR" then
										if SN < "CAPTAINCDWILLTOTACMAS" then
											if SN == "CAPTAINCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CAPTAINCDWILLTOTACMAS" then
											if SN == "CAPTAINCDWILLTOTACMIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "CATMINTBEARARMOUR" then
										if SN < "CHAMPIONCDAGILITYTOFINESSE" then
											if SN == "CHAMPIONCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDAGILITYTOFINESSE" then
											if SN == "CHAMPIONCDAGILITYTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return CalcStat("LMCatmintBearArmour",L);
									end
								else
									return 1.5;
								end
							elseif SN > "CHAMPIONCDAGILITYTOPARRY" then
								if SN < "CHAMPIONCDBASEICMR" then
									if SN < "CHAMPIONCDARMOURTOTACMIT" then
										if SN < "CHAMPIONCDARMOURTOCOMPHYMIT" then
											if SN == "CHAMPIONCDAGILITYTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDARMOURTOCOMPHYMIT" then
											if SN == "CHAMPIONCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "CHAMPIONCDARMOURTOTACMIT" then
										if SN < "CHAMPIONCDBASEAGILITY" then
											if SN == "CHAMPIONCDARMOURTYPE" then
												return 3;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDBASEAGILITY" then
											if SN == "CHAMPIONCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseAgilityM",L);
										end
									else
										return 0.2;
									end
								elseif SN > "CHAMPIONCDBASEICMR" then
									if SN < "CHAMPIONCDBASENCMR" then
										if SN < "CHAMPIONCDBASEMIGHT" then
											if SN == "CHAMPIONCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDBASEMIGHT" then
											if SN == "CHAMPIONCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMightH",L);
										end
									elseif SN > "CHAMPIONCDBASENCMR" then
										if SN < "CHAMPIONCDBASEPOWER" then
											if SN == "CHAMPIONCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDBASEPOWER" then
											if SN == "CHAMPIONCDBASEVITALITY" then
												return CalcStat("ClassBaseVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBasePower",L);
										end
									else
										return CalcStat("ClassBaseNCMRH",L);
									end
								else
									return CalcStat("ClassBaseICMRH",L);
								end
							else
								return 1;
							end
						else
							return 1;
						end
					else
						return 2;
					end
				elseif SN > "CHAMPIONCDBASEWILL" then
					if SN < "CLASSBASEWILLH" then
						if SN < "CHISELCRITHITH" then
							if SN < "CHAMPIONCDPHYMITTONONPHYMIT" then
								if SN < "CHAMPIONCDHASPOWER" then
									if SN < "CHAMPIONCDCALCTYPETACMIT" then
										if SN > "CHAMPIONCDCALCTYPECOMPHYMIT" then
											if SN == "CHAMPIONCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN == "CHAMPIONCDCALCTYPECOMPHYMIT" then
											return 14;
										else
											return 0;
										end
									elseif SN > "CHAMPIONCDCALCTYPETACMIT" then
										if SN < "CHAMPIONCDFATETONCPR" then
											if SN == "CHAMPIONCDCANBLOCK" then
												if Lm <= 5 then
													return 0;
												else
													return 1;
												end
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDFATETONCPR" then
											if SN == "CHAMPIONCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 0.07;
										end
									else
										return 27;
									end
								elseif SN > "CHAMPIONCDHASPOWER" then
									if SN < "CHAMPIONCDMIGHTTOPHYMAS" then
										if SN < "CHAMPIONCDMIGHTTOOUTHEAL" then
											if SN == "CHAMPIONCDMIGHTTOCRITHIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDMIGHTTOOUTHEAL" then
											if SN == "CHAMPIONCDMIGHTTOPARRY" then
												return 3;
											else
												return 0;
											end
										else
											return 3;
										end
									elseif SN > "CHAMPIONCDMIGHTTOPHYMAS" then
										if SN < "CHAMPIONCDMIGHTTOTACMIT" then
											if SN == "CHAMPIONCDMIGHTTOPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDMIGHTTOTACMIT" then
											if SN == "CHAMPIONCDPHYMITTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 3;
									end
								else
									return 1;
								end
							elseif SN > "CHAMPIONCDPHYMITTONONPHYMIT" then
								if SN < "CHAMPIONCDWILLTOPHYMIT" then
									if SN < "CHAMPIONCDVITALITYTONCMR" then
										if SN < "CHAMPIONCDVITALITYTOICMR" then
											if SN == "CHAMPIONCDTACMASTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDVITALITYTOICMR" then
											if SN == "CHAMPIONCDVITALITYTOMORALE" then
												return 4.5;
											else
												return 0;
											end
										else
											return 0.012;
										end
									elseif SN > "CHAMPIONCDVITALITYTONCMR" then
										if SN < "CHAMPIONCDWILLTOOUTHEAL" then
											if SN == "CHAMPIONCDWILLTOFINESSE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDWILLTOOUTHEAL" then
											if SN == "CHAMPIONCDWILLTOPHYMAS" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 0.12;
									end
								elseif SN > "CHAMPIONCDWILLTOPHYMIT" then
									if SN < "CHICKENCDCALCTYPECOMPHYMIT" then
										if SN < "CHAMPIONCDWILLTOTACMIT" then
											if SN == "CHAMPIONCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CHAMPIONCDWILLTOTACMIT" then
											if SN == "CHICKENCANBLOCK" then
												return 1;
											else
												return 0;
											end
										else
											return 1.5;
										end
									elseif SN > "CHICKENCDCALCTYPECOMPHYMIT" then
										if SN < "CHICKENCDCALCTYPETACMIT" then
											if SN == "CHICKENCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN > "CHICKENCDCALCTYPETACMIT" then
											if SN == "CHICKENCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 27;
										end
									else
										return 14;
									end
								else
									return 1.5;
								end
							else
								return 1;
							end
						elseif SN > "CHISELCRITHITH" then
							if SN < "CLASSBASEICMRL" then
								if SN < "CHPMIGHTINCREASE" then
									if SN < "CHP2HWPNBLOCK" then
										if SN < "CHISELCRITHITL" then
											if SN == "CHISELCRITHITHOLD" then
												if Lm <= 105 then
													return RoundDbl(24.24*L);
												else
													return CalcStat("ProgExtHighLinExpRnd",L,CalcStat("ChiselCritHitHOld",105));
												end
											else
												return 0;
											end
										elseif SN > "CHISELCRITHITL" then
											if SN == "CHISELCRITHITLOLD" then
												if Lm <= 105 then
													return RoundDbl(16.16*L);
												else
													return CalcStat("ProgExtHighLinExpRnd",L,CalcStat("ChiselCritHitLOld",105));
												end
											else
												return 0;
											end
										else
											if Lm <= 140 then
												return CalcStat("U371LegacyStatFix",L,"ChiselCritHitLOld");
											else
												return CalcStat("ChiselCritHitL",140);
											end
										end
									elseif SN > "CHP2HWPNBLOCK" then
										if SN < "CHPFINESSEINCREASE" then
											if SN == "CHPCONTRBURNICPR" then
												return CalcStat("ICPRT",L,0.4);
											else
												return 0;
											end
										elseif SN > "CHPFINESSEINCREASE" then
											if SN == "CHPFLURRYINCRCRITHIT" then
												return CalcStat("CritHitT",L,2.4);
											else
												return 0;
											end
										else
											return CalcStat("FinesseT",L,CalcStat("Trait12345Choice",N)*0.4);
										end
									else
										return CalcStat("BlockT",L,4);
									end
								elseif SN > "CHPMIGHTINCREASE" then
									if SN < "CLASSBASEAGILITYL" then
										if SN < "CHPUNBREAKTACMIT" then
											if SN == "CHPSTALWBLADEVITALITY" then
												return CalcStat("VitalityT",L,CalcStat("Trait567810Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "CHPUNBREAKTACMIT" then
											if SN == "CLASSBASEAGILITYH" then
												return CalcStat("BaseAgility",L,1.5);
											else
												return 0;
											end
										else
											return CalcStat("TacMitT",L,0.4);
										end
									elseif SN > "CLASSBASEAGILITYL" then
										if SN < "CLASSBASEFATE" then
											if SN == "CLASSBASEAGILITYM" then
												return CalcStat("BaseAgility",L,1.0);
											else
												return 0;
											end
										elseif SN > "CLASSBASEFATE" then
											if SN == "CLASSBASEICMRH" then
												return 0.2;
											else
												return 0;
											end
										else
											return CalcStat("BaseFate",L);
										end
									else
										return CalcStat("BaseAgility",L,0.5);
									end
								else
									return CalcStat("MightT",L,CalcStat("Trait567810Choice",N)*0.4);
								end
							elseif SN > "CLASSBASEICMRL" then
								if SN < "CLASSBASENCMRH" then
									if SN < "CLASSBASEMIGHTH" then
										if SN < "CLASSBASEICPR" then
											if SN == "CLASSBASEICMRM" then
												return 0.175;
											else
												return 0;
											end
										elseif SN > "CLASSBASEICPR" then
											if SN == "CLASSBASEICPRADJ" then
												if Lm <= 1 then
													return 1.5*N;
												elseif Lm <= 20 then
													return 1.1*N;
												else
													return N;
												end
											else
												return 0;
											end
										else
											return StatLinInter("PntMPClassBaseICPR","ClassBasePowerRegenPntS","ProgBICPR","ClassBaseICPRAdj",L,N,99);
										end
									elseif SN > "CLASSBASEMIGHTH" then
										if SN < "CLASSBASEMIGHTM" then
											if SN == "CLASSBASEMIGHTL" then
												return CalcStat("BaseMight",L,0.5);
											else
												return 0;
											end
										elseif SN > "CLASSBASEMIGHTM" then
											if SN == "CLASSBASEMORALE" then
												return CalcStat("BaseMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("BaseMight",L,1.0);
										end
									else
										return CalcStat("BaseMight",L,1.5);
									end
								elseif SN > "CLASSBASENCMRH" then
									if SN < "CLASSBASENCPRADJ" then
										if SN < "CLASSBASENCMRM" then
											if SN == "CLASSBASENCMRL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "CLASSBASENCMRM" then
											if SN == "CLASSBASENCPR" then
												return StatLinInter("PntMPClassBaseNCPR","ClassBasePowerRegenPntS","ProgBNCPR","ClassBaseNCPRAdj",L,N,99);
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "CLASSBASENCPRADJ" then
										if SN < "CLASSBASEPOWERREGENPNTS" then
											if SN == "CLASSBASEPOWER" then
												return CalcStat("BasePower",L);
											else
												return 0;
											end
										elseif SN > "CLASSBASEPOWERREGENPNTS" then
											if SN == "CLASSBASEVITALITY" then
												return CalcStat("BaseVitality",L);
											else
												return 0;
											end
										else
											return {{1,20,50,60,65,75,85,95,100,105,115,120,130,140,150},{1,20,50,60,65,75,85,95,100,105,115,120,130,140,150}};
										end
									else
										if Lm <= 1 then
											return 1.5*N;
										elseif Lm <= 20 then
											return 1.1*N;
										else
											return N;
										end
									end
								else
									return 2;
								end
							else
								return 0.15;
							end
						else
							if Lm <= 140 then
								return CalcStat("U371LegacyStatFix",L,"ChiselCritHitHOld");
							else
								return CalcStat("ChiselCritHitH",140);
							end
						end
					elseif SN > "CLASSBASEWILLH" then
						if SN < "COMBATDAMAGEMODNERFEDADJ" then
							if SN < "COMBATBASETACHPS" then
								if SN < "COMBATBASEHQTYMP" then
									if SN < "CLOTHARMOUR" then
										if SN > "CLASSBASEWILLL" then
											if SN == "CLASSBASEWILLM" then
												return CalcStat("BaseWill",L,1.0);
											else
												return 0;
											end
										elseif SN == "CLASSBASEWILLL" then
											return CalcStat("BaseWill",L,0.5);
										else
											return 0;
										end
									elseif SN > "CLOTHARMOUR" then
										if SN < "COMBATBASECAT" then
											if SN == "COMBATBASE" then
												return CalcStat("CombatBaseCat",WpnCodeIndex(C,1),L)*CalcStat("CombatBaseTypeMP",WpnCodeIndex(C,2))*CalcStat("CombatBaseQtyMPCat",WpnCodeIndex(C,1),WpnCodeIndex(C,3));
											else
												return 0;
											end
										elseif SN > "COMBATBASECAT" then
											if SN == "COMBATBASEH" then
												return 1.0*CalcStat("CombatBasePhyDPS",L)*1.08;
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											elseif Lm <= 1 then
												return CalcStat("CombatBaseH",N);
											else
												return CalcStat("CombatBaseL",N);
											end
										end
									else
										if Lm <= 50 then
											return L;
										else
											return 50;
										end
									end
								elseif SN > "COMBATBASEHQTYMP" then
									if SN < "COMBATBASEQTYMPCAT" then
										if SN < "COMBATBASELQTYMP" then
											if SN == "COMBATBASEL" then
												return 0.9*CalcStat("CombatBasePhyDPS",L)*1.08;
											else
												return 0;
											end
										elseif SN > "COMBATBASELQTYMP" then
											if SN == "COMBATBASEPHYDPS" then
												if Lm <= 50 then
													return LinFmod(1,2,20,1,50,L);
												elseif Lm <= 60 then
													return LinFmod(1,20,26.6,50,60,L);
												elseif Lm <= 65 then
													return LinFmod(1,26.6,29.1,60,65,L);
												elseif Lm <= 75 then
													return LinFmod(1,29.1,39,65,75,L);
												elseif Lm <= 125 then
													return LinFmod(1,39,52,75,125,L);
												elseif Lm <= 175 then
													return LinFmod(1,52,69,125,175,L);
												elseif Lm <= 200 then
													return LinFmod(1,69,86,175,200,L);
												elseif Lm <= 222 then
													return LinFmod(1,86,108,200,222,L);
												elseif Lm <= 300 then
													return LinFmod(1,108,108,222,300,L);
												elseif Lm <= 350 then
													return LinFmod(1,119,144,301,350,L);
												elseif Lm <= 400 then
													return LinFmod(1,158,180,351,400,L);
												elseif Lm <= 450 then
													return LinFmod(1,198,239,401,450,L);
												elseif Lm <= 500 then
													return LinFmod(1,263,360,451,500,L);
												elseif Lm <= 550 then
													return LinFmod(1,400,540,501,550,L);
												elseif Lm <= 600 then
													return LinFmod(1,590,810,551,600,L);
												elseif Lm <= 650 then
													return RoundDblDown(RoundDblUp((L-50)/5.5)*36.7-2811,-1);
												else
													return CalcStat("CombatBasePhyDPS",650);
												end
											else
												return 0;
											end
										else
											return CalcStat("CombatBaseHQtyMP",L);
										end
									elseif SN > "COMBATBASEQTYMPCAT" then
										if SN < "COMBATBASETACDPSBYLEVEL" then
											if SN == "COMBATBASETACDPS" then
												if Lm <= 47 then
													return LinFmod(1,0.5,0.5,1,47,L);
												elseif Lm <= 50 then
													return LinFmod(1,0.5,0.8,47,50,L);
												elseif Lm <= 51 then
													return LinFmod(1,1,1,51,51,L);
												elseif Lm <= 60 then
													return LinFmod(1,1.32,6.6,52,60,L);
												elseif Lm <= 65 then
													return LinFmod(1,6.6,9.1,60,65,L);
												elseif Lm <= 75 then
													return LinFmod(1,9.1,19,65,75,L);
												elseif Lm <= 125 then
													return LinFmod(1,19,32,75,125,L);
												elseif Lm <= 175 then
													return LinFmod(1,32,49,125,175,L);
												elseif Lm <= 200 then
													return LinFmod(1,49,66,175,200,L);
												elseif Lm <= 222 then
													return LinFmod(1,66,88,200,222,L);
												elseif Lm <= 299 then
													return LinFmod(1,88,88,222,299,L);
												elseif Lm <= 349 then
													return LinFmod(1,99,124,300,349,L);
												elseif Lm <= 399 then
													return LinFmod(1,138,160,350,399,L);
												elseif Lm <= 449 then
													return LinFmod(1,178,219,400,449,L);
												elseif Lm <= 499 then
													return LinFmod(1,243,340,450,499,L);
												elseif Lm <= 549 then
													return LinFmod(1,380,520,500,549,L);
												elseif Lm <= 599 then
													return LinFmod(1,570,790,550,599,L);
												elseif Lm <= 649 then
													return RoundDblDown(RoundDblUp((L-49)/5.5)*36.7-2831,-1);
												else
													return CalcStat("CombatBaseTacDPS",649);
												end
											else
												return 0;
											end
										elseif SN > "COMBATBASETACDPSBYLEVEL" then
											if SN == "COMBATBASETACDPSBYLEVELMAX" then
												return 20;
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return LinFmod(1,2,CalcStat("CombatBaseTacDPSByLevelMax",L),1,50,L);
											else
												return CalcStat("CombatBaseTacDPSByLevelMax",L);
											end
										end
									else
										if Lm <= 0 then
											return 0;
										elseif Lm <= 1 then
											return CalcStat("CombatBaseHQtyMP",N);
										else
											return CalcStat("CombatBaseLQtyMP",N);
										end
									end
								else
									if Lm <= 0 then
										return 0;
									else
										return DataTableValue({1,1.02,1.04,1.08,1.12},L);
									end
								end
							elseif SN > "COMBATBASETACHPS" then
								if SN < "COMBATDAMAGEMODENERGY" then
									if SN < "COMBATBASETACHPSLVLTOILVL" then
										if SN < "COMBATBASETACHPSBYLEVELMAX" then
											if SN == "COMBATBASETACHPSBYLEVEL" then
												if Lm <= 46 then
													return CalcStat("CombatBaseTacHPSCurves",L);
												else
													return CalcStat("CombatBaseTacHPSByLevelMax",L);
												end
											else
												return 0;
											end
										elseif SN > "COMBATBASETACHPSBYLEVELMAX" then
											if SN == "COMBATBASETACHPSCURVES" then
												if Lm <= 25 then
													return -0.0033215*L*L+0.2470730225*L+1.7562484775;
												else
													return -0.003714298*L*L+0.254286886*L+1.82140064;
												end
											else
												return 0;
											end
										else
											return 5.659142856;
										end
									elseif SN > "COMBATBASETACHPSLVLTOILVL" then
										if SN < "COMBATBASETYPEMP" then
											if SN == "COMBATBASETACHPSNOCLASS" then
												return CalcStat("CombatBaseTacHPSByLevel",L)+CalcStat("CombatBaseTacHPS",CalcStat("CombatBaseTacHPSLvlToILvl",L));
											else
												return 0;
											end
										elseif SN > "COMBATBASETYPEMP" then
											if SN == "COMBATDAMAGEMOD" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","",L,N,2);
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({1,1.4,1.4},L);
											end
										end
									else
										if Lm <= 75 then
											return LinFmod(1,1,75,1,75,L);
										elseif Lm <= 100 then
											return LinFmod(1,75,200,75,100,L);
										elseif Lm <= 104 then
											return RoundDbl(LinFmod(1,201.3,214.3,101,104,L));
										elseif Lm <= 105 then
											return 222;
										else
											return RoundDbl(CalcStat("LvlToILvl",L));
										end
									end
								elseif SN > "COMBATDAMAGEMODENERGY" then
									if SN < "COMBATDAMAGEMODHEALTHLOWADJ" then
										if SN < "COMBATDAMAGEMODHEALTHADJ" then
											if SN == "COMBATDAMAGEMODHEALTH" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBHealth","CombatDamageModHealthAdj",L,N,2);
											else
												return 0;
											end
										elseif SN > "COMBATDAMAGEMODHEALTHADJ" then
											if SN == "COMBATDAMAGEMODHEALTHLOW" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBHealth","CombatDamageModHealthLowAdj",L,N,99);
											else
												return 0;
											end
										else
											if Lm <= 141 then
												return 1;
											else
												return 0.63;
											end
										end
									elseif SN > "COMBATDAMAGEMODHEALTHLOWADJ" then
										if SN < "COMBATDAMAGEMODHEALTHMEDIUMADJ" then
											if SN == "COMBATDAMAGEMODHEALTHMEDIUM" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBHealth","CombatDamageModHealthMediumAdj",L,N,99);
											else
												return 0;
											end
										elseif SN > "COMBATDAMAGEMODHEALTHMEDIUMADJ" then
											if SN == "COMBATDAMAGEMODNERFED" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","CombatDamageModNerfedAdj",L,N,2);
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 0.36*N;
											elseif Lm <= 25 then
												return 0.54*N;
											elseif Lm <= 50 then
												return 0.72*N;
											else
												return 0.9*N;
											end
										end
									else
										if Lm <= 1 then
											return 0.144*N;
										elseif Lm <= 25 then
											return 0.324*N;
										elseif Lm <= 50 then
											return 0.576*N;
										else
											return 0.9*N;
										end
									end
								else
									return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBEnergy","",L,N,2);
								end
							else
								if Lm <= 46 then
									return 0;
								elseif Lm <= 49 then
									return CalcStat("CombatBaseTacHPSCurves",L)-CalcStat("CombatBaseTacHPSByLevelMax",L);
								elseif Lm <= 55 then
									return 0.5;
								elseif Lm <= 599 then
									return CalcStat("CommonTacHPS",L)-CalcStat("CombatBaseTacHPSByLevelMax",L);
								elseif Lm <= 649 then
									return (RoundDblUp((4*L+2)/22)*678-RoundDblUp((L+1)/22))*0.175-11734.1-CalcStat("CombatBaseTacHPSByLevelMax",L);
								else
									return CalcStat("CombatBaseTacHPS",649);
								end
							end
						elseif SN > "COMBATDAMAGEMODNERFEDADJ" then
							if SN < "CPTCOVPHYMIT" then
								if SN < "COMMONTACHPS" then
									if SN < "COMBATDAMAGEMODPETSRND" then
										if SN < "COMBATDAMAGEMODPETS" then
											if SN == "COMBATDAMAGEMODNPCS" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","",L,N,99);
											else
												return 0;
											end
										elseif SN > "COMBATDAMAGEMODPETS" then
											if SN == "COMBATDAMAGEMODPETSADJ" then
												if Lm <= 1 then
													return N;
												elseif Lm <= 25 then
													return 0.4*N;
												elseif Lm <= 50 then
													return 0.5*N;
												elseif Lm <= 60 then
													return 0.6*N;
												elseif Lm <= 65 then
													return 0.7*N;
												elseif Lm <= 75 then
													return 0.8*N;
												elseif Lm <= 85 then
													return 0.85*N;
												elseif Lm <= 95 then
													return 0.9*N;
												elseif Lm <= 100 then
													return 0.95*N;
												else
													return N;
												end
											else
												return 0;
											end
										else
											return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","CombatDamageModPetsAdj",L,N,99);
										end
									elseif SN > "COMBATDAMAGEMODPETSRND" then
										if SN < "COMBATDAMAGEMODPLAYERSADJ" then
											if SN == "COMBATDAMAGEMODPLAYERS" then
												return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","CombatDamageModPlayersAdj",L,N,99);
											else
												return 0;
											end
										elseif SN > "COMBATDAMAGEMODPLAYERSADJ" then
											if SN == "COMBATINHEAL" then
												return CalcStat("InHeal",L,2.0);
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 0.8*N;
											elseif Lm <= 25 then
												return 0.9*N;
											else
												return N;
											end
										end
									else
										return StatLinInter("PntMPCombatDamageMod","TraitPntSVital","ProgBCombatDamageMod","CombatDamageModPetsAdj",L,N,2);
									end
								elseif SN > "COMMONTACHPS" then
									if SN < "CPTBLADEPHYMAS" then
										if SN < "CONSTSTATC" then
											if SN == "COMMONTACHPSITEMPNTS" then
												return {{1,50,60,65,75,125,175,200,222,299,300,349,350,399,400,449,450,499,500,549,550,599},{1,50,60,65,75,85,95,100,105,105,106,115,116,120,121,130,131,140,141,150,151,160}};
											else
												return 0;
											end
										elseif SN > "CONSTSTATC" then
											if SN == "CPTBLADECRITDEF" then
												return CalcStat("CritDefT",L,0.8);
											else
												return 0;
											end
										else
											return CalcStat(C,1,L);
										end
									elseif SN > "CPTBLADEPHYMAS" then
										if SN < "CPTCOVFATE" then
											if SN == "CPTBLADETACMAS" then
												return CalcStat("TacMasT",L,0.8);
											else
												return 0;
											end
										elseif SN > "CPTCOVFATE" then
											if SN == "CPTCOVMAIN" then
												return CalcStat("MainT",L,0.4);
											else
												return 0;
											end
										else
											return CalcStat("FateT",L,0.4);
										end
									else
										return CalcStat("PhyMasT",L,1.2);
									end
								else
									return StatLinInter("PntMPTacHPS","CommonTacHPSItemPntS","ProgBTacHPS","",L,N,99);
								end
							elseif SN > "CPTCOVPHYMIT" then
								if SN < "CPTSHIELDTACMAS" then
									if SN < "CPTIDOMEMAIN" then
										if SN < "CPTCRITDEF" then
											if SN == "CPTCOVVITALITY" then
												return CalcStat("VitalityT",L,0.4);
											else
												return 0;
											end
										elseif SN > "CPTCRITDEF" then
											if SN == "CPTIDOMEFATE" then
												return CalcStat("FateT",L,0.4);
											else
												return 0;
											end
										else
											return CalcStat("CritDef",L,0.6);
										end
									elseif SN > "CPTIDOMEMAIN" then
										if SN < "CPTSHIELDCRITDEF" then
											if SN == "CPTIDOMEVITALITY" then
												return CalcStat("VitalityT",L,0.4);
											else
												return 0;
											end
										elseif SN > "CPTSHIELDCRITDEF" then
											if SN == "CPTSHIELDPHYMAS" then
												return CalcStat("PhyMasT",L,0.8);
											else
												return 0;
											end
										else
											return CalcStat("CritDefT",L,1.2);
										end
									else
										return CalcStat("MainT",L,0.4);
									end
								elseif SN > "CPTSHIELDTACMAS" then
									if SN < "CPTSTANDALONEPHYMAS" then
										if SN < "CPTSONGPHYMAS" then
											if SN == "CPTSONGCRITDEF" then
												return CalcStat("CritDefT",L,0.8);
											else
												return 0;
											end
										elseif SN > "CPTSONGPHYMAS" then
											if SN == "CPTSONGTACMAS" then
												return CalcStat("TacMasT",L,1.2);
											else
												return 0;
											end
										else
											return CalcStat("PhyMasT",L,0.8);
										end
									elseif SN > "CPTSTANDALONEPHYMAS" then
										if SN < "CREEPAUDACITYCCDP" then
											if SN == "CPTSTANDALONETACMAS" then
												return CalcStat("TacMasT",L,0.8);
											else
												return 0;
											end
										elseif SN > "CREEPAUDACITYCCDP" then
											if SN == "CREEPAUDACITYCOST" then
												return CalcStat("CreepAudacityCostBase",L)*25;
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											elseif Lm <= 16 then
												return 0.5;
											else
												return 0.4;
											end
										end
									else
										return CalcStat("PhyMasT",L,1.2);
									end
								else
									return CalcStat("TacMasT",L,0.8);
								end
							else
								return CalcStat("PhyMitT",L,2.4);
							end
						else
							if Lm <= 141 then
								return 1;
							else
								return 0.82;
							end
						end
					else
						return CalcStat("BaseWill",L,1.5);
					end
				else
					return CalcStat("ClassBaseWillL",L);
				end
			else
				return -CalcStat("BPET",L,1.2);
			end
		elseif SN > "CREEPAUDACITYCOSTBASE" then
			if SN < "HUNTERCDAGILITYTOCRITHIT" then
				if SN < "FINESSEPRATPA" then
					if SN < "DEVHITPRATPC" then
						if SN < "CRITDEFT" then
							if SN < "CREEPBATPROMPOWERP" then
								if SN < "CREEPAUDACITYTACDMGP" then
									if SN < "CREEPAUDACITYMELREDP" then
										if SN > "CREEPAUDACITYDMGP" then
											if SN == "CREEPAUDACITYMELDMGP" then
												return CalcStat("CreepAudacityDmgP",L);
											else
												return 0;
											end
										elseif SN == "CREEPAUDACITYDMGP" then
											if Lm <= 0 then
												return 0;
											elseif Lm <= 10 then
												return LinFmod(1,1,1.2,1,10,L);
											elseif Lm <= 36 then
												return LinFmod(1,1.2,1.25,10,36,L);
											elseif Lm <= 41 then
												return LinFmod(1,1.25,1.3,36,41,L);
											elseif Lm <= 60 then
												return LinFmod(1,1.3,1.25,41,60,L);
											else
												return CalcStat("CreepAudacityDmgP",60);
											end
										else
											return 0;
										end
									elseif SN > "CREEPAUDACITYMELREDP" then
										if SN < "CREEPAUDACITYRNGDMGP" then
											if SN == "CREEPAUDACITYREDP" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 10 then
													return LinFmod(1,0.55,0.55,1,10,L);
												elseif Lm <= 36 then
													return LinFmod(1,0.55,0.55,10,36,L);
												elseif Lm <= 41 then
													return LinFmod(1,0.55,0.55,36,41,L);
												elseif Lm <= 60 then
													return LinFmod(1,0.55,0.55,41,60,L);
												else
													return CalcStat("CreepAudacityRedP",60);
												end
											else
												return 0;
											end
										elseif SN > "CREEPAUDACITYRNGDMGP" then
											if SN == "CREEPAUDACITYRNGREDP" then
												return CalcStat("CreepAudacityRedP",L);
											else
												return 0;
											end
										else
											return CalcStat("CreepAudacityDmgP",L);
										end
									else
										return CalcStat("CreepAudacityRedP",L);
									end
								elseif SN > "CREEPAUDACITYTACDMGP" then
									if SN < "CREEPBATPROMHEALTHP" then
										if SN < "CREEPBATPROMDMGP" then
											if SN == "CREEPAUDACITYTACREDP" then
												return CalcStat("CreepAudacityRedP",L);
											else
												return 0;
											end
										elseif SN > "CREEPBATPROMDMGP" then
											if SN == "CREEPBATPROMFINESSE" then
												return 0;
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											elseif Lm <= 5 then
												return LinFmod(1,0.005,0.02,1,5,L);
											elseif Lm <= 10 then
												return LinFmod(1,0.02,0.045,5,10,L);
											elseif Lm <= 15 then
												return LinFmod(1,0.045,0.075,10,15,L);
											else
												return CalcStat("CreepBatPromDmgP",15);
											end
										end
									elseif SN > "CREEPBATPROMHEALTHP" then
										if SN < "CREEPBATPROMMELDMGP" then
											if SN == "CREEPBATPROMINHEALP" then
												return 0;
											else
												return 0;
											end
										elseif SN > "CREEPBATPROMMELDMGP" then
											if SN == "CREEPBATPROMOUTHEALP" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 5 then
													return LinFmod(1,0.02,0.1,1,5,L);
												elseif Lm <= 10 then
													return LinFmod(1,0.1,0.15,5,10,L);
												elseif Lm <= 15 then
													return LinFmod(1,0.15,0.2,10,15,L);
												else
													return CalcStat("CreepBatPromOutHealP",15);
												end
											else
												return 0;
											end
										else
											return CalcStat("CreepBatPromDmgP",L);
										end
									else
										return CalcStat("CreepBatPromVitalP",L);
									end
								else
									return CalcStat("CreepAudacityDmgP",L);
								end
							elseif SN > "CREEPBATPROMPOWERP" then
								if SN < "CRITDEFPBONUS" then
									if SN < "CREEPPNTS" then
										if SN < "CREEPBATPROMTACDMGP" then
											if SN == "CREEPBATPROMRNGDMGP" then
												return CalcStat("CreepBatPromDmgP",L);
											else
												return 0;
											end
										elseif SN > "CREEPBATPROMTACDMGP" then
											if SN == "CREEPBATPROMVITALP" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 5 then
													return LinFmod(1,1.02,1.1,1,5,L);
												elseif Lm <= 10 then
													return LinFmod(1,1.1,1.15,5,10,L);
												elseif Lm <= 15 then
													return LinFmod(1,1.15,1.2,10,15,L);
												else
													return CalcStat("CreepBatPromVitalP",15);
												end
											else
												return 0;
											end
										else
											return CalcStat("CreepBatPromDmgP",L);
										end
									elseif SN > "CREEPPNTS" then
										if SN < "CRITDEF" then
											if SN == "CREEPPROGB" then
												return LinFmod(1,0.01,1,1,CalcStat("LevelCap",L),L);
											else
												return 0;
											end
										elseif SN > "CRITDEF" then
											if SN == "CRITDEFC" then
												return StatLinInter("PntMPCritDefC","CreepPntS","ProgBCritDefC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPCritDef","ItemPntS","ProgBCritDef","AdjUmbarItem",L,N,0);
										end
									else
										return {{1,150},{1,150}};
									end
								elseif SN > "CRITDEFPBONUS" then
									if SN < "CRITDEFPRATPB" then
										if SN < "CRITDEFPRATP" then
											if SN == "CRITDEFPPRAT" then
												return CalcRatAB(CalcStat("CritDefPRatPA",L),CalcStat("CritDefPRatPB",L),CalcStat("CritDefPRatPCapR",L),N);
											else
												return 0;
											end
										elseif SN > "CRITDEFPRATP" then
											if SN == "CRITDEFPRATPA" then
												return 240;
											else
												return 0;
											end
										else
											return CalcPercAB(CalcStat("CritDefPRatPA",L),CalcStat("CritDefPRatPB",L),CalcStat("CritDefPRatPCap",L),N);
										end
									elseif SN > "CRITDEFPRATPB" then
										if SN < "CRITDEFPRATPCAP" then
											if SN == "CRITDEFPRATPC" then
												return 0.5;
											else
												return 0;
											end
										elseif SN > "CRITDEFPRATPCAP" then
											if SN == "CRITDEFPRATPCAPR" then
												return CalcStat("CritDefPRatPB",L)*CalcStat("CritDefPRatPC",L);
											else
												return 0;
											end
										else
											return 80;
										end
									else
										return CalcStat("BRatRounded",L,"BRatStandard");
									end
								else
									return 0;
								end
							else
								return CalcStat("CreepBatPromVitalP",L);
							end
						elseif SN > "CRITDEFT" then
							if SN < "CRITMAGNPRATPA" then
								if SN < "CRITHITPRATPB" then
									if SN < "CRITHITPBONUS" then
										if SN < "CRITHITC" then
											if SN == "CRITHIT" then
												return StatLinInter("PntMPCritHit","ItemPntS","ProgBCritHit","AdjUmbarItem",L,N,0);
											else
												return 0;
											end
										elseif SN > "CRITHITC" then
											if SN == "CRITHITOLD" then
												return CalcStat("CritHit",L,N);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPCritHitC","CreepPntS","ProgBCritHitC","",L,N,0);
										end
									elseif SN > "CRITHITPBONUS" then
										if SN < "CRITHITPRATP" then
											if SN == "CRITHITPPRAT" then
												return CalcRatAB(CalcStat("CritHitPRatPA",L),CalcStat("CritHitPRatPB",L),CalcStat("CritHitPRatPCapR",L),N);
											else
												return 0;
											end
										elseif SN > "CRITHITPRATP" then
											if SN == "CRITHITPRATPA" then
												return 75;
											else
												return 0;
											end
										else
											return CalcPercAB(CalcStat("CritHitPRatPA",L),CalcStat("CritHitPRatPB",L),CalcStat("CritHitPRatPCap",L),N);
										end
									else
										return 0;
									end
								elseif SN > "CRITHITPRATPB" then
									if SN < "CRITHITT" then
										if SN < "CRITHITPRATPCAP" then
											if SN == "CRITHITPRATPC" then
												return 0.5;
											else
												return 0;
											end
										elseif SN > "CRITHITPRATPCAP" then
											if SN == "CRITHITPRATPCAPR" then
												return CalcStat("CritHitPRatPB",L)*CalcStat("CritHitPRatPC",L);
											else
												return 0;
											end
										else
											return 25;
										end
									elseif SN > "CRITHITT" then
										if SN < "CRITMAGNPPRAT" then
											if SN == "CRITMAGNPBONUS" then
												return 0;
											else
												return 0;
											end
										elseif SN > "CRITMAGNPPRAT" then
											if SN == "CRITMAGNPRATP" then
												return CalcPercAB(CalcStat("CritMagnPRatPA",L),CalcStat("CritMagnPRatPB",L),CalcStat("CritMagnPRatPCap",L),N);
											else
												return 0;
											end
										else
											return CalcRatAB(CalcStat("CritMagnPRatPA",L),CalcStat("CritMagnPRatPB",L),CalcStat("CritMagnPRatPCapR",L),N);
										end
									else
										return StatLinInter("PntMPCritHit","TraitPntS","ProgBCritHit","AdjUmbarTrait",L,N,0);
									end
								else
									return CalcStat("BRatRounded",L,"BRatExtra");
								end
							elseif SN > "CRITMAGNPRATPA" then
								if SN < "DEFILERCDCALCTYPENONPHYMIT" then
									if SN < "CRITMAGNPRATPCAPR" then
										if SN < "CRITMAGNPRATPC" then
											if SN == "CRITMAGNPRATPB" then
												return CalcStat("BRatRounded",L,"BRatCritMagn");
											else
												return 0;
											end
										elseif SN > "CRITMAGNPRATPC" then
											if SN == "CRITMAGNPRATPCAP" then
												return 75;
											else
												return 0;
											end
										else
											return 0.5;
										end
									elseif SN > "CRITMAGNPRATPCAPR" then
										if SN < "DEFILERCANBLOCK" then
											if SN == "CRYRESISTT" then
												return CalcStat("ResistAddT",L,N);
											else
												return 0;
											end
										elseif SN > "DEFILERCANBLOCK" then
											if SN == "DEFILERCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return CalcStat("CritMagnPRatPB",L)*CalcStat("CritMagnPRatPC",L);
									end
								elseif SN > "DEFILERCDCALCTYPENONPHYMIT" then
									if SN < "DEVHITPPRAT" then
										if SN < "DEFILERCDHASPOWER" then
											if SN == "DEFILERCDCALCTYPETACMIT" then
												return 27;
											else
												return 0;
											end
										elseif SN > "DEFILERCDHASPOWER" then
											if SN == "DEVHITPBONUS" then
												return 0;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "DEVHITPPRAT" then
										if SN < "DEVHITPRATPA" then
											if SN == "DEVHITPRATP" then
												return CalcPercAB(CalcStat("DevHitPRatPA",L),CalcStat("DevHitPRatPB",L),CalcStat("DevHitPRatPCap",L),N);
											else
												return 0;
											end
										elseif SN > "DEVHITPRATPA" then
											if SN == "DEVHITPRATPB" then
												return CalcStat("BRatRounded",L,"BRatDevHit");
											else
												return 0;
											end
										else
											return 30;
										end
									else
										return CalcRatAB(CalcStat("DevHitPRatPA",L),CalcStat("DevHitPRatPB",L),CalcStat("DevHitPRatPCapR",L),N);
									end
								else
									return 14;
								end
							else
								return 225;
							end
						else
							return StatLinInter("PntMPCritDef","TraitPntS","ProgBCritDef","AdjUmbarTrait",L,N,0);
						end
					elseif SN > "DEVHITPRATPC" then
						if SN < "ELFAGILITYWOODSAGILITY" then
							if SN < "DWARFRDTRAITICMR" then
								if SN < "DWARFFATEFULDWARFFATE" then
									if SN < "DISEASERESISTT" then
										if SN > "DEVHITPRATPCAP" then
											if SN == "DEVHITPRATPCAPR" then
												return CalcStat("DevHitPRatPB",L)*CalcStat("DevHitPRatPC",L);
											else
												return 0;
											end
										elseif SN == "DEVHITPRATPCAP" then
											return 10;
										else
											return 0;
										end
									elseif SN > "DISEASERESISTT" then
										if SN < "DMGTYPEMITT" then
											if SN == "DMGTYPEMIT" then
												return StatLinInter("PntMPDmgTypeMit","ItemPntS","ProgBMitigation","AdjUmbarItemMit",L,N,0);
											else
												return 0;
											end
										elseif SN > "DMGTYPEMITT" then
											if SN == "DWARFENDURVITALITY" then
												return CalcStat("VitalityT",L,1.0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPDmgTypeMit","TraitPntS","ProgBMitigation","AdjUmbarTraitMit",L,N,0);
										end
									else
										return CalcStat("ResistAddT",L,N);
									end
								elseif SN > "DWARFFATEFULDWARFFATE" then
									if SN < "DWARFRDPSVTWOBLOCK" then
										if SN < "DWARFRDPSVONEFATE" then
											if SN == "DWARFLOSTDWARFKDSFATE" then
												return -CalcStat("FateT",L,0.4);
											else
												return 0;
											end
										elseif SN > "DWARFRDPSVONEFATE" then
											if SN == "DWARFRDPSVONENAME" then
												return "Fateful Dwarf";
											else
												return 0;
											end
										else
											return CalcStat("DwarfFatefulDwarfFate",L);
										end
									elseif SN > "DWARFRDPSVTWOBLOCK" then
										if SN < "DWARFRDTRAITAGILITY" then
											if SN == "DWARFRDPSVTWONAME" then
												return "Shield Brawler";
											else
												return 0;
											end
										elseif SN > "DWARFRDTRAITAGILITY" then
											if SN == "DWARFRDTRAITFATE" then
												return CalcStat("DwarfLostDwarfKdsFate",L);
											else
												return 0;
											end
										else
											return CalcStat("DwarfStockyAgility",L);
										end
									else
										return CalcStat("DwarfShieldBrwlBlock",L);
									end
								else
									return CalcStat("FateT",L,1.0);
								end
							elseif SN > "DWARFRDTRAITICMR" then
								if SN < "DWARFSTOCKYAGILITY" then
									if SN < "DWARFRDTRAITNCPR" then
										if SN < "DWARFRDTRAITMIGHT" then
											if SN == "DWARFRDTRAITICPR" then
												return CalcStat("DwarfUnwearBattleICPR",L);
											else
												return 0;
											end
										elseif SN > "DWARFRDTRAITMIGHT" then
											if SN == "DWARFRDTRAITNCMR" then
												return CalcStat("DwarfUnwearBattleNCMR",L);
											else
												return 0;
											end
										else
											return CalcStat("DwarfSturdinessMight",L);
										end
									elseif SN > "DWARFRDTRAITNCPR" then
										if SN < "DWARFRDTRAITVITALITY" then
											if SN == "DWARFRDTRAITPHYMITP" then
												return CalcStat("DwarfSturdinessPhyMitP",L);
											else
												return 0;
											end
										elseif SN > "DWARFRDTRAITVITALITY" then
											if SN == "DWARFSHIELDBRWLBLOCK" then
												return CalcStat("BlockT",L,0.8);
											else
												return 0;
											end
										else
											return CalcStat("DwarfSturdinessVitality",L);
										end
									else
										return CalcStat("DwarfUnwearBattleNCPR",L);
									end
								elseif SN > "DWARFSTOCKYAGILITY" then
									if SN < "DWARFUNWEARBATTLEICMR" then
										if SN < "DWARFSTURDINESSPHYMITP" then
											if SN == "DWARFSTURDINESSMIGHT" then
												return CalcStat("MightT",L,1.0);
											else
												return 0;
											end
										elseif SN > "DWARFSTURDINESSPHYMITP" then
											if SN == "DWARFSTURDINESSVITALITY" then
												return CalcStat("VitalityT",L,1.0);
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "DWARFUNWEARBATTLEICMR" then
										if SN < "DWARFUNWEARBATTLENCMR" then
											if SN == "DWARFUNWEARBATTLEICPR" then
												return CalcStat("ICPRT",L,0.6);
											else
												return 0;
											end
										elseif SN > "DWARFUNWEARBATTLENCMR" then
											if SN == "DWARFUNWEARBATTLENCPR" then
												return -CalcStat("NCPRT",L,0.4);
											else
												return 0;
											end
										else
											return -CalcStat("NCMRT",L,0.4);
										end
									else
										return CalcStat("ICMRT",L,0.6);
									end
								else
									return CalcStat("AgilityT",L,0.4);
								end
							else
								return CalcStat("DwarfUnwearBattleICMR",L);
							end
						elseif SN > "ELFAGILITYWOODSAGILITY" then
							if SN < "EVADEPRATP" then
								if SN < "ELFRDTRAITMORALE" then
									if SN < "ELFRDPSVONENAME" then
										if SN < "ELFFRIENDOFMANFATE" then
											if SN == "ELFFADINGFIRSTBORNFATE" then
												return -CalcStat("FateT",L,0.4);
											else
												return 0;
											end
										elseif SN > "ELFFRIENDOFMANFATE" then
											if SN == "ELFRDPSVONEFATE" then
												return CalcStat("ElfFriendOfManFate",L);
											else
												return 0;
											end
										else
											return CalcStat("FateT",L,1.0);
										end
									elseif SN > "ELFRDPSVONENAME" then
										if SN < "ELFRDTRAITAGILITY" then
											if SN == "ELFRDPSVTWONAME" then
												return "";
											else
												return 0;
											end
										elseif SN > "ELFRDTRAITAGILITY" then
											if SN == "ELFRDTRAITFATE" then
												return CalcStat("ElfFadingFirstbornFate",L);
											else
												return 0;
											end
										else
											return CalcStat("ElfAgilityWoodsAgility",L);
										end
									else
										return "Friend Of Man";
									end
								elseif SN > "ELFRDTRAITMORALE" then
									if SN < "EVADE" then
										if SN < "ELFSORROWFIRSTBORNMORALE" then
											if SN == "ELFRDTRAITNCMR" then
												return CalcStat("ElfSorrowFirstbornNCMR",L);
											else
												return 0;
											end
										elseif SN > "ELFSORROWFIRSTBORNMORALE" then
											if SN == "ELFSORROWFIRSTBORNNCMR" then
												return -CalcStat("NCMRT",L,0.4);
											else
												return 0;
											end
										else
											return -CalcStat("MoraleT",L,0.4);
										end
									elseif SN > "EVADE" then
										if SN < "EVADEPBONUS" then
											if SN == "EVADEC" then
												return CalcStat("BPEC",L,N);
											else
												return 0;
											end
										elseif SN > "EVADEPBONUS" then
											if SN == "EVADEPPRAT" then
												return CalcStat("BPEPPRat",L,N);
											else
												return 0;
											end
										else
											return CalcStat("BPEPBonus",L);
										end
									else
										return CalcStat("BPE",L,N);
									end
								else
									return CalcStat("ElfSorrowFirstbornMorale",L);
								end
							elseif SN > "EVADEPRATP" then
								if SN < "FATEC" then
									if SN < "EVADEPRATPCAP" then
										if SN < "EVADEPRATPB" then
											if SN == "EVADEPRATPA" then
												return CalcStat("BPEPRatPA",L);
											else
												return 0;
											end
										elseif SN > "EVADEPRATPB" then
											if SN == "EVADEPRATPC" then
												return CalcStat("BPEPRatPC",L);
											else
												return 0;
											end
										else
											return CalcStat("BPEPRatPB",L);
										end
									elseif SN > "EVADEPRATPCAP" then
										if SN < "EVADET" then
											if SN == "EVADEPRATPCAPR" then
												return CalcStat("BPEPRatPCapR",L);
											else
												return 0;
											end
										elseif SN > "EVADET" then
											if SN == "FATE" then
												return RoundDblDown(StatLinInter("PntMPFate","ItemPntSVital","ProgBFate","",L,N,0));
											else
												return 0;
											end
										else
											return CalcStat("BPET",L,N);
										end
									else
										return CalcStat("BPEPRatPCap",L);
									end
								elseif SN > "FATEC" then
									if SN < "FINESSEC" then
										if SN < "FEARRESISTT" then
											if SN == "FATET" then
												return RoundDblDown(StatLinInter("PntMPFate","TraitPntSVital","ProgBFate","",L,N,0));
											else
												return 0;
											end
										elseif SN > "FEARRESISTT" then
											if SN == "FINESSE" then
												return StatLinInter("PntMPFinesse","ItemPntS","ProgBFinesse","AdjUmbarItem",L,N,0);
											else
												return 0;
											end
										else
											return CalcStat("ResistAddT",L,N);
										end
									elseif SN > "FINESSEC" then
										if SN < "FINESSEPPRAT" then
											if SN == "FINESSEPBONUS" then
												return 0;
											else
												return 0;
											end
										elseif SN > "FINESSEPPRAT" then
											if SN == "FINESSEPRATP" then
												return CalcPercAB(CalcStat("FinessePRatPA",L),CalcStat("FinessePRatPB",L),CalcStat("FinessePRatPCap",L),N);
											else
												return 0;
											end
										else
											return CalcRatAB(CalcStat("FinessePRatPA",L),CalcStat("FinessePRatPB",L),CalcStat("FinessePRatPCapR",L),N);
										end
									else
										return StatLinInter("PntMPFinesseC","CreepPntS","ProgBFinesseC","",L,N,0);
									end
								else
									return RoundDblDown(StatLinInter("PntMPFateC","CreepPntS","ProgBFateC","",L,N,0));
								end
							else
								return CalcStat("BPEPRatP",L,N);
							end
						else
							return CalcStat("AgilityT",L,1.0);
						end
					else
						return 0.5;
					end
				elseif SN > "FINESSEPRATPA" then
					if SN < "GUARDIANCDBASEPOWER" then
						if SN < "FREEPBATPROMMELDMGP" then
							if SN < "FOODNCPRL" then
								if SN < "FIREMITT" then
									if SN < "FINESSEPRATPCAP" then
										if SN > "FINESSEPRATPB" then
											if SN == "FINESSEPRATPC" then
												return 0.5;
											else
												return 0;
											end
										elseif SN == "FINESSEPRATPB" then
											return CalcStat("BRatRounded",L,"BRatStandard");
										else
											return 0;
										end
									elseif SN > "FINESSEPRATPCAP" then
										if SN < "FINESSET" then
											if SN == "FINESSEPRATPCAPR" then
												return CalcStat("FinessePRatPB",L)*CalcStat("FinessePRatPC",L);
											else
												return 0;
											end
										elseif SN > "FINESSET" then
											if SN == "FIREMIT" then
												return CalcStat("DmgTypeMit",L,N);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPFinesseT","TraitPntS","ProgBFinesse","AdjUmbarTrait",L,N,0);
										end
									else
										return 50;
									end
								elseif SN > "FIREMITT" then
									if SN < "FOODNCMRM" then
										if SN < "FOODNCMRH" then
											if SN == "FOODNCMRBASEPROG" then
												if Lm <= 1 then
													return (N*70.2+210)/60;
												elseif Lm <= 2 then
													return (N*84+216)/120;
												else
													return (N*83.7+270)/90;
												end
											else
												return 0;
											end
										elseif SN > "FOODNCMRH" then
											if SN == "FOODNCMRL" then
												return CalcStat("FoodNCMRProg",L,2)*N;
											else
												return 0;
											end
										else
											return CalcStat("FoodNCMRProg",L,1)*N;
										end
									elseif SN > "FOODNCMRM" then
										if SN < "FOODNCPRBASEPROG" then
											if SN == "FOODNCMRPROG" then
												if Lm <= 50 then
													return CalcStat("FoodNCMRBaseProg",N,L);
												elseif Lm <= 52 then
													return CalcStat("FoodNCMRBaseProg",N,50);
												elseif Lm <= 77 then
													return CalcStat("FoodNCMRBaseProg",N,L-3);
												elseif Lm <= 111 then
													return CalcStat("FoodNCMRBaseProg",N,RoundDbl((L+143)/3));
												elseif Lm <= 140 then
													return CalcStat("FoodNCMRBaseProg",N,85);
												elseif Lm <= 217 then
													return CalcStat("FoodNCMRBaseProg",N,RoundDbl((L+200)/4));
												elseif Lm <= 221 then
													return CalcStat("FoodNCMRBaseProg",N,104);
												elseif Lm <= 299 then
													return CalcStat("FoodNCMRBaseProg",N,105);
												elseif Lm <= 320 then
													return CalcStat("FoodNCMRBaseProg",N,RoundDbl((L-53)/(7/3)));
												elseif Lm <= 325 then
													return CalcStat("FoodNCMRBaseProg",N,114);
												elseif Lm <= 326 then
													return CalcStat("FoodNCMRBaseProg",N,115);
												else
													return ExpFmod(CalcStat("FoodNCMRProg",326,N),327,1,L,1);
												end
											else
												return 0;
											end
										elseif SN > "FOODNCPRBASEPROG" then
											if SN == "FOODNCPRH" then
												return CalcStat("FoodNCPRProg",L,1)*N;
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return (N*75+300)/60;
											elseif Lm <= 2 then
												return (N*100+350)/120;
											else
												return (N*90+337.5)/90;
											end
										end
									else
										return CalcStat("FoodNCMRProg",L,3)*N;
									end
								else
									return CalcStat("DmgTypeMitT",L,N);
								end
							elseif SN > "FOODNCPRL" then
								if SN < "FREEPAUDACITYMORALEP" then
									if SN < "FREEPAUDACITYCCDP" then
										if SN < "FOODNCPRPROG" then
											if SN == "FOODNCPRM" then
												return CalcStat("FoodNCPRProg",L,3)*N;
											else
												return 0;
											end
										elseif SN > "FOODNCPRPROG" then
											if SN == "FOODRESIST" then
												return StatLinInter("PntMPFoodResist","ItemPntS","ProgBResist","AdjUmbarItem",L,N,0);
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return CalcStat("FoodNCPRBaseProg",N,L);
											elseif Lm <= 6 then
												return CalcStat("FoodNCPRBaseProg",N,L)-0.25;
											elseif Lm <= 24 then
												return CalcStat("FoodNCPRBaseProg",N,L)-0.5;
											elseif Lm <= 48 then
												return CalcStat("FoodNCPRBaseProg",N,L)-0.75;
											elseif Lm <= 61 then
												return RoundDblDown(CalcStat("FoodNCPRProg",48,N))+1;
											elseif Lm <= 66 then
												return RoundDblDown(CalcStat("FoodNCPRProg",48,N))+2;
											elseif Lm <= 72 then
												return RoundDblDown(CalcStat("FoodNCPRProg",48,N))+3;
											elseif Lm <= 326 then
												return RoundDblDown(CalcStat("FoodNCPRProg",48,N))+4;
											else
												return ExpFmod(CalcStat("FoodNCPRProg",326,N),327,1,L,1);
											end
										end
									elseif SN > "FREEPAUDACITYCCDP" then
										if SN < "FREEPAUDACITYMELDMGP" then
											if SN == "FREEPAUDACITYDMGP" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 16 then
													return 0.75;
												elseif Lm <= 36 then
													return LinFmod(1,1.15,1.25,17,36,L);
												else
													return 1.25;
												end
											else
												return 0;
											end
										elseif SN > "FREEPAUDACITYMELDMGP" then
											if SN == "FREEPAUDACITYMELREDP" then
												return CalcStat("FreepAudacityRedP",L);
											else
												return 0;
											end
										else
											return CalcStat("FreepAudacityDmgP",L);
										end
									else
										if Lm <= 0 then
											return 0;
										elseif Lm <= 16 then
											return 0.5;
										else
											return 0.4;
										end
									end
								elseif SN > "FREEPAUDACITYMORALEP" then
									if SN < "FREEPAUDACITYTACDMGP" then
										if SN < "FREEPAUDACITYRNGDMGP" then
											if SN == "FREEPAUDACITYREDP" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 16 then
													return 1.5;
												else
													return 0.55;
												end
											else
												return 0;
											end
										elseif SN > "FREEPAUDACITYRNGDMGP" then
											if SN == "FREEPAUDACITYRNGREDP" then
												return CalcStat("FreepAudacityRedP",L);
											else
												return 0;
											end
										else
											return CalcStat("FreepAudacityDmgP",L);
										end
									elseif SN > "FREEPAUDACITYTACDMGP" then
										if SN < "FREEPBATPROMDMGP" then
											if SN == "FREEPAUDACITYTACREDP" then
												return CalcStat("FreepAudacityRedP",L);
											else
												return 0;
											end
										elseif SN > "FREEPBATPROMDMGP" then
											if SN == "FREEPBATPROMHEALTHP" then
												return CalcStat("FreepBatPromVitalP",L);
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											elseif Lm <= 1 then
												return 0.005;
											elseif Lm <= 14 then
												return LinFmod(1,0.005,0.065,2,14,L);
											else
												return 0.075;
											end
										end
									else
										return CalcStat("FreepAudacityDmgP",L);
									end
								else
									if Lm <= 0 then
										return 0;
									elseif Lm <= 16 then
										return LinFmod(1,0.5,1.3,1,16,L);
									else
										return 1.4;
									end
								end
							else
								return CalcStat("FoodNCPRProg",L,2)*N;
							end
						elseif SN > "FREEPBATPROMMELDMGP" then
							if SN < "GUARDIANCDAGILITYTOFINESSE" then
								if SN < "GRDRELENTLASSFINESSE" then
									if SN < "FREEPBATPROMVITALP" then
										if SN < "FREEPBATPROMRNGDMGP" then
											if SN == "FREEPBATPROMPOWERP" then
												return CalcStat("FreepBatPromVitalP",L);
											else
												return 0;
											end
										elseif SN > "FREEPBATPROMRNGDMGP" then
											if SN == "FREEPBATPROMTACDMGP" then
												return CalcStat("FreepBatPromDmgP",L);
											else
												return 0;
											end
										else
											return CalcStat("FreepBatPromDmgP",L);
										end
									elseif SN > "FREEPBATPROMVITALP" then
										if SN < "FROSTMITT" then
											if SN == "FROSTMIT" then
												return CalcStat("DmgTypeMit",L,N);
											else
												return 0;
											end
										elseif SN > "FROSTMITT" then
											if SN == "GRDCRITDEF" then
												return CalcStat("CritDef",L);
											else
												return 0;
											end
										else
											return CalcStat("DmgTypeMitT",L,N);
										end
									else
										if Lm <= 0 then
											return 0;
										elseif Lm <= 5 then
											return LinFmod(1,1.02,1.1,1,5,L);
										elseif Lm <= 10 then
											return LinFmod(1,1.1,1.15,5,10,L);
										elseif Lm <= 15 then
											return LinFmod(1,1.15,1.2,10,15,L);
										else
											return CalcStat("FreepBatPromVitalP",15);
										end
									end
								elseif SN > "GRDRELENTLASSFINESSE" then
									if SN < "GRDTENDERIZET4CRITHIT" then
										if SN < "GRDTENDERIZET2CRITHIT" then
											if SN == "GRDTENDERIZECRITHIT" then
												return CalcStat("CritHitT",L,CalcStat("Trait12345Choice",N)*0.2);
											else
												return 0;
											end
										elseif SN > "GRDTENDERIZET2CRITHIT" then
											if SN == "GRDTENDERIZET3CRITHIT" then
												return CalcStat("CritHitT",L,CalcStat("Trait357912Choice",N)*0.2);
											else
												return 0;
											end
										else
											return CalcStat("CritHitT",L,CalcStat("Trait12345Choice",N)*0.4);
										end
									elseif SN > "GRDTENDERIZET4CRITHIT" then
										if SN < "GRDWARDTACTTACMIT" then
											if SN == "GRDTENDERIZET5CRITHIT" then
												return CalcStat("CritHitT",L,CalcStat("Trait58121620Choice",N)*0.2);
											else
												return 0;
											end
										elseif SN > "GRDWARDTACTTACMIT" then
											if SN == "GUARDIANCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										else
											return CalcStat("TacMitT",L,CalcStat("Trait12345Choice",N)*0.2);
										end
									else
										return CalcStat("CritHitT",L,CalcStat("Trait47101316Choice",N)*0.2);
									end
								else
									return CalcStat("FinesseT",L,CalcStat("Trait12345Choice",N)*0.2);
								end
							elseif SN > "GUARDIANCDAGILITYTOFINESSE" then
								if SN < "GUARDIANCDBASEAGILITY" then
									if SN < "GUARDIANCDARMOURTOCOMPHYMIT" then
										if SN < "GUARDIANCDAGILITYTOPARRY" then
											if SN == "GUARDIANCDAGILITYTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDAGILITYTOPARRY" then
											if SN == "GUARDIANCDAGILITYTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "GUARDIANCDARMOURTOCOMPHYMIT" then
										if SN < "GUARDIANCDARMOURTOTACMIT" then
											if SN == "GUARDIANCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDARMOURTOTACMIT" then
											if SN == "GUARDIANCDARMOURTYPE" then
												return 3;
											else
												return 0;
											end
										else
											return 0.2;
										end
									else
										return 1;
									end
								elseif SN > "GUARDIANCDBASEAGILITY" then
									if SN < "GUARDIANCDBASEMIGHT" then
										if SN < "GUARDIANCDBASEICMR" then
											if SN == "GUARDIANCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										elseif SN > "GUARDIANCDBASEICMR" then
											if SN == "GUARDIANCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICMRH",L);
										end
									elseif SN > "GUARDIANCDBASEMIGHT" then
										if SN < "GUARDIANCDBASENCMR" then
											if SN == "GUARDIANCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										elseif SN > "GUARDIANCDBASENCMR" then
											if SN == "GUARDIANCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCMRH",L);
										end
									else
										return CalcStat("ClassBaseMightH",L);
									end
								else
									return CalcStat("ClassBaseAgilityM",L);
								end
							else
								return 1;
							end
						else
							return CalcStat("FreepBatPromDmgP",L);
						end
					elseif SN > "GUARDIANCDBASEPOWER" then
						if SN < "HELFPEACEELDARNCMR" then
							if SN < "GUARDIANCDMIGHTTOPHYMIT" then
								if SN < "GUARDIANCDFATETONCPR" then
									if SN < "GUARDIANCDCALCTYPECOMPHYMIT" then
										if SN > "GUARDIANCDBASEVITALITY" then
											if SN == "GUARDIANCDBASEWILL" then
												return CalcStat("ClassBaseWillL",L);
											else
												return 0;
											end
										elseif SN == "GUARDIANCDBASEVITALITY" then
											return CalcStat("ClassBaseVitality",L);
										else
											return 0;
										end
									elseif SN > "GUARDIANCDCALCTYPECOMPHYMIT" then
										if SN < "GUARDIANCDCALCTYPETACMIT" then
											if SN == "GUARDIANCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDCALCTYPETACMIT" then
											if SN == "GUARDIANCDCANBLOCK" then
												return 1;
											else
												return 0;
											end
										else
											return 27;
										end
									else
										return 14;
									end
								elseif SN > "GUARDIANCDFATETONCPR" then
									if SN < "GUARDIANCDMIGHTTOCRITHIT" then
										if SN < "GUARDIANCDHASPOWER" then
											if SN == "GUARDIANCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDHASPOWER" then
											if SN == "GUARDIANCDMIGHTTOBLOCK" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "GUARDIANCDMIGHTTOCRITHIT" then
										if SN < "GUARDIANCDMIGHTTOPARRY" then
											if SN == "GUARDIANCDMIGHTTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDMIGHTTOPARRY" then
											if SN == "GUARDIANCDMIGHTTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 2;
										end
									else
										return 1;
									end
								else
									return 0.07;
								end
							elseif SN > "GUARDIANCDMIGHTTOPHYMIT" then
								if SN < "GUARDIANCDWILLTOFINESSE" then
									if SN < "GUARDIANCDTACMASTOOUTHEAL" then
										if SN < "GUARDIANCDPHYMITTOCOMPHYMIT" then
											if SN == "GUARDIANCDMIGHTTOTACMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDPHYMITTOCOMPHYMIT" then
											if SN == "GUARDIANCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "GUARDIANCDTACMASTOOUTHEAL" then
										if SN < "GUARDIANCDVITALITYTOMORALE" then
											if SN == "GUARDIANCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDVITALITYTOMORALE" then
											if SN == "GUARDIANCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										else
											return 4.5;
										end
									else
										return 1;
									end
								elseif SN > "GUARDIANCDWILLTOFINESSE" then
									if SN < "GUARDIANCDWILLTORESIST" then
										if SN < "GUARDIANCDWILLTOPHYMAS" then
											if SN == "GUARDIANCDWILLTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "GUARDIANCDWILLTOPHYMAS" then
											if SN == "GUARDIANCDWILLTOPHYMIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "GUARDIANCDWILLTORESIST" then
										if SN < "HELFFADINGFIRSTBORNFATE" then
											if SN == "GUARDIANCDWILLTOTACMIT" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "HELFFADINGFIRSTBORNFATE" then
											if SN == "HELFPEACEELDARMORALE" then
												return CalcStat("MoraleT",L,1.0);
											else
												return 0;
											end
										else
											return -CalcStat("FateT",L,0.4);
										end
									else
										return 1;
									end
								else
									return 1;
								end
							else
								return 1;
							end
						elseif SN > "HELFPEACEELDARNCMR" then
							if SN < "HNTPRECISIONSTANCEFINESSE" then
								if SN < "HIGHELFRDTRAITNCMR" then
									if SN < "HIGHELFRDPSVONEWILL" then
										if SN < "HELFTHOSEWHOREMAINWILL" then
											if SN == "HELFSORROWUNDYINGWILL" then
												return -CalcStat("WillT",L,0.4);
											else
												return 0;
											end
										elseif SN > "HELFTHOSEWHOREMAINWILL" then
											if SN == "HIGHELFRDPSVONENAME" then
												return "Those Who Remain";
											else
												return 0;
											end
										else
											return CalcStat("WillT",L,1.0);
										end
									elseif SN > "HIGHELFRDPSVONEWILL" then
										if SN < "HIGHELFRDTRAITFATE" then
											if SN == "HIGHELFRDPSVTWONAME" then
												return "";
											else
												return 0;
											end
										elseif SN > "HIGHELFRDTRAITFATE" then
											if SN == "HIGHELFRDTRAITMORALE" then
												return CalcStat("HElfPeaceEldarMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("HElfFadingFirstbornFate",L);
										end
									else
										return CalcStat("HElfThoseWhoRemainWill",L);
									end
								elseif SN > "HIGHELFRDTRAITNCMR" then
									if SN < "HNTARMOURRENDPARRY" then
										if SN < "HNTARMOURRENDBLOCK" then
											if SN == "HIGHELFRDTRAITWILL" then
												return CalcStat("HElfSorrowUndyingWill",L);
											else
												return 0;
											end
										elseif SN > "HNTARMOURRENDBLOCK" then
											if SN == "HNTARMOURRENDEVADE" then
												return -CalcStat("EvadeT",L,CalcStat("Trait23456Choice",N)*0.4);
											else
												return 0;
											end
										else
											return -CalcStat("ShieldBlock",L,CalcStat("Trait23456Choice",N)*0.4);
										end
									elseif SN > "HNTARMOURRENDPARRY" then
										if SN < "HNTCAMPFIRENCMR" then
											if SN == "HNTBREACHFINDERRNGMIT" then
												return (-20)*L;
											else
												return 0;
											end
										elseif SN > "HNTCAMPFIRENCMR" then
											if SN == "HNTCAMPFIRENCPR" then
												return CalcStat("NCPRT",L,1.2);
											else
												return 0;
											end
										else
											return CalcStat("NCMRT",L,1.2);
										end
									else
										return -CalcStat("ParryT",L,CalcStat("Trait23456Choice",N)*0.4);
									end
								else
									return CalcStat("HElfPeaceEldarNCMR",L);
								end
							elseif SN > "HNTPRECISIONSTANCEFINESSE" then
								if SN < "HOBBITRDTRAITMIGHT" then
									if SN < "HNTSTRENGTHSTANCECRITHIT" then
										if SN < "HNTRAPIDFIREPHYMAS" then
											if SN == "HNTPURGEPOISONRESIST" then
												return CalcStat("PoisonResistT",L,4);
											else
												return 0;
											end
										elseif SN > "HNTRAPIDFIREPHYMAS" then
											if SN == "HNTRAPIDFIRESEL" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 8 then
													return L+2;
												elseif Lm <= 10 then
													return 2*L-6;
												else
													return CalcStat("HntRapidFireSel",10);
												end
											else
												return 0;
											end
										else
											return CalcStat("PhyMasT",L,CalcStat("HntRapidFireSel",N)*0.2);
										end
									elseif SN > "HNTSTRENGTHSTANCECRITHIT" then
										if SN < "HOBBITRDPSVONENAME" then
											if SN == "HOBBITRDPSVONEMIGHT" then
												return CalcStat("HobHobbitStatureMight",L);
											else
												return 0;
											end
										elseif SN > "HOBBITRDPSVONENAME" then
											if SN == "HOBBITRDPSVTWONAME" then
												return "";
											else
												return 0;
											end
										else
											return "Hobbit-stature";
										end
									else
										return CalcStat("CritHitT",L,4);
									end
								elseif SN > "HOBBITRDTRAITMIGHT" then
									if SN < "HOBHOBBITTOUGHNVITALITY" then
										if SN < "HOBBITRDTRAITVITALITY" then
											if SN == "HOBBITRDTRAITNCMR" then
												return CalcStat("HobRapidRecoveryNCMR",L);
											else
												return 0;
											end
										elseif SN > "HOBBITRDTRAITVITALITY" then
											if SN == "HOBHOBBITSTATUREMIGHT" then
												return CalcStat("MightT",L,1.0);
											else
												return 0;
											end
										else
											return CalcStat("HobHobbitToughnVitality",L);
										end
									elseif SN > "HOBHOBBITTOUGHNVITALITY" then
										if SN < "HOBSMALLSIZEMIGHT" then
											if SN == "HOBRAPIDRECOVERYNCMR" then
												return CalcStat("NCMRT",L,0.6);
											else
												return 0;
											end
										elseif SN > "HOBSMALLSIZEMIGHT" then
											if SN == "HOPEMORALEP" then
												if Lm <= 5 then
													return DataTableValue({-0.99,-0.97,-0.95,-0.9,-0.85,-0.8,-0.65,-0.6,-0.5,-0.4,-0.3,-0.2,-0.15,-0.1,-0.05,0,0.01,0.02,0.03,0.04,0.05},L+16);
												else
													return 0.05;
												end
											else
												return 0;
											end
										else
											return -CalcStat("MightT",L,0.4);
										end
									else
										return CalcStat("VitalityT",L,1.0);
									end
								else
									return CalcStat("HobSmallSizeMight",L);
								end
							else
								return CalcStat("FinesseT",L,1.6);
							end
						else
							return CalcStat("NCMRT",L,0.6);
						end
					else
						return CalcStat("ClassBasePower",L);
					end
				else
					return 150;
				end
			elseif SN > "HUNTERCDAGILITYTOCRITHIT" then
				if SN < "LOREMASTERCDCALCTYPECOMPHYMIT" then
					if SN < "INHEALPPRAT" then
						if SN < "HUNTERCDMIGHTTOOUTHEAL" then
							if SN < "HUNTERCDBASEMIGHT" then
								if SN < "HUNTERCDARMOURTOCOMPHYMIT" then
									if SN < "HUNTERCDAGILITYTOPARRY" then
										if SN > "HUNTERCDAGILITYTOEVADE" then
											if SN == "HUNTERCDAGILITYTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN == "HUNTERCDAGILITYTOEVADE" then
											return 2;
										else
											return 0;
										end
									elseif SN > "HUNTERCDAGILITYTOPARRY" then
										if SN < "HUNTERCDAGILITYTOPHYMIT" then
											if SN == "HUNTERCDAGILITYTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										elseif SN > "HUNTERCDAGILITYTOPHYMIT" then
											if SN == "HUNTERCDAGILITYTOTACMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "HUNTERCDARMOURTOCOMPHYMIT" then
									if SN < "HUNTERCDBASEAGILITY" then
										if SN < "HUNTERCDARMOURTOTACMIT" then
											if SN == "HUNTERCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "HUNTERCDARMOURTOTACMIT" then
											if SN == "HUNTERCDARMOURTYPE" then
												return 2;
											else
												return 0;
											end
										else
											return 0.2;
										end
									elseif SN > "HUNTERCDBASEAGILITY" then
										if SN < "HUNTERCDBASEICMR" then
											if SN == "HUNTERCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										elseif SN > "HUNTERCDBASEICMR" then
											if SN == "HUNTERCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICMRM",L);
										end
									else
										return CalcStat("ClassBaseAgilityH",L);
									end
								else
									return 1;
								end
							elseif SN > "HUNTERCDBASEMIGHT" then
								if SN < "HUNTERCDCALCTYPENONPHYMIT" then
									if SN < "HUNTERCDBASEPOWER" then
										if SN < "HUNTERCDBASENCMR" then
											if SN == "HUNTERCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										elseif SN > "HUNTERCDBASENCMR" then
											if SN == "HUNTERCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCMRM",L);
										end
									elseif SN > "HUNTERCDBASEPOWER" then
										if SN < "HUNTERCDBASEWILL" then
											if SN == "HUNTERCDBASEVITALITY" then
												return CalcStat("ClassBaseVitality",L);
											else
												return 0;
											end
										elseif SN > "HUNTERCDBASEWILL" then
											if SN == "HUNTERCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseWillL",L);
										end
									else
										return CalcStat("ClassBasePower",L);
									end
								elseif SN > "HUNTERCDCALCTYPENONPHYMIT" then
									if SN < "HUNTERCDHASPOWER" then
										if SN < "HUNTERCDFATETONCPR" then
											if SN == "HUNTERCDCALCTYPETACMIT" then
												return 26;
											else
												return 0;
											end
										elseif SN > "HUNTERCDFATETONCPR" then
											if SN == "HUNTERCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 0.07;
										end
									elseif SN > "HUNTERCDHASPOWER" then
										if SN < "HUNTERCDMIGHTTOEVADE" then
											if SN == "HUNTERCDMIGHTTOCRITHIT" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "HUNTERCDMIGHTTOEVADE" then
											if SN == "HUNTERCDMIGHTTOFINESSE" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								else
									return 13;
								end
							else
								return CalcStat("ClassBaseMightM",L);
							end
						elseif SN > "HUNTERCDMIGHTTOOUTHEAL" then
							if SN < "ICMRCRAW" then
								if SN < "HUNTERCDWILLTOCRITHIT" then
									if SN < "HUNTERCDTACMASTOOUTHEAL" then
										if SN < "HUNTERCDPHYMITTOCOMPHYMIT" then
											if SN == "HUNTERCDMIGHTTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										elseif SN > "HUNTERCDPHYMITTOCOMPHYMIT" then
											if SN == "HUNTERCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "HUNTERCDTACMASTOOUTHEAL" then
										if SN < "HUNTERCDVITALITYTOMORALE" then
											if SN == "HUNTERCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										elseif SN > "HUNTERCDVITALITYTOMORALE" then
											if SN == "HUNTERCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										else
											return 4.5;
										end
									else
										return 1;
									end
								elseif SN > "HUNTERCDWILLTOCRITHIT" then
									if SN < "HUNTERCDWILLTOPHYMIT" then
										if SN < "HUNTERCDWILLTOOUTHEAL" then
											if SN == "HUNTERCDWILLTOFINESSE" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "HUNTERCDWILLTOOUTHEAL" then
											if SN == "HUNTERCDWILLTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "HUNTERCDWILLTOPHYMIT" then
										if SN < "ICMR" then
											if SN == "HUNTERCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										elseif SN > "ICMR" then
											if SN == "ICMRC" then
												return StatLinInter("PntMPICMRC","CreepPntS","ProgBICMRC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPICMR","ItemPntSVital","ProgBICMR","",L,N,1);
										end
									else
										return 1;
									end
								else
									return 0.5;
								end
							elseif SN > "ICMRCRAW" then
								if SN < "INDMGPRATP" then
									if SN < "ICPRCRAW" then
										if SN < "ICPR" then
											if SN == "ICMRT" then
												return StatLinInter("PntMPICMR","TraitPntSVital","ProgBICMR","",L,N,1);
											else
												return 0;
											end
										elseif SN > "ICPR" then
											if SN == "ICPRC" then
												return StatLinInter("PntMPICPRC","CreepPntS","ProgBICPRC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPICPR","ItemPntSVital","ProgBICPR","",L,N,99);
										end
									elseif SN > "ICPRCRAW" then
										if SN < "INDMGPBONUS" then
											if SN == "ICPRT" then
												return StatLinInter("PntMPICPR","TraitPntSVital","ProgBICPR","",L,N,99);
											else
												return 0;
											end
										elseif SN > "INDMGPBONUS" then
											if SN == "INDMGPPRAT" then
												return CalcRatAB(CalcStat("InDmgPRatPA",L),CalcStat("InDmgPRatPB",L),CalcStat("InDmgPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									else
										return StatLinInter("PntMPICPRCOld","CreepPntS","ProgBICPRC","",L,N,99);
									end
								elseif SN > "INDMGPRATP" then
									if SN < "INDMGPRATPCAP" then
										if SN < "INDMGPRATPB" then
											if SN == "INDMGPRATPA" then
												return 1200;
											else
												return 0;
											end
										elseif SN > "INDMGPRATPB" then
											if SN == "INDMGPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatStandard");
										end
									elseif SN > "INDMGPRATPCAP" then
										if SN < "INHEAL" then
											if SN == "INDMGPRATPCAPR" then
												return CalcStat("InDmgPRatPB",L)*CalcStat("InDmgPRatPC",L);
											else
												return 0;
											end
										elseif SN > "INHEAL" then
											if SN == "INHEALPBONUS" then
												return 0;
											else
												return 0;
											end
										else
											return StatLinInter("PntMPInHeal","ItemPntS","ProgBInHeal","AdjUmbarItem",L,N,0);
										end
									else
										return 400;
									end
								else
									return CalcPercAB(CalcStat("InDmgPRatPA",L),CalcStat("InDmgPRatPB",L),CalcStat("InDmgPRatPCap",L),N);
								end
							else
								return StatLinInter("PntMPICMRCOld","CreepPntS","ProgBICMRC","",L,N,99);
							end
						else
							return 2;
						end
					elseif SN > "INHEALPPRAT" then
						if SN < "LMKNOWLEDGELMTACRES" then
							if SN < "L" then
								if SN < "INHEALT" then
									if SN < "INHEALPRATPB" then
										if SN > "INHEALPRATP" then
											if SN == "INHEALPRATPA" then
												return 75;
											else
												return 0;
											end
										elseif SN == "INHEALPRATP" then
											return CalcPercAB(CalcStat("InHealPRatPA",L),CalcStat("InHealPRatPB",L),CalcStat("InHealPRatPCap",L),N);
										else
											return 0;
										end
									elseif SN > "INHEALPRATPB" then
										if SN < "INHEALPRATPCAP" then
											if SN == "INHEALPRATPC" then
												return 0.5;
											else
												return 0;
											end
										elseif SN > "INHEALPRATPCAP" then
											if SN == "INHEALPRATPCAPR" then
												return CalcStat("InHealPRatPB",L)*CalcStat("InHealPRatPC",L);
											else
												return 0;
											end
										else
											return 25;
										end
									else
										return CalcStat("BRatRounded",L,"BRatStandard");
									end
								elseif SN > "INHEALT" then
									if SN < "ITEMPNTSCLASSIC" then
										if SN < "INSTRPOWER" then
											if SN == "INSTRMORALE" then
												if Lm <= 105 then
													return RoundDbl(4.04*L);
												else
													return CalcStat("ProgExtLowExpRnd",L,CalcStat("InstrMorale",105));
												end
											else
												return 0;
											end
										elseif SN > "INSTRPOWER" then
											if SN == "ITEMPNTS" then
												return {{1,25,79,80,200,225,300,349,350,399,400,449,450,499,500,549,550,599},{1,25,75,76,100,105,106,115,116,120,121,130,131,140,141,150,151,160}};
											else
												return 0;
											end
										else
											if Lm <= 9 then
												return RoundDbl(0.95*L+12.6);
											elseif Lm <= 18 then
												return RoundDbl(1.95*L+3);
											elseif Lm <= 26 then
												return RoundDbl(2.95*L-15.55);
											elseif Lm <= 35 then
												return RoundDbl(3.95*L-42.15);
											elseif Lm <= 42 then
												return RoundDbl(4.95*L-77.7);
											elseif Lm <= 45 then
												return RoundDbl(5.95*L-120.35);
											elseif Lm <= 105 then
												return RoundDbl(6*L-124);
											else
												return CalcStat("ProgExtMpExpRnd",L,CalcStat("InstrPower",105));
											end
										end
									elseif SN > "ITEMPNTSCLASSIC" then
										if SN < "ITEMPNTSVIRTUEMORALE" then
											if SN == "ITEMPNTSVIRTUEMASTERY" then
												return {{0,1,25,79,80,200,225,300,349,350,400,449,450,499,500,549,550,599},{0,1,25,75,76,100,105,106,115,116,121,130,131,140,141,150,151,160}};
											else
												return 0;
											end
										elseif SN > "ITEMPNTSVIRTUEMORALE" then
											if SN == "ITEMPNTSVITAL" then
												return {{1,25,50,60,79,80,200,225,300,349,350,399,400,449,450,499,500,549,550,599},{1,25,50,60,75,76,100,105,106,115,116,120,121,130,131,140,141,150,151,160}};
											else
												return 0;
											end
										else
											return {{0,1,2,50,80,200,225,300,349,350,399,400,449,450,499,500,549,550,599},{0,1,2,50,76,100,105,106,115,116,120,121,130,131,140,141,150,151,160}};
										end
									else
										return {{1,25,50,60,79,80,200,225,300,349,350,399,400,449,450,499,500,549,550,599},{1,25,50,60,75,76,100,105,106,115,116,120,121,130,131,140,141,150,151,160}};
									end
								else
									return StatLinInter("PntMPInHeal","TraitPntS","ProgBInHeal","AdjUmbarTrait",L,N,0);
								end
							elseif SN > "L" then
								if SN < "LMANCIENTWISDOMWILL" then
									if SN < "LIGHTMIT" then
										if SN < "LI2ILVLCAP" then
											if SN == "LEVELCAP" then
												return 150;
											else
												return 0;
											end
										elseif SN > "LI2ILVLCAP" then
											if SN == "LI2REFORGEILVL" then
												if Lm <= 145 then
													return CalcStat("AwardILvlI",L);
												else
													return N;
												end
											else
												return 0;
											end
										else
											return 520;
										end
									elseif SN > "LIGHTMIT" then
										if SN < "LIGHTNINGMIT" then
											if SN == "LIGHTMITT" then
												return CalcStat("DmgTypeMitT",L,N);
											else
												return 0;
											end
										elseif SN > "LIGHTNINGMIT" then
											if SN == "LIGHTNINGMITT" then
												return CalcStat("DmgTypeMitT",L,N);
											else
												return 0;
											end
										else
											return CalcStat("DmgTypeMit",L,N);
										end
									else
										return CalcStat("DmgTypeMit",L,N);
									end
								elseif SN > "LMANCIENTWISDOMWILL" then
									if SN < "LMHEARTYDIETMORALE" then
										if SN < "LMEAGLENOBILITYICPR" then
											if SN == "LMCATMINTBEARARMOUR" then
												return CalcStat("BaseArmour",L,15);
											else
												return 0;
											end
										elseif SN > "LMEAGLENOBILITYICPR" then
											if SN == "LMEVASIONRAVENARMOUR" then
												return CalcStat("ArmourT",L,0.8);
											else
												return 0;
											end
										else
											return CalcStat("ICPRT",L,0.8);
										end
									elseif SN > "LMHEARTYDIETMORALE" then
										if SN < "LMKNOWLEDGELMPHYRES" then
											if SN == "LMKNOWLEDGELMCRYRES" then
												return -CalcStat("CryResistT",L,0.6);
											else
												return 0;
											end
										elseif SN > "LMKNOWLEDGELMPHYRES" then
											if SN == "LMKNOWLEDGELMSONGRES" then
												return -CalcStat("SongResistT",L,0.6);
											else
												return 0;
											end
										else
											return -CalcStat("PhyResistT",L,0.6);
										end
									else
										return CalcStat("Morale",L,CalcStat("Trait12345Choice",N)*0.4);
									end
								else
									if Lm <= 105 then
										return RoundDbl(1.1*L);
									else
										return CalcStat("ProgExtLowExpRnd",L,CalcStat("LmAncientWisdomWill",105));
									end
								end
							else
								return L;
							end
						elseif SN > "LMKNOWLEDGELMTACRES" then
							if SN < "LOREMASTERCDAGILITYTOTACMAS" then
								if SN < "LMSWSTAFFBUGMORALE" then
									if SN < "LMRAVENSHOTRAVWINGTACMIT" then
										if SN < "LMPREPFORWARTACMAS" then
											if SN == "LMPREPFORWARPETTACMAS" then
												return CalcStat("TacMas",L,3.0);
											else
												return 0;
											end
										elseif SN > "LMPREPFORWARTACMAS" then
											if SN == "LMRAVENSHOTRAVWINGFIXTACMIT" then
												return CalcStat("TacMitT",L,2);
											else
												return 0;
											end
										else
											return CalcStat("TacMasT",L,CalcStat("Trait12345Choice",N)*0.4);
										end
									elseif SN > "LMRAVENSHOTRAVWINGTACMIT" then
										if SN < "LMRINGOFFIREEVADE" then
											if SN == "LMRINGOFFIREBLOCK" then
												return -CalcStat("BlockT",L,2.4);
											else
												return 0;
											end
										elseif SN > "LMRINGOFFIREEVADE" then
											if SN == "LMRINGOFFIREPARRY" then
												return -CalcStat("ParryT",L,2.4);
											else
												return 0;
											end
										else
											return -CalcStat("EvadeT",L,2.4);
										end
									else
										return CalcStat("TacMitT",L,2);
									end
								elseif SN > "LMSWSTAFFBUGMORALE" then
									if SN < "LOEPASSIVE" then
										if SN < "LMSWSTAFFBUGPARRYOLD" then
											if SN == "LMSWSTAFFBUGPARRY" then
												if Lm <= 140 then
													return CalcStat("U371LegacyStatFix",L,"LmSwStaffBugParryOld");
												else
													return CalcStat("LMSwStaffBugParry",140);
												end
											else
												return 0;
											end
										elseif SN > "LMSWSTAFFBUGPARRYOLD" then
											if SN == "LOE" then
												return 2*N;
											else
												return 0;
											end
										else
											if Lm <= 105 then
												return RoundDbl(44.44*L);
											else
												return CalcStat("ProgExtHighLinExpRnd",L,CalcStat("LmSwStaffBugParryOld",105));
											end
										end
									elseif SN > "LOEPASSIVE" then
										if SN < "LOREMASTERCDAGILITYTOEVADE" then
											if SN == "LOREMASTERCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDAGILITYTOEVADE" then
											if SN == "LOREMASTERCDAGILITYTOFINESSE" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										if Lm <= 115 then
											return 0;
										elseif Lm <= 119 then
											return 20*L-2300;
										else
											return CalcStat("LoEPassive",119);
										end
									end
								else
									if Lm <= 105 then
										return RoundDbl(LinFmod(1,16.2,696.9,1,105,L));
									else
										return CalcStat("ProgExtLowExpRnd",L,CalcStat("LmSwStaffBugMorale",105));
									end
								end
							elseif SN > "LOREMASTERCDAGILITYTOTACMAS" then
								if SN < "LOREMASTERCDBASEICPR" then
									if SN < "LOREMASTERCDARMOURTYPE" then
										if SN < "LOREMASTERCDARMOURTONONPHYMIT" then
											if SN == "LOREMASTERCDARMOURTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDARMOURTONONPHYMIT" then
											if SN == "LOREMASTERCDARMOURTOTACMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 0.2;
										end
									elseif SN > "LOREMASTERCDARMOURTYPE" then
										if SN < "LOREMASTERCDBASEFATE" then
											if SN == "LOREMASTERCDBASEAGILITY" then
												return CalcStat("ClassBaseAgilityL",L);
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDBASEFATE" then
											if SN == "LOREMASTERCDBASEICMR" then
												return CalcStat("ClassBaseICMRL",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseFate",L);
										end
									else
										return 1;
									end
								elseif SN > "LOREMASTERCDBASEICPR" then
									if SN < "LOREMASTERCDBASENCPR" then
										if SN < "LOREMASTERCDBASEMORALE" then
											if SN == "LOREMASTERCDBASEMIGHT" then
												return CalcStat("ClassBaseMightM",L);
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDBASEMORALE" then
											if SN == "LOREMASTERCDBASENCMR" then
												return CalcStat("ClassBaseNCMRL",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMorale",L);
										end
									elseif SN > "LOREMASTERCDBASENCPR" then
										if SN < "LOREMASTERCDBASEVITALITY" then
											if SN == "LOREMASTERCDBASEPOWER" then
												return CalcStat("ClassBasePower",L);
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDBASEVITALITY" then
											if SN == "LOREMASTERCDBASEWILL" then
												return CalcStat("ClassBaseWillH",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseVitality",L);
										end
									else
										return CalcStat("ClassBaseNCPR",L);
									end
								else
									return CalcStat("ClassBaseICPR",L);
								end
							else
								return 2;
							end
						else
							return -CalcStat("TacResistT",L,0.6);
						end
					else
						return CalcRatAB(CalcStat("InHealPRatPA",L),CalcStat("InHealPRatPB",L),CalcStat("InHealPRatPCapR",L),N);
					end
				elseif SN > "LOREMASTERCDCALCTYPECOMPHYMIT" then
					if SN < "MARINERCDBASENCMR" then
						if SN < "MAINT" then
							if SN < "LOREMASTERCDVITALITYTONCMR" then
								if SN < "LOREMASTERCDMIGHTTOFINESSE" then
									if SN < "LOREMASTERCDFATETONCPR" then
										if SN > "LOREMASTERCDCALCTYPENONPHYMIT" then
											if SN == "LOREMASTERCDCALCTYPETACMIT" then
												return 25;
											else
												return 0;
											end
										elseif SN == "LOREMASTERCDCALCTYPENONPHYMIT" then
											return 12;
										else
											return 0;
										end
									elseif SN > "LOREMASTERCDFATETONCPR" then
										if SN < "LOREMASTERCDHASPOWER" then
											if SN == "LOREMASTERCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDHASPOWER" then
											if SN == "LOREMASTERCDMIGHTTOCRITHIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 0.07;
									end
								elseif SN > "LOREMASTERCDMIGHTTOFINESSE" then
									if SN < "LOREMASTERCDPHYMITTONONPHYMIT" then
										if SN < "LOREMASTERCDMIGHTTOTACMAS" then
											if SN == "LOREMASTERCDMIGHTTOPARRY" then
												return 1;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDMIGHTTOTACMAS" then
											if SN == "LOREMASTERCDPHYMITTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "LOREMASTERCDPHYMITTONONPHYMIT" then
										if SN < "LOREMASTERCDVITALITYTOICMR" then
											if SN == "LOREMASTERCDTACMASTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDVITALITYTOICMR" then
											if SN == "LOREMASTERCDVITALITYTOMORALE" then
												return 4.5;
											else
												return 0;
											end
										else
											return 0.012;
										end
									else
										return 1;
									end
								else
									return 1.5;
								end
							elseif SN > "LOREMASTERCDVITALITYTONCMR" then
								if SN < "LVLBONUSPHYDMG" then
									if SN < "LOREMASTERCDWILLTORESIST" then
										if SN < "LOREMASTERCDWILLTOEVADE" then
											if SN == "LOREMASTERCDWILLTOCRITHIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDWILLTOEVADE" then
											if SN == "LOREMASTERCDWILLTOPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "LOREMASTERCDWILLTORESIST" then
										if SN < "LOREMASTERCDWILLTOTACMIT" then
											if SN == "LOREMASTERCDWILLTOTACMAS" then
												return 3;
											else
												return 0;
											end
										elseif SN > "LOREMASTERCDWILLTOTACMIT" then
											if SN == "LVLBONUSMORRES" then
												return 0.1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "LVLBONUSPHYDMG" then
									if SN < "LVLEXPCOSTTOT" then
										if SN < "LVLBONUSTACDMG" then
											if SN == "LVLBONUSPOWRES" then
												return CalcStat("SkillPowerCost",L,N);
											else
												return 0;
											end
										elseif SN > "LVLBONUSTACDMG" then
											if SN == "LVLEXPCOST" then
												if Lm <= 1 then
													return 0;
												elseif Lm <= 5 then
													return RoundDbl(12.5*L*L+12.5666666666667*L+24.8666666666667);
												elseif Lm <= 10 then
													return RoundDbl(33.8*L*L-179.48*L+452.6);
												elseif Lm <= 15 then
													return RoundDbl(55.05*L*L-583.77*L+2370.5);
												elseif Lm <= 20 then
													return RoundDbl(76.2*L*L-1196.96*L+6809);
												elseif Lm <= 25 then
													return RoundDbl(97.4*L*L-2023*L+14849.8);
												elseif Lm <= 30 then
													return RoundDbl(118.7*L*L-3066.02 *L+27612.8);
												elseif Lm <= 35 then
													return RoundDbl(139.95*L*L-4319.23*L+46084.1);
												elseif Lm <= 40 then
													return RoundDbl(161.2*L*L-5785.04*L+71356.2);
												elseif Lm <= 45 then
													return RoundDbl(182.5*L*L-7467.38*L+104569.8);
												elseif Lm <= 50 then
													return RoundDbl(203.8*L*L-9363.48*L+146761.8);
												elseif Lm <= 55 then
													return RoundDbl(225.05*L*L-11467.77*L+198851.3);
												elseif Lm <= 60 then
													return RoundDbl(246.3*L*L-13784.46*L+261988);
												elseif Lm <= 70 then
													return RoundDbl(ExpFmod(CalcStat("LvlExpCost",60),61,5.071,L,nil,3.485));
												elseif Lm <= 75 then
													return RoundDbl(ExpFmod(CalcStat("LvlExpCost",70),71,5.072,L,nil,-0.95));
												else
													return ExpFmod(CalcStat("LvlExpCost",75),76,5,L,0,-0.5);
												end
											else
												return 0;
											end
										else
											return 0.1;
										end
									elseif SN > "LVLEXPCOSTTOT" then
										if SN < "MAIN" then
											if SN == "LVLTOILVL" then
												if Lm <= 106 then
													return LinFmod(1,225,300,105,106,L);
												elseif Lm <= 115 then
													return LinFmod(1,300,349,106,115,L);
												elseif Lm <= 116 then
													return LinFmod(1,349,350,115,116,L);
												elseif Lm <= 120 then
													return LinFmod(1,350,399,116,120,L);
												elseif Lm <= 121 then
													return LinFmod(1,399,400,120,121,L);
												elseif Lm <= 130 then
													return LinFmod(1,400,449,121,130,L);
												elseif Lm <= 131 then
													return LinFmod(1,449,450,130,131,L);
												elseif Lm <= 140 then
													return LinFmod(1,450,499,131,140,L);
												elseif Lm <= 141 then
													return LinFmod(1,499,500,140,141,L);
												else
													return LinFmod(1,500,549,141,150,L);
												end
											else
												return 0;
											end
										elseif SN > "MAIN" then
											if SN == "MAINC" then
												return RoundDblDown(StatLinInter("PntMPMainC","CreepPntS","ProgBMainC","",L,N,0));
											else
												return 0;
											end
										else
											return RoundDblDown(StatLinInter("PntMPMain","ItemPntS","ProgBMain","AdjUmbarItem",L,N,0));
										end
									else
										if Lm <= 1 then
											return 0;
										else
											return CalcStat("LvlExpCostTot",L-1)+CalcStat("LvlExpCost",L);
										end
									end
								else
									return 0.1;
								end
							else
								return 0.12;
							end
						elseif SN > "MAINT" then
							if SN < "MARINERCDAGILITYTOCRITHIT" then
								if SN < "MANRDPSVTWOEVADE" then
									if SN < "MANGIFTOFMENFATE" then
										if SN < "MANEASILYINSPINHEALP" then
											if SN == "MANDIMMANKINDWILL" then
												return -CalcStat("WillT",L,0.4);
											else
												return 0;
											end
										elseif SN > "MANEASILYINSPINHEALP" then
											if SN == "MANFOURTHAGEWILL" then
												return CalcStat("WillT",L,1.0);
											else
												return 0;
											end
										else
											return 5;
										end
									elseif SN > "MANGIFTOFMENFATE" then
										if SN < "MANRDPSVONEWILL" then
											if SN == "MANRDPSVONENAME" then
												return "Man of the Fourth Age";
											else
												return 0;
											end
										elseif SN > "MANRDPSVONEWILL" then
											if SN == "MANRDPSVTWOBLOCK" then
												return CalcStat("BalanceOfManBlock",L);
											else
												return 0;
											end
										else
											return CalcStat("ManFourthAgeWill",L);
										end
									else
										return CalcStat("FateT",L,1.0);
									end
								elseif SN > "MANRDPSVTWOEVADE" then
									if SN < "MANRDTRAITINHEALP" then
										if SN < "MANRDPSVTWOPARRY" then
											if SN == "MANRDPSVTWONAME" then
												return "Balance of Man";
											else
												return 0;
											end
										elseif SN > "MANRDPSVTWOPARRY" then
											if SN == "MANRDTRAITFATE" then
												return CalcStat("ManGiftOfMenFate",L);
											else
												return 0;
											end
										else
											return CalcStat("BalanceOfManParry",L);
										end
									elseif SN > "MANRDTRAITINHEALP" then
										if SN < "MANRDTRAITWILL" then
											if SN == "MANRDTRAITMIGHT" then
												return CalcStat("ManStrongMenMight",L);
											else
												return 0;
											end
										elseif SN > "MANRDTRAITWILL" then
											if SN == "MANSTRONGMENMIGHT" then
												return CalcStat("MightT",L,1.0);
											else
												return 0;
											end
										else
											return CalcStat("ManDimMankindWill",L);
										end
									else
										return CalcStat("ManEasilyInspInHealP",L);
									end
								else
									return CalcStat("BalanceOfManEvade",L);
								end
							elseif SN > "MARINERCDAGILITYTOCRITHIT" then
								if SN < "MARINERCDARMOURTOTACMIT" then
									if SN < "MARINERCDAGILITYTOPHYMIT" then
										if SN < "MARINERCDAGILITYTOPARRY" then
											if SN == "MARINERCDAGILITYTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN > "MARINERCDAGILITYTOPARRY" then
											if SN == "MARINERCDAGILITYTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 3;
										end
									elseif SN > "MARINERCDAGILITYTOPHYMIT" then
										if SN < "MARINERCDARMOURTOCOMPHYMIT" then
											if SN == "MARINERCDAGILITYTOTACMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MARINERCDARMOURTOCOMPHYMIT" then
											if SN == "MARINERCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "MARINERCDARMOURTOTACMIT" then
									if SN < "MARINERCDBASEICMR" then
										if SN < "MARINERCDBASEAGILITY" then
											if SN == "MARINERCDARMOURTYPE" then
												return 2;
											else
												return 0;
											end
										elseif SN > "MARINERCDBASEAGILITY" then
											if SN == "MARINERCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseAgilityM",L);
										end
									elseif SN > "MARINERCDBASEICMR" then
										if SN < "MARINERCDBASEMIGHT" then
											if SN == "MARINERCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										elseif SN > "MARINERCDBASEMIGHT" then
											if SN == "MARINERCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMightM",L);
										end
									else
										return CalcStat("ClassBaseICMRL",L);
									end
								else
									return 0.2;
								end
							else
								return 1;
							end
						else
							return RoundDblDown(StatLinInter("PntMPMain","TraitPntS","ProgBMain","AdjUmbarTrait",L,N,0));
						end
					elseif SN > "MARINERCDBASENCMR" then
						if SN < "MASTERYT" then
							if SN < "MARINERCDPHYMITTOCOMPHYMIT" then
								if SN < "MARINERCDFATETONCPR" then
									if SN < "MARINERCDBASEWILL" then
										if SN < "MARINERCDBASEPOWER" then
											if SN == "MARINERCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										elseif SN > "MARINERCDBASEPOWER" then
											if SN == "MARINERCDBASEVITALITY" then
												return CalcStat("ClassBaseVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBasePower",L);
										end
									elseif SN > "MARINERCDBASEWILL" then
										if SN < "MARINERCDCALCTYPENONPHYMIT" then
											if SN == "MARINERCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										elseif SN > "MARINERCDCALCTYPENONPHYMIT" then
											if SN == "MARINERCDCALCTYPETACMIT" then
												return 26;
											else
												return 0;
											end
										else
											return 13;
										end
									else
										return CalcStat("ClassBaseWillM",L);
									end
								elseif SN > "MARINERCDFATETONCPR" then
									if SN < "MARINERCDMIGHTTOFINESSE" then
										if SN < "MARINERCDHASPOWER" then
											if SN == "MARINERCDFATETOPOWER" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MARINERCDHASPOWER" then
											if SN == "MARINERCDMIGHTTOCRITHIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "MARINERCDMIGHTTOFINESSE" then
										if SN < "MARINERCDMIGHTTOPARRY" then
											if SN == "MARINERCDMIGHTTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										elseif SN > "MARINERCDMIGHTTOPARRY" then
											if SN == "MARINERCDMIGHTTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1.5;
									end
								else
									return 0.07;
								end
							elseif SN > "MARINERCDPHYMITTOCOMPHYMIT" then
								if SN < "MARINERCDWILLTOOUTHEAL" then
									if SN < "MARINERCDVITALITYTOMORALE" then
										if SN < "MARINERCDTACMASTOOUTHEAL" then
											if SN == "MARINERCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MARINERCDTACMASTOOUTHEAL" then
											if SN == "MARINERCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "MARINERCDVITALITYTOMORALE" then
										if SN < "MARINERCDWILLTOCRITHIT" then
											if SN == "MARINERCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										elseif SN > "MARINERCDWILLTOCRITHIT" then
											if SN == "MARINERCDWILLTOFINESSE" then
												return 1.5;
											else
												return 0;
											end
										else
											return 0.5;
										end
									else
										return 4.5;
									end
								elseif SN > "MARINERCDWILLTOOUTHEAL" then
									if SN < "MASTERY" then
										if SN < "MARINERCDWILLTOPHYMIT" then
											if SN == "MARINERCDWILLTOPHYMAS" then
												return 2;
											else
												return 0;
											end
										elseif SN > "MARINERCDWILLTOPHYMIT" then
											if SN == "MARINERCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "MASTERY" then
										if SN < "MASTERYC" then
											if SN == "MASTERYADJ" then
												if Lm <= 499 then
													return 1;
												elseif Lm <= 500 then
													return 0.9;
												else
													return 247/300;
												end
											else
												return 0;
											end
										elseif SN > "MASTERYC" then
											if SN == "MASTERYOLD" then
												return CalcStat("Mastery",L,N);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPMasteryC","CreepPntS","ProgBMasteryC","",L,N,0);
										end
									else
										return StatLinInter("PntMPMastery","ItemPntS","ProgBMastery","MasteryAdj",L,N,0);
									end
								else
									return 2;
								end
							else
								return 1;
							end
						elseif SN > "MASTERYT" then
							if SN < "MINSTRELCDAGILITYTOTACMAS" then
								if SN < "MINCOURAGERESIST" then
									if SN < "MIGHTC" then
										if SN < "MATHOMLVLTOILVL" then
											if SN == "MASTERYTADJ" then
												if Lm <= 140 then
													return 1;
												elseif Lm <= 141 then
													return 0.9;
												else
													return 247/300;
												end
											else
												return 0;
											end
										elseif SN > "MATHOMLVLTOILVL" then
											if SN == "MIGHT" then
												return CalcStat("Main",L,N);
											else
												return 0;
											end
										else
											return CalcStat("AwardLvlToILvl",L);
										end
									elseif SN > "MIGHTC" then
										if SN < "MINCOMPOSURERESIST" then
											if SN == "MIGHTT" then
												return CalcStat("MainT",L,N);
											else
												return 0;
											end
										elseif SN > "MINCOMPOSURERESIST" then
											if SN == "MINCOMPOSURETACMIT" then
												return CalcStat("TacMitT",L,1.0);
											else
												return 0;
											end
										else
											return CalcStat("ResistT",L,1.6);
										end
									else
										return CalcStat("MainC",L,N);
									end
								elseif SN > "MINCOURAGERESIST" then
									if SN < "MINPIERCINGBALFINESSE" then
										if SN < "MINECHOESBATTLERESIST" then
											if SN == "MINECHOESBATTLECRITDEF" then
												return -CalcStat("CritDefT",L,2.0);
											else
												return 0;
											end
										elseif SN > "MINECHOESBATTLERESIST" then
											if SN == "MINENDMORALE" then
												return CalcStat("MoraleT",L,CalcStat("Trait12345Choice",N)*0.8);
											else
												return 0;
											end
										else
											return -CalcStat("SongResistT",L,1.0);
										end
									elseif SN > "MINPIERCINGBALFINESSE" then
										if SN < "MINSTRELCDAGILITYTOEVADE" then
											if SN == "MINSTRELCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDAGILITYTOEVADE" then
											if SN == "MINSTRELCDAGILITYTOFINESSE" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return CalcStat("FinesseT",L,CalcStat("Trait12345Choice",N)*0.4);
									end
								else
									return CalcStat("FearResistT",L,1.0);
								end
							elseif SN > "MINSTRELCDAGILITYTOTACMAS" then
								if SN < "MINSTRELCDBASEICPR" then
									if SN < "MINSTRELCDARMOURTYPE" then
										if SN < "MINSTRELCDARMOURTONONPHYMIT" then
											if SN == "MINSTRELCDARMOURTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDARMOURTONONPHYMIT" then
											if SN == "MINSTRELCDARMOURTOTACMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 0.2;
										end
									elseif SN > "MINSTRELCDARMOURTYPE" then
										if SN < "MINSTRELCDBASEFATE" then
											if SN == "MINSTRELCDBASEAGILITY" then
												return CalcStat("ClassBaseAgilityM",L);
											else
												return 0;
											end
										elseif SN > "MINSTRELCDBASEFATE" then
											if SN == "MINSTRELCDBASEICMR" then
												return CalcStat("ClassBaseICMRL",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseFate",L);
										end
									else
										return 1;
									end
								elseif SN > "MINSTRELCDBASEICPR" then
									if SN < "MINSTRELCDBASENCPR" then
										if SN < "MINSTRELCDBASEMORALE" then
											if SN == "MINSTRELCDBASEMIGHT" then
												return CalcStat("ClassBaseMightL",L);
											else
												return 0;
											end
										elseif SN > "MINSTRELCDBASEMORALE" then
											if SN == "MINSTRELCDBASENCMR" then
												return CalcStat("ClassBaseNCMRL",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMorale",L);
										end
									elseif SN > "MINSTRELCDBASENCPR" then
										if SN < "MINSTRELCDBASEVITALITY" then
											if SN == "MINSTRELCDBASEPOWER" then
												return CalcStat("ClassBasePower",L);
											else
												return 0;
											end
										elseif SN > "MINSTRELCDBASEVITALITY" then
											if SN == "MINSTRELCDBASEWILL" then
												return CalcStat("ClassBaseWillH",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseVitality",L);
										end
									else
										return CalcStat("ClassBaseNCPR",L);
									end
								else
									return CalcStat("ClassBaseICPR",L);
								end
							else
								return 2;
							end
						else
							return StatLinInter("PntMPMastery","TraitPntS","ProgBMastery","MasteryTAdj",L,N,0);
						end
					else
						return CalcStat("ClassBaseNCMRL",L);
					end
				else
					return 12;
				end
			else
				return 1;
			end
		else
			if Lm <= 0 then
				return 0;
			elseif Lm <= 2 then
				return 2*L;
			elseif Lm <= 9 then
				return 2*L-1;
			elseif Lm <= 15 then
				return 3*L;
			elseif Lm <= 25 then
				return 6*L;
			elseif Lm <= 29 then
				return 9*L;
			elseif Lm <= 36 then
				return 300;
			else
				return 0;
			end
		end
	elseif SN > "MINSTRELCDCALCTYPECOMPHYMIT" then
		if SN < "TACMITLPRATPB" then
			if SN < "PNTMPFINESSE" then
				if SN < "PARTBPEPRATPCAP" then
					if SN < "MORALET" then
						if SN < "MINTOTFINESSESEL" then
							if SN < "MINSTRELCDVITALITYTOMORALE" then
								if SN < "MINSTRELCDMIGHTTOCRITHIT" then
									if SN < "MINSTRELCDCANBLOCK" then
										if SN > "MINSTRELCDCALCTYPENONPHYMIT" then
											if SN == "MINSTRELCDCALCTYPETACMIT" then
												return 25;
											else
												return 0;
											end
										elseif SN == "MINSTRELCDCALCTYPENONPHYMIT" then
											return 12;
										else
											return 0;
										end
									elseif SN > "MINSTRELCDCANBLOCK" then
										if SN < "MINSTRELCDFATETOPOWER" then
											if SN == "MINSTRELCDFATETONCPR" then
												return 0.07;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDFATETOPOWER" then
											if SN == "MINSTRELCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										if Lm <= 19 then
											return 0;
										else
											return 1;
										end
									end
								elseif SN > "MINSTRELCDMIGHTTOCRITHIT" then
									if SN < "MINSTRELCDPHYMITTOCOMPHYMIT" then
										if SN < "MINSTRELCDMIGHTTOTACMAS" then
											if SN == "MINSTRELCDMIGHTTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDMIGHTTOTACMAS" then
											if SN == "MINSTRELCDMIGHTTOTACMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "MINSTRELCDPHYMITTOCOMPHYMIT" then
										if SN < "MINSTRELCDTACMASTOOUTHEAL" then
											if SN == "MINSTRELCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDTACMASTOOUTHEAL" then
											if SN == "MINSTRELCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								else
									return 1;
								end
							elseif SN > "MINSTRELCDVITALITYTOMORALE" then
								if SN < "MINSTRELCDWILLTOTACMIT" then
									if SN < "MINSTRELCDWILLTOEVADE" then
										if SN < "MINSTRELCDWILLTOBLOCK" then
											if SN == "MINSTRELCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDWILLTOBLOCK" then
											if SN == "MINSTRELCDWILLTOCRITHIT" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "MINSTRELCDWILLTOEVADE" then
										if SN < "MINSTRELCDWILLTORESIST" then
											if SN == "MINSTRELCDWILLTOPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "MINSTRELCDWILLTORESIST" then
											if SN == "MINSTRELCDWILLTOTACMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "MINSTRELCDWILLTOTACMIT" then
									if SN < "MINTOTCRITHITSEL" then
										if SN < "MINTIMEECHOESBATTLERESIST" then
											if SN == "MINTACMAS" then
												return CalcStat("TacMasT",L,CalcStat("Trait12345Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "MINTIMEECHOESBATTLERESIST" then
											if SN == "MINTOTCRITHIT" then
												return CalcStat("CritHitT",L,CalcStat("MinToTCritHitSel",N));
											else
												return 0;
											end
										else
											return -CalcStat("SongResistT",L,0.6);
										end
									elseif SN > "MINTOTCRITHITSEL" then
										if SN < "MINTOTFATESEL" then
											if SN == "MINTOTFATE" then
												return CalcStat("FateT",L,CalcStat("MinToTFateSel",N));
											else
												return 0;
											end
										elseif SN > "MINTOTFATESEL" then
											if SN == "MINTOTFINESSE" then
												return CalcStat("FinesseT",L,CalcStat("MinToTFinesseSel",N));
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({0.2,0.3,0.4,0.5,0.6,0},L);
											end
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return DataTableValue({0,0,0,0.4,0.6,0},L);
										end
									end
								else
									return 1;
								end
							else
								return 4.5;
							end
						elseif SN > "MINTOTFINESSESEL" then
							if SN < "MITLIGHTPRATP" then
								if SN < "MITHEAVYPRATPA" then
									if SN < "MINTOTVITALITYSEL" then
										if SN < "MINTOTRESISTSEL" then
											if SN == "MINTOTRESIST" then
												return CalcStat("ResistT",L,CalcStat("MinToTResistSel",N));
											else
												return 0;
											end
										elseif SN > "MINTOTRESISTSEL" then
											if SN == "MINTOTVITALITY" then
												return CalcStat("VitalityT",L,CalcStat("MinToTVitalitySel",N));
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({0,0.2,0.3,0.4,0.5,0},L);
											end
										end
									elseif SN > "MINTOTVITALITYSEL" then
										if SN < "MITHEAVYPPRAT" then
											if SN == "MITHEAVYPBONUS" then
												return 0;
											else
												return 0;
											end
										elseif SN > "MITHEAVYPPRAT" then
											if SN == "MITHEAVYPRATP" then
												return CalcPercAB(CalcStat("MitHeavyPRatPA",L),CalcStat("MitHeavyPRatPB",L),CalcStat("MitHeavyPRatPCap",L),N);
											else
												return 0;
											end
										else
											return CalcRatAB(CalcStat("MitHeavyPRatPA",L),CalcStat("MitHeavyPRatPB",L),CalcStat("MitHeavyPRatPCapR",L),N);
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return DataTableValue({0,0,0,0,0.4,0},L);
										end
									end
								elseif SN > "MITHEAVYPRATPA" then
									if SN < "MITHEAVYPRATPCAPR" then
										if SN < "MITHEAVYPRATPC" then
											if SN == "MITHEAVYPRATPB" then
												return CalcStat("BRatRounded",L,"BRatMitHeavy");
											else
												return 0;
											end
										elseif SN > "MITHEAVYPRATPC" then
											if SN == "MITHEAVYPRATPCAP" then
												return 60;
											else
												return 0;
											end
										else
											return 0.5;
										end
									elseif SN > "MITHEAVYPRATPCAPR" then
										if SN < "MITLIGHTPBONUS" then
											if SN == "MITIGATION" then
												return StatLinInter("PntMPMitigation","ItemPntS","ProgBMitigation","AdjUmbarItemMit",L,N,0);
											else
												return 0;
											end
										elseif SN > "MITLIGHTPBONUS" then
											if SN == "MITLIGHTPPRAT" then
												return CalcRatAB(CalcStat("MitLightPRatPA",L),CalcStat("MitLightPRatPB",L),CalcStat("MitLightPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									else
										return CalcStat("MitHeavyPRatPB",L)*CalcStat("MitHeavyPRatPC",L);
									end
								else
									return 180;
								end
							elseif SN > "MITLIGHTPRATP" then
								if SN < "MITMEDIUMPRATP" then
									if SN < "MITLIGHTPRATPCAP" then
										if SN < "MITLIGHTPRATPB" then
											if SN == "MITLIGHTPRATPA" then
												return 120;
											else
												return 0;
											end
										elseif SN > "MITLIGHTPRATPB" then
											if SN == "MITLIGHTPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatMitLight");
										end
									elseif SN > "MITLIGHTPRATPCAP" then
										if SN < "MITMEDIUMPBONUS" then
											if SN == "MITLIGHTPRATPCAPR" then
												return CalcStat("MitLightPRatPB",L)*CalcStat("MitLightPRatPC",L);
											else
												return 0;
											end
										elseif SN > "MITMEDIUMPBONUS" then
											if SN == "MITMEDIUMPPRAT" then
												return CalcRatAB(CalcStat("MitMediumPRatPA",L),CalcStat("MitMediumPRatPB",L),CalcStat("MitMediumPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									else
										return 40;
									end
								elseif SN > "MITMEDIUMPRATP" then
									if SN < "MITMEDIUMPRATPCAP" then
										if SN < "MITMEDIUMPRATPB" then
											if SN == "MITMEDIUMPRATPA" then
												return 150;
											else
												return 0;
											end
										elseif SN > "MITMEDIUMPRATPB" then
											if SN == "MITMEDIUMPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatMitMedium");
										end
									elseif SN > "MITMEDIUMPRATPCAP" then
										if SN < "MORALE" then
											if SN == "MITMEDIUMPRATPCAPR" then
												return CalcStat("MitMediumPRatPB",L)*CalcStat("MitMediumPRatPC",L);
											else
												return 0;
											end
										elseif SN > "MORALE" then
											if SN == "MORALEADJ" then
												if Lm <= 25 then
													return 0.5;
												elseif Lm <= 50 then
													return 0.6;
												elseif Lm <= 60 then
													return 0.7;
												elseif Lm <= 79 then
													return 0.8;
												elseif Lm <= 80 then
													return 0.9;
												else
													return 1;
												end
											else
												return 0;
											end
										else
											return StatLinInter("PntMPMorale","ItemPntSVital","ProgBMorale","MoraleAdj",L,N,0);
										end
									else
										return 50;
									end
								else
									return CalcPercAB(CalcStat("MitMediumPRatPA",L),CalcStat("MitMediumPRatPB",L),CalcStat("MitMediumPRatPCap",L),N);
								end
							else
								return CalcPercAB(CalcStat("MitLightPRatPA",L),CalcStat("MitLightPRatPB",L),CalcStat("MitLightPRatPCap",L),N);
							end
						else
							if Lm <= 0 then
								return 0;
							else
								return DataTableValue({0,0,0.2,0.4,0.6,0},L);
							end
						end
					elseif SN > "MORALET" then
						if SN < "PARRYC" then
							if SN < "OUTDMGPRATPA" then
								if SN < "NCPR" then
									if SN < "NCMR" then
										if SN > "MORALETADJ" then
											if SN == "N" then
												return N;
											else
												return 0;
											end
										elseif SN == "MORALETADJ" then
											if Lm <= 25 then
												return 0.5;
											elseif Lm <= 50 then
												return 0.6;
											elseif Lm <= 60 then
												return 0.7;
											elseif Lm <= 65 then
												return 0.8;
											elseif Lm <= 75 then
												return 0.9;
											else
												return 1;
											end
										else
											return 0;
										end
									elseif SN > "NCMR" then
										if SN < "NCMRCRAW" then
											if SN == "NCMRC" then
												return StatLinInter("PntMPNCMRC","CreepPntS","ProgBNCMRC","",L,N,0);
											else
												return 0;
											end
										elseif SN > "NCMRCRAW" then
											if SN == "NCMRT" then
												return StatLinInter("PntMPNCMR","TraitPntSVital","ProgBNCMR","",L,N,1);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPNCMRCOld","CreepPntS","ProgBNCMRC","",L,N,99);
										end
									else
										return StatLinInter("PntMPNCMR","ItemPntSVital","ProgBNCMR","",L,N,1);
									end
								elseif SN > "NCPR" then
									if SN < "OFFSET" then
										if SN < "NCPRCRAW" then
											if SN == "NCPRC" then
												return StatLinInter("PntMPNCPRC","CreepPntS","ProgBNCPRC","",L,N,0);
											else
												return 0;
											end
										elseif SN > "NCPRCRAW" then
											if SN == "NCPRT" then
												return StatLinInter("PntMPNCPR","TraitPntSVital","ProgBNCPR","",L,N,99);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPNCPRCOld","CreepPntS","ProgBNCPRC","",L,N,99);
										end
									elseif SN > "OFFSET" then
										if SN < "OUTDMGPPRAT" then
											if SN == "OUTDMGPBONUS" then
												return 0;
											else
												return 0;
											end
										elseif SN > "OUTDMGPPRAT" then
											if SN == "OUTDMGPRATP" then
												return CalcPercAB(CalcStat("OutDmgPRatPA",L),CalcStat("OutDmgPRatPB",L),CalcStat("OutDmgPRatPCap",L),N);
											else
												return 0;
											end
										else
											return CalcRatAB(CalcStat("OutDmgPRatPA",L),CalcStat("OutDmgPRatPB",L),CalcStat("OutDmgPRatPCapR",L),N);
										end
									else
										return L+N;
									end
								else
									return StatLinInter("PntMPNCPR","ItemPntSClassic","ProgBNCPR","",L,N,99);
								end
							elseif SN > "OUTDMGPRATPA" then
								if SN < "OUTHEALPRATP" then
									if SN < "OUTDMGPRATPCAPR" then
										if SN < "OUTDMGPRATPC" then
											if SN == "OUTDMGPRATPB" then
												return CalcStat("BRatRounded",L,"BRatExtra");
											else
												return 0;
											end
										elseif SN > "OUTDMGPRATPC" then
											if SN == "OUTDMGPRATPCAP" then
												return 200;
											else
												return 0;
											end
										else
											return 0.5;
										end
									elseif SN > "OUTDMGPRATPCAPR" then
										if SN < "OUTHEALPBONUS" then
											if SN == "OUTHEAL" then
												return StatLinInter("PntMPOutHeal","ItemPntS","ProgBOutHeal","AdjUmbarItem",L,N,0);
											else
												return 0;
											end
										elseif SN > "OUTHEALPBONUS" then
											if SN == "OUTHEALPPRAT" then
												return CalcRatAB(CalcStat("OutHealPRatPA",L),CalcStat("OutHealPRatPB",L),CalcStat("OutHealPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									else
										return CalcStat("OutDmgPRatPB",L)*CalcStat("OutDmgPRatPC",L);
									end
								elseif SN > "OUTHEALPRATP" then
									if SN < "OUTHEALPRATPCAP" then
										if SN < "OUTHEALPRATPB" then
											if SN == "OUTHEALPRATPA" then
												return 210;
											else
												return 0;
											end
										elseif SN > "OUTHEALPRATPB" then
											if SN == "OUTHEALPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatOutHeal");
										end
									elseif SN > "OUTHEALPRATPCAP" then
										if SN < "OUTHEALT" then
											if SN == "OUTHEALPRATPCAPR" then
												return CalcStat("OutHealPRatPB",L)*CalcStat("OutHealPRatPC",L);
											else
												return 0;
											end
										elseif SN > "OUTHEALT" then
											if SN == "PARRY" then
												return CalcStat("BPE",L,N);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPOutHeal","TraitPntS","ProgBOutHeal","AdjUmbarTrait",L,N,0);
										end
									else
										return 70;
									end
								else
									return CalcPercAB(CalcStat("OutHealPRatPA",L),CalcStat("OutHealPRatPB",L),CalcStat("OutHealPRatPCap",L),N);
								end
							else
								return 600;
							end
						elseif SN > "PARRYC" then
							if SN < "PARTBLOCKMITPRATPCAP" then
								if SN < "PARRYPRATPCAPR" then
									if SN < "PARRYPRATPA" then
										if SN < "PARRYPPRAT" then
											if SN == "PARRYPBONUS" then
												return CalcStat("BPEPBonus",L);
											else
												return 0;
											end
										elseif SN > "PARRYPPRAT" then
											if SN == "PARRYPRATP" then
												return CalcStat("BPEPRatP",L,N);
											else
												return 0;
											end
										else
											return CalcStat("BPEPPRat",L,N);
										end
									elseif SN > "PARRYPRATPA" then
										if SN < "PARRYPRATPC" then
											if SN == "PARRYPRATPB" then
												return CalcStat("BPEPRatPB",L);
											else
												return 0;
											end
										elseif SN > "PARRYPRATPC" then
											if SN == "PARRYPRATPCAP" then
												return CalcStat("BPEPRatPCap",L);
											else
												return 0;
											end
										else
											return CalcStat("BPEPRatPC",L);
										end
									else
										return CalcStat("BPEPRatPA",L);
									end
								elseif SN > "PARRYPRATPCAPR" then
									if SN < "PARTBLOCKMITPRATP" then
										if SN < "PARTBLOCKMITPBONUS" then
											if SN == "PARRYT" then
												return CalcStat("BPET",L,N);
											else
												return 0;
											end
										elseif SN > "PARTBLOCKMITPBONUS" then
											if SN == "PARTBLOCKMITPPRAT" then
												return CalcStat("PartMitPPRat",L,N);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPBonus",L);
										end
									elseif SN > "PARTBLOCKMITPRATP" then
										if SN < "PARTBLOCKMITPRATPB" then
											if SN == "PARTBLOCKMITPRATPA" then
												return CalcStat("PartMitPRatPA",L);
											else
												return 0;
											end
										elseif SN > "PARTBLOCKMITPRATPB" then
											if SN == "PARTBLOCKMITPRATPC" then
												return CalcStat("PartMitPRatPC",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPB",L);
										end
									else
										return CalcStat("PartMitPRatP",L,N);
									end
								else
									return CalcStat("BPEPRatPCapR",L);
								end
							elseif SN > "PARTBLOCKMITPRATPCAP" then
								if SN < "PARTBLOCKPRATPCAP" then
									if SN < "PARTBLOCKPRATP" then
										if SN < "PARTBLOCKPBONUS" then
											if SN == "PARTBLOCKMITPRATPCAPR" then
												return CalcStat("PartMitPRatPCapR",L);
											else
												return 0;
											end
										elseif SN > "PARTBLOCKPBONUS" then
											if SN == "PARTBLOCKPPRAT" then
												return CalcStat("PartBPEPPRat",L,N);
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPBonus",L);
										end
									elseif SN > "PARTBLOCKPRATP" then
										if SN < "PARTBLOCKPRATPB" then
											if SN == "PARTBLOCKPRATPA" then
												return CalcStat("PartBPEPRatPA",L);
											else
												return 0;
											end
										elseif SN > "PARTBLOCKPRATPB" then
											if SN == "PARTBLOCKPRATPC" then
												return CalcStat("PartBPEPRatPC",L);
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPRatPB",L);
										end
									else
										return CalcStat("PartBPEPRatP",L,N);
									end
								elseif SN > "PARTBLOCKPRATPCAP" then
									if SN < "PARTBPEPRATP" then
										if SN < "PARTBPEPBONUS" then
											if SN == "PARTBLOCKPRATPCAPR" then
												return CalcStat("PartBPEPRatPCapR",L);
											else
												return 0;
											end
										elseif SN > "PARTBPEPBONUS" then
											if SN == "PARTBPEPPRAT" then
												return CalcRatAB(CalcStat("PartBPEPRatPA",L),CalcStat("PartBPEPRatPB",L),CalcStat("PartBPEPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									elseif SN > "PARTBPEPRATP" then
										if SN < "PARTBPEPRATPB" then
											if SN == "PARTBPEPRATPA" then
												return 75;
											else
												return 0;
											end
										elseif SN > "PARTBPEPRATPB" then
											if SN == "PARTBPEPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatPartBPE");
										end
									else
										return CalcPercAB(CalcStat("PartBPEPRatPA",L),CalcStat("PartBPEPRatPB",L),CalcStat("PartBPEPRatPCap",L),N);
									end
								else
									return CalcStat("PartBPEPRatPCap",L);
								end
							else
								return CalcStat("PartMitPRatPCap",L);
							end
						else
							return CalcStat("BPEC",L,N);
						end
					else
						return StatLinInter("PntMPMorale","TraitPntSVital","ProgBMorale","MoraleTAdj",L,N,0);
					end
				elseif SN > "PARTBPEPRATPCAP" then
					if SN < "PERKTACMIT" then
						if SN < "PARTFINESSEPRATPC" then
							if SN < "PARTEVADEPRATPC" then
								if SN < "PARTEVADEMITPRATPC" then
									if SN < "PARTEVADEMITPPRAT" then
										if SN > "PARTBPEPRATPCAPR" then
											if SN == "PARTEVADEMITPBONUS" then
												return CalcStat("PartMitPBonus",L);
											else
												return 0;
											end
										elseif SN == "PARTBPEPRATPCAPR" then
											return CalcStat("PartBPEPRatPB",L)*CalcStat("PartBPEPRatPC",L);
										else
											return 0;
										end
									elseif SN > "PARTEVADEMITPPRAT" then
										if SN < "PARTEVADEMITPRATPA" then
											if SN == "PARTEVADEMITPRATP" then
												return CalcStat("PartMitPRatP",L,N);
											else
												return 0;
											end
										elseif SN > "PARTEVADEMITPRATPA" then
											if SN == "PARTEVADEMITPRATPB" then
												return CalcStat("PartMitPRatPB",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPA",L);
										end
									else
										return CalcStat("PartMitPPRat",L,N);
									end
								elseif SN > "PARTEVADEMITPRATPC" then
									if SN < "PARTEVADEPPRAT" then
										if SN < "PARTEVADEMITPRATPCAPR" then
											if SN == "PARTEVADEMITPRATPCAP" then
												return CalcStat("PartMitPRatPCap",L);
											else
												return 0;
											end
										elseif SN > "PARTEVADEMITPRATPCAPR" then
											if SN == "PARTEVADEPBONUS" then
												return CalcStat("PartBPEPBonus",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPCapR",L);
										end
									elseif SN > "PARTEVADEPPRAT" then
										if SN < "PARTEVADEPRATPA" then
											if SN == "PARTEVADEPRATP" then
												return CalcStat("PartBPEPRatP",L,N);
											else
												return 0;
											end
										elseif SN > "PARTEVADEPRATPA" then
											if SN == "PARTEVADEPRATPB" then
												return CalcStat("PartBPEPRatPB",L);
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPRatPA",L);
										end
									else
										return CalcStat("PartBPEPPRat",L,N);
									end
								else
									return CalcStat("PartMitPRatPC",L);
								end
							elseif SN > "PARTEVADEPRATPC" then
								if SN < "PARTFINESSEDMGPRATPC" then
									if SN < "PARTFINESSEDMGPPRAT" then
										if SN < "PARTEVADEPRATPCAPR" then
											if SN == "PARTEVADEPRATPCAP" then
												return CalcStat("PartBPEPRatPCap",L);
											else
												return 0;
											end
										elseif SN > "PARTEVADEPRATPCAPR" then
											if SN == "PARTFINESSEDMGPBONUS" then
												return 0;
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPRatPCapR",L);
										end
									elseif SN > "PARTFINESSEDMGPPRAT" then
										if SN < "PARTFINESSEDMGPRATPA" then
											if SN == "PARTFINESSEDMGPRATP" then
												return CalcPercAB(CalcStat("PartFinesseDmgPRatPA",L),CalcStat("PartFinesseDmgPRatPB",L),CalcStat("PartFinesseDmgPRatPCap",L),N);
											else
												return 0;
											end
										elseif SN > "PARTFINESSEDMGPRATPA" then
											if SN == "PARTFINESSEDMGPRATPB" then
												return CalcStat("BRatRounded",L,"BRatStandard");
											else
												return 0;
											end
										else
											return 150;
										end
									else
										return CalcRatAB(CalcStat("PartFinesseDmgPRatPA",L),CalcStat("PartFinesseDmgPRatPB",L),CalcStat("PartFinesseDmgPRatPCapR",L),N);
									end
								elseif SN > "PARTFINESSEDMGPRATPC" then
									if SN < "PARTFINESSEPPRAT" then
										if SN < "PARTFINESSEDMGPRATPCAPR" then
											if SN == "PARTFINESSEDMGPRATPCAP" then
												return 50;
											else
												return 0;
											end
										elseif SN > "PARTFINESSEDMGPRATPCAPR" then
											if SN == "PARTFINESSEPBONUS" then
												return 0;
											else
												return 0;
											end
										else
											return CalcStat("PartFinesseDmgPRatPB",L)*CalcStat("PartFinesseDmgPRatPC",L);
										end
									elseif SN > "PARTFINESSEPPRAT" then
										if SN < "PARTFINESSEPRATPA" then
											if SN == "PARTFINESSEPRATP" then
												return CalcPercAB(CalcStat("PartFinessePRatPA",L),CalcStat("PartFinessePRatPB",L),CalcStat("PartFinessePRatPCap",L),N);
											else
												return 0;
											end
										elseif SN > "PARTFINESSEPRATPA" then
											if SN == "PARTFINESSEPRATPB" then
												return CalcStat("BRatRounded",L,"BRatStandard");
											else
												return 0;
											end
										else
											return 150;
										end
									else
										return CalcRatAB(CalcStat("PartFinessePRatPA",L),CalcStat("PartFinessePRatPB",L),CalcStat("PartFinessePRatPCapR",L),N);
									end
								else
									return 0.5;
								end
							else
								return CalcStat("PartBPEPRatPC",L);
							end
						elseif SN > "PARTFINESSEPRATPC" then
							if SN < "PARTPARRYMITPRATPC" then
								if SN < "PARTMITPRATPC" then
									if SN < "PARTMITPPRAT" then
										if SN < "PARTFINESSEPRATPCAPR" then
											if SN == "PARTFINESSEPRATPCAP" then
												return 50;
											else
												return 0;
											end
										elseif SN > "PARTFINESSEPRATPCAPR" then
											if SN == "PARTMITPBONUS" then
												return 0.1;
											else
												return 0;
											end
										else
											return CalcStat("PartFinessePRatPB",L)*CalcStat("PartFinessePRatPC",L);
										end
									elseif SN > "PARTMITPPRAT" then
										if SN < "PARTMITPRATPA" then
											if SN == "PARTMITPRATP" then
												return CalcPercAB(CalcStat("PartMitPRatPA",L),CalcStat("PartMitPRatPB",L),CalcStat("PartMitPRatPCap",L),N);
											else
												return 0;
											end
										elseif SN > "PARTMITPRATPA" then
											if SN == "PARTMITPRATPB" then
												return CalcStat("BRatRounded",L,"BRatPartBPE");
											else
												return 0;
											end
										else
											return 105;
										end
									else
										return CalcRatAB(CalcStat("PartMitPRatPA",L),CalcStat("PartMitPRatPB",L),CalcStat("PartMitPRatPCapR",L),N);
									end
								elseif SN > "PARTMITPRATPC" then
									if SN < "PARTPARRYMITPPRAT" then
										if SN < "PARTMITPRATPCAPR" then
											if SN == "PARTMITPRATPCAP" then
												return 35;
											else
												return 0;
											end
										elseif SN > "PARTMITPRATPCAPR" then
											if SN == "PARTPARRYMITPBONUS" then
												return CalcStat("PartMitPBonus",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPB",L)*CalcStat("PartMitPRatPC",L);
										end
									elseif SN > "PARTPARRYMITPPRAT" then
										if SN < "PARTPARRYMITPRATPA" then
											if SN == "PARTPARRYMITPRATP" then
												return CalcStat("PartMitPRatP",L,N);
											else
												return 0;
											end
										elseif SN > "PARTPARRYMITPRATPA" then
											if SN == "PARTPARRYMITPRATPB" then
												return CalcStat("PartMitPRatPB",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPA",L);
										end
									else
										return CalcStat("PartMitPPRat",L,N);
									end
								else
									return 0.5;
								end
							elseif SN > "PARTPARRYMITPRATPC" then
								if SN < "PARTPARRYPRATPC" then
									if SN < "PARTPARRYPPRAT" then
										if SN < "PARTPARRYMITPRATPCAPR" then
											if SN == "PARTPARRYMITPRATPCAP" then
												return CalcStat("PartMitPRatPCap",L);
											else
												return 0;
											end
										elseif SN > "PARTPARRYMITPRATPCAPR" then
											if SN == "PARTPARRYPBONUS" then
												return CalcStat("PartBPEPBonus",L);
											else
												return 0;
											end
										else
											return CalcStat("PartMitPRatPCapR",L);
										end
									elseif SN > "PARTPARRYPPRAT" then
										if SN < "PARTPARRYPRATPA" then
											if SN == "PARTPARRYPRATP" then
												return CalcStat("PartBPEPRatP",L,N);
											else
												return 0;
											end
										elseif SN > "PARTPARRYPRATPA" then
											if SN == "PARTPARRYPRATPB" then
												return CalcStat("PartBPEPRatPB",L);
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPRatPA",L);
										end
									else
										return CalcStat("PartBPEPPRat",L,N);
									end
								elseif SN > "PARTPARRYPRATPC" then
									if SN < "PERKNCMR" then
										if SN < "PARTPARRYPRATPCAPR" then
											if SN == "PARTPARRYPRATPCAP" then
												return CalcStat("PartBPEPRatPCap",L);
											else
												return 0;
											end
										elseif SN > "PARTPARRYPRATPCAPR" then
											if SN == "PERKMORALE" then
												return DataTableValue({10,20,30,40},L);
											else
												return 0;
											end
										else
											return CalcStat("PartBPEPRatPCapR",L);
										end
									elseif SN > "PERKNCMR" then
										if SN < "PERKPHYMIT" then
											if SN == "PERKNCPR" then
												return CalcStat("FoodNCPRL",L);
											else
												return 0;
											end
										elseif SN > "PERKPHYMIT" then
											if SN == "PERKPOWER" then
												return DataTableValue({10,20,30,40},L);
											else
												return 0;
											end
										else
											return CalcStat("PhyMitT",L,0.2*N);
										end
									else
										return CalcStat("FoodNCMRL",L);
									end
								else
									return CalcStat("PartBPEPRatPC",L);
								end
							else
								return CalcStat("PartMitPRatPC",L);
							end
						else
							return 0.5;
						end
					elseif SN > "PERKTACMIT" then
						if SN < "PHYMITMPBONUS" then
							if SN < "PHYMITHPBONUS" then
								if SN < "PHYDMGPRATPCAP" then
									if SN < "PHYDMGPRATP" then
										if SN > "PHYDMGPBONUS" then
											if SN == "PHYDMGPPRAT" then
												return CalcStat("OutDmgPPRat",L,N);
											else
												return 0;
											end
										elseif SN == "PHYDMGPBONUS" then
											return CalcStat("OutDmgPBonus",L);
										else
											return 0;
										end
									elseif SN > "PHYDMGPRATP" then
										if SN < "PHYDMGPRATPB" then
											if SN == "PHYDMGPRATPA" then
												return CalcStat("OutDmgPRatPA",L);
											else
												return 0;
											end
										elseif SN > "PHYDMGPRATPB" then
											if SN == "PHYDMGPRATPC" then
												return CalcStat("OutDmgPRatPC",L);
											else
												return 0;
											end
										else
											return CalcStat("OutDmgPRatPB",L);
										end
									else
										return CalcStat("OutDmgPRatP",L,N);
									end
								elseif SN > "PHYDMGPRATPCAP" then
									if SN < "PHYMASOLD" then
										if SN < "PHYMAS" then
											if SN == "PHYDMGPRATPCAPR" then
												return CalcStat("OutDmgPRatPCapR",L);
											else
												return 0;
											end
										elseif SN > "PHYMAS" then
											if SN == "PHYMASC" then
												return CalcStat("MasteryC",L,N);
											else
												return 0;
											end
										else
											return CalcStat("Mastery",L,N);
										end
									elseif SN > "PHYMASOLD" then
										if SN < "PHYMIT" then
											if SN == "PHYMAST" then
												return CalcStat("MasteryT",L,N);
											else
												return 0;
											end
										elseif SN > "PHYMIT" then
											if SN == "PHYMITC" then
												return StatLinInter("PntMPPhyMitC","CreepPntS","ProgBMitigationC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPPhyMit","ItemPntS","ProgBMitigation","AdjUmbarItemMit",L,N,0);
										end
									else
										return CalcStat("Mastery",L,N);
									end
								else
									return CalcStat("OutDmgPRatPCap",L);
								end
							elseif SN > "PHYMITHPBONUS" then
								if SN < "PHYMITLPBONUS" then
									if SN < "PHYMITHPRATPB" then
										if SN < "PHYMITHPRATP" then
											if SN == "PHYMITHPPRAT" then
												return CalcStat("MitHeavyPPRat",L,N);
											else
												return 0;
											end
										elseif SN > "PHYMITHPRATP" then
											if SN == "PHYMITHPRATPA" then
												return CalcStat("MitHeavyPRatPA",L);
											else
												return 0;
											end
										else
											return CalcStat("MitHeavyPRatP",L,N);
										end
									elseif SN > "PHYMITHPRATPB" then
										if SN < "PHYMITHPRATPCAP" then
											if SN == "PHYMITHPRATPC" then
												return CalcStat("MitHeavyPRatPC",L);
											else
												return 0;
											end
										elseif SN > "PHYMITHPRATPCAP" then
											if SN == "PHYMITHPRATPCAPR" then
												return CalcStat("MitHeavyPRatPCapR",L);
											else
												return 0;
											end
										else
											return CalcStat("MitHeavyPRatPCap",L);
										end
									else
										return CalcStat("MitHeavyPRatPB",L);
									end
								elseif SN > "PHYMITLPBONUS" then
									if SN < "PHYMITLPRATPB" then
										if SN < "PHYMITLPRATP" then
											if SN == "PHYMITLPPRAT" then
												return CalcStat("MitLightPPRat",L,N);
											else
												return 0;
											end
										elseif SN > "PHYMITLPRATP" then
											if SN == "PHYMITLPRATPA" then
												return CalcStat("MitLightPRatPA",L);
											else
												return 0;
											end
										else
											return CalcStat("MitLightPRatP",L,N);
										end
									elseif SN > "PHYMITLPRATPB" then
										if SN < "PHYMITLPRATPCAP" then
											if SN == "PHYMITLPRATPC" then
												return CalcStat("MitLightPRatPC",L);
											else
												return 0;
											end
										elseif SN > "PHYMITLPRATPCAP" then
											if SN == "PHYMITLPRATPCAPR" then
												return CalcStat("MitLightPRatPCapR",L);
											else
												return 0;
											end
										else
											return CalcStat("MitLightPRatPCap",L);
										end
									else
										return CalcStat("MitLightPRatPB",L);
									end
								else
									return CalcStat("MitLightPBonus",L);
								end
							else
								return CalcStat("MitHeavyPBonus",L);
							end
						elseif SN > "PHYMITMPBONUS" then
							if SN < "PNTMPARMOURC" then
								if SN < "PHYMITT" then
									if SN < "PHYMITMPRATPB" then
										if SN < "PHYMITMPRATP" then
											if SN == "PHYMITMPPRAT" then
												return CalcStat("MitMediumPPRat",L,N);
											else
												return 0;
											end
										elseif SN > "PHYMITMPRATP" then
											if SN == "PHYMITMPRATPA" then
												return CalcStat("MitMediumPRatPA",L);
											else
												return 0;
											end
										else
											return CalcStat("MitMediumPRatP",L,N);
										end
									elseif SN > "PHYMITMPRATPB" then
										if SN < "PHYMITMPRATPCAP" then
											if SN == "PHYMITMPRATPC" then
												return CalcStat("MitMediumPRatPC",L);
											else
												return 0;
											end
										elseif SN > "PHYMITMPRATPCAP" then
											if SN == "PHYMITMPRATPCAPR" then
												return CalcStat("MitMediumPRatPCapR",L);
											else
												return 0;
											end
										else
											return CalcStat("MitMediumPRatPCap",L);
										end
									else
										return CalcStat("MitMediumPRatPB",L);
									end
								elseif SN > "PHYMITT" then
									if SN < "PLAYERBASEPARRY" then
										if SN < "PLAYERBASEEVADE" then
											if SN == "PHYRESISTT" then
												return CalcStat("ResistAddT",L,N);
											else
												return 0;
											end
										elseif SN > "PLAYERBASEEVADE" then
											if SN == "PLAYERBASEMORALE" then
												return 52.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "PLAYERBASEPARRY" then
										if SN < "PLAYERBASETACMAS" then
											if SN == "PLAYERBASEPHYMAS" then
												return 11.5;
											else
												return 0;
											end
										elseif SN > "PLAYERBASETACMAS" then
											if SN == "PNTMPARMOUR" then
												return 4.4/1200;
											else
												return 0;
											end
										else
											return 11.5;
										end
									else
										return 3;
									end
								else
									return StatLinInter("PntMPPhyMit","TraitPntS","ProgBMitigation","AdjUmbarTraitMit",L,N,0);
								end
							elseif SN > "PNTMPARMOURC" then
								if SN < "PNTMPCOMBATDAMAGEMOD" then
									if SN < "PNTMPBPE" then
										if SN < "PNTMPARMOURT" then
											if SN == "PNTMPARMOURPENT" then
												return 72/1200;
											else
												return 0;
											end
										elseif SN > "PNTMPARMOURT" then
											if SN == "PNTMPARMOURVIRTUES" then
												return 24/1200;
											else
												return 0;
											end
										else
											return 25/1200;
										end
									elseif SN > "PNTMPBPE" then
										if SN < "PNTMPCLASSBASEICPR" then
											if SN == "PNTMPBPEC" then
												return 20430/6;
											else
												return 0;
											end
										elseif SN > "PNTMPCLASSBASEICPR" then
											if SN == "PNTMPCLASSBASENCPR" then
												return 0.25;
											else
												return 0;
											end
										else
											return 0.125;
										end
									else
										return 42/1200;
									end
								elseif SN > "PNTMPCOMBATDAMAGEMOD" then
									if SN < "PNTMPCRITHITC" then
										if SN < "PNTMPCRITDEFC" then
											if SN == "PNTMPCRITDEF" then
												return 40/1200;
											else
												return 0;
											end
										elseif SN > "PNTMPCRITDEFC" then
											if SN == "PNTMPCRITHIT" then
												return 20/1200;
											else
												return 0;
											end
										else
											return 20430/6;
										end
									elseif SN > "PNTMPCRITHITC" then
										if SN < "PNTMPFATE" then
											if SN == "PNTMPDMGTYPEMIT" then
												return 60/1200;
											else
												return 0;
											end
										elseif SN > "PNTMPFATE" then
											if SN == "PNTMPFATEC" then
												return 1803/6;
											else
												return 0;
											end
										else
											return 1.25;
										end
									else
										return 30610/6;
									end
								else
									return 300/1200;
								end
							else
								return 16990/6;
							end
						else
							return CalcStat("MitMediumPBonus",L);
						end
					else
						return CalcStat("TacMitT",L,0.2*N);
					end
				else
					return 25;
				end
			elseif SN > "PNTMPFINESSE" then
				if SN < "RIVERHOBBITRDPSVONENAME" then
					if SN < "PROGBINHEAL" then
						if SN < "PNTMPSHIELDBLOCK" then
							if SN < "PNTMPMITIGATION" then
								if SN < "PNTMPICPR" then
									if SN < "PNTMPFOODRESIST" then
										if SN > "PNTMPFINESSEC" then
											if SN == "PNTMPFINESSET" then
												return 36/1200;
											else
												return 0;
											end
										elseif SN == "PNTMPFINESSEC" then
											return 20430/6;
										else
											return 0;
										end
									elseif SN > "PNTMPFOODRESIST" then
										if SN < "PNTMPICMRC" then
											if SN == "PNTMPICMR" then
												return 0.015;
											else
												return 0;
											end
										elseif SN > "PNTMPICMRC" then
											if SN == "PNTMPICMRCOLD" then
												return 27;
											else
												return 0;
											end
										else
											return 44.4;
										end
									else
										return 30/1200;
									end
								elseif SN > "PNTMPICPR" then
									if SN < "PNTMPMAIN" then
										if SN < "PNTMPICPRCOLD" then
											if SN == "PNTMPICPRC" then
												return 5.1;
											else
												return 0;
											end
										elseif SN > "PNTMPICPRCOLD" then
											if SN == "PNTMPINHEAL" then
												return 40/1200;
											else
												return 0;
											end
										else
											return 3.125;
										end
									elseif SN > "PNTMPMAIN" then
										if SN < "PNTMPMASTERY" then
											if SN == "PNTMPMAINC" then
												return 1803/6;
											else
												return 0;
											end
										elseif SN > "PNTMPMASTERY" then
											if SN == "PNTMPMASTERYC" then
												return 30610/6;
											else
												return 0;
											end
										else
											return 17/1200;
										end
									else
										return 0.5;
									end
								else
									return 0.0625;
								end
							elseif SN > "PNTMPMITIGATION" then
								if SN < "PNTMPNCPRCOLD" then
									if SN < "PNTMPNCMRC" then
										if SN < "PNTMPMORALEVIRTUES" then
											if SN == "PNTMPMORALE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "PNTMPMORALEVIRTUES" then
											if SN == "PNTMPNCMR" then
												return 0.15;
											else
												return 0;
											end
										else
											return 0.75;
										end
									elseif SN > "PNTMPNCMRC" then
										if SN < "PNTMPNCPR" then
											if SN == "PNTMPNCMRCOLD" then
												return 108;
											else
												return 0;
											end
										elseif SN > "PNTMPNCPR" then
											if SN == "PNTMPNCPRC" then
												return 19;
											else
												return 0;
											end
										else
											return 0.5;
										end
									else
										return 164.8;
									end
								elseif SN > "PNTMPNCPRCOLD" then
									if SN < "PNTMPPOWER" then
										if SN < "PNTMPPHYMIT" then
											if SN == "PNTMPOUTHEAL" then
												return 30/1200;
											else
												return 0;
											end
										elseif SN > "PNTMPPHYMIT" then
											if SN == "PNTMPPHYMITC" then
												return 16990/6;
											else
												return 0;
											end
										else
											return 36/1200;
										end
									elseif SN > "PNTMPPOWER" then
										if SN < "PNTMPRESIST" then
											if SN == "PNTMPPOWERT" then
												return 0.6666;
											else
												return 0;
											end
										elseif SN > "PNTMPRESIST" then
											if SN == "PNTMPRESISTC" then
												return 30610/6;
											else
												return 0;
											end
										else
											return 36/1200;
										end
									else
										return 1;
									end
								else
									return 12.5;
								end
							else
								return 28/1200;
							end
						elseif SN > "PNTMPSHIELDBLOCK" then
							if SN < "PROGBBPEC" then
								if SN < "POWER" then
									if SN < "PNTMPVITALITY" then
										if SN < "PNTMPTACMIT" then
											if SN == "PNTMPTACHPS" then
												return 0.0875;
											else
												return 0;
											end
										elseif SN > "PNTMPTACMIT" then
											if SN == "PNTMPTACMITC" then
												return 16990/6;
											else
												return 0;
											end
										else
											return 36/1200;
										end
									elseif SN > "PNTMPVITALITY" then
										if SN < "PNTMPVITALITYT" then
											if SN == "PNTMPVITALITYC" then
												return 4500/6;
											else
												return 0;
											end
										elseif SN > "PNTMPVITALITYT" then
											if SN == "POISONRESISTT" then
												return CalcStat("ResistAddT",L,N);
											else
												return 0;
											end
										else
											return 0.225;
										end
									else
										return 0.175;
									end
								elseif SN > "POWER" then
									if SN < "PROGBARMOURHEAVY" then
										if SN < "PROGBARMOUR" then
											if SN == "POWERT" then
												return StatLinInter("PntMPPowerT","TraitPntSVital","ProgBPower","",L,N,0);
											else
												return 0;
											end
										elseif SN > "PROGBARMOUR" then
											if SN == "PROGBARMOURC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										else
											return CalcStat("BRatProgB",L,"BRatMitMedium");
										end
									elseif SN > "PROGBARMOURHEAVY" then
										if SN < "PROGBARMOURMEDIUM" then
											if SN == "PROGBARMOURLIGHT" then
												return CalcStat("BRatProgB",L,"BRatMitLight");
											else
												return 0;
											end
										elseif SN > "PROGBARMOURMEDIUM" then
											if SN == "PROGBBPE" then
												return CalcStat("BRatProgB",L,"BRatStandard");
											else
												return 0;
											end
										else
											return CalcStat("BRatProgB",L,"BRatMitMedium");
										end
									else
										return CalcStat("BRatProgB",L,"BRatMitHeavy");
									end
								else
									return StatLinInter("PntMPPower","ItemPntSVital","ProgBPower","",L,N,0);
								end
							elseif SN > "PROGBBPEC" then
								if SN < "PROGBFATEC" then
									if SN < "PROGBCRITHIT" then
										if SN < "PROGBCRITDEF" then
											if SN == "PROGBCOMBATDAMAGEMOD" then
												if Lm <= 25 then
													return LinFmod(1,5,45.58309,1,25,L);
												elseif Lm <= 50 then
													return LinFmod(1,45.58309,120,25,50,L);
												elseif Lm <= 60 then
													return LinFmod(1,120,175.56,50,60,L);
												elseif Lm <= 65 then
													return LinFmod(1,175.56,200.79,60,65,L);
												elseif Lm <= 75 then
													return LinFmod(1,200.79,292.5,65,75,L);
												elseif Lm <= 85 then
													return LinFmod(1,292.5,421.2,75,85,L);
												elseif Lm <= 95 then
													return LinFmod(1,421.2,600.3,85,95,L);
												elseif Lm <= 100 then
													return LinFmod(1,600.3,774,95,100,L);
												elseif Lm <= 105 then
													return LinFmod(1,774,985.5,100,105,L);
												elseif Lm <= 115 then
													return LinFmod(1,985.5,1350,105,115,L);
												elseif Lm <= 120 then
													return LinFmod(1,1350,1710,115,120,L);
												elseif Lm <= 130 then
													return LinFmod(1,1710,2330.25,120,130,L);
												elseif Lm <= 140 then
													return LinFmod(1,2330.25,3600,130,140,L);
												else
													return LinFmod(1,4010,5535,141,150,L);
												end
											else
												return 0;
											end
										elseif SN > "PROGBCRITDEF" then
											if SN == "PROGBCRITDEFC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										else
											return CalcStat("BRatProgB",L,"BRatStandard");
										end
									elseif SN > "PROGBCRITHIT" then
										if SN < "PROGBENERGY" then
											if SN == "PROGBCRITHITC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										elseif SN > "PROGBENERGY" then
											if SN == "PROGBFATE" then
												return CalcStat("ProgBEnergy",L);
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return LinFmod(1,4,8,1,50,L);
											elseif Lm <= 60 then
												return LinFmod(1,8,10.6,50,60,L);
											elseif Lm <= 65 then
												return LinFmod(1,10.6,13.2,60,65,L);
											elseif Lm <= 75 then
												return LinFmod(1,13.2,19.8,65,75,L);
											elseif Lm <= 85 then
												return LinFmod(1,19.8,29.8,75,85,L);
											elseif Lm <= 95 then
												return LinFmod(1,29.8,39.6,85,95,L);
											elseif Lm <= 100 then
												return LinFmod(1,39.6,52,95,100,L);
											elseif Lm <= 105 then
												return LinFmod(1,52,70,100,105,L);
											elseif Lm <= 115 then
												return LinFmod(1,78,106,106,115,L);
											elseif Lm <= 120 then
												return LinFmod(1,122,132,116,120,L);
											elseif Lm <= 130 then
												return LinFmod(1,152,198,121,130,L);
											elseif Lm <= 140 then
												return LinFmod(1,228,396,131,140,L);
											elseif Lm <= 150 then
												return LinFmod(1,456,800,141,150,L);
											else
												return LinFmod(1,800,1600,151,160,L);
											end
										end
									else
										return CalcStat("BRatProgB",L,"BRatExtra");
									end
								elseif SN > "PROGBFATEC" then
									if SN < "PROGBICMR" then
										if SN < "PROGBFINESSEC" then
											if SN == "PROGBFINESSE" then
												return CalcStat("BRatProgB",L,"BRatStandard");
											else
												return 0;
											end
										elseif SN > "PROGBFINESSEC" then
											if SN == "PROGBHEALTH" then
												if Lm <= 50 then
													return LinFmod(1,8,60,1,50,L);
												elseif Lm <= 60 then
													return LinFmod(1,60,80,50,60,L);
												elseif Lm <= 65 then
													return LinFmod(1,80,100,60,65,L);
												elseif Lm <= 75 then
													return LinFmod(1,100,150,65,75,L);
												elseif Lm <= 85 then
													return LinFmod(1,150,226,75,85,L);
												elseif Lm <= 95 then
													return LinFmod(1,226,300,85,95,L);
												elseif Lm <= 100 then
													return LinFmod(1,300,450,95,100,L);
												elseif Lm <= 105 then
													return LinFmod(1,450,600,100,105,L);
												elseif Lm <= 115 then
													return LinFmod(1,660,900,106,115,L);
												elseif Lm <= 120 then
													return LinFmod(1,1040,1120,116,120,L);
												elseif Lm <= 130 then
													return LinFmod(1,1280,1680,121,130,L);
												elseif Lm <= 140 then
													return LinFmod(1,1940,3360,131,140,L);
												elseif Lm <= 150 then
													return LinFmod(1,3860,6800,141,150,L);
												else
													return LinFmod(1,6800,13600,151,160,L);
												end
											else
												return 0;
											end
										else
											return CalcStat("CreepProgB",L);
										end
									elseif SN > "PROGBICMR" then
										if SN < "PROGBICPR" then
											if SN == "PROGBICMRC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										elseif SN > "PROGBICPR" then
											if SN == "PROGBICPRC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										else
											return CalcStat("ProgBEnergy",L);
										end
									else
										return CalcStat("ProgBHealth",L);
									end
								else
									return CalcStat("CreepProgB",L);
								end
							else
								return CalcStat("CreepProgB",L);
							end
						else
							return 80/1200;
						end
					elseif SN > "PROGBINHEAL" then
						if SN < "REAVERCDHASPOWER" then
							if SN < "PROGBRESISTC" then
								if SN < "PROGBMORALE" then
									if SN < "PROGBMASTERY" then
										if SN > "PROGBMAIN" then
											if SN == "PROGBMAINC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										elseif SN == "PROGBMAIN" then
											return CalcStat("StdProg",L,1.75);
										else
											return 0;
										end
									elseif SN > "PROGBMASTERY" then
										if SN < "PROGBMITIGATION" then
											if SN == "PROGBMASTERYC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										elseif SN > "PROGBMITIGATION" then
											if SN == "PROGBMITIGATIONC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										else
											return CalcStat("BRatProgB",L,"BRatMitMedium");
										end
									else
										return CalcStat("BRatProgB",L,"BRatExtra");
									end
								elseif SN > "PROGBMORALE" then
									if SN < "PROGBNCPRC" then
										if SN < "PROGBNCMRC" then
											if SN == "PROGBNCMR" then
												return CalcStat("ProgBHealth",L);
											else
												return 0;
											end
										elseif SN > "PROGBNCMRC" then
											if SN == "PROGBNCPR" then
												return CalcStat("ProgBEnergy",L);
											else
												return 0;
											end
										else
											return CalcStat("CreepProgB",L);
										end
									elseif SN > "PROGBNCPRC" then
										if SN < "PROGBPOWER" then
											if SN == "PROGBOUTHEAL" then
												return CalcStat("BRatProgB",L,"BRatOutHeal");
											else
												return 0;
											end
										elseif SN > "PROGBPOWER" then
											if SN == "PROGBRESIST" then
												return CalcStat("BRatProgB",L,"BRatExtra");
											else
												return 0;
											end
										else
											return CalcStat("ProgBEnergy",L);
										end
									else
										return CalcStat("CreepProgB",L);
									end
								else
									return CalcStat("ProgBHealth",L);
								end
							elseif SN > "PROGBRESISTC" then
								if SN < "PROGEXTHIGHLINEXPRND" then
									if SN < "PROGEXTCOMHIGHRAW" then
										if SN < "PROGBVITALITY" then
											if SN == "PROGBTACHPS" then
												return CalcStat("ProgBHealth",L);
											else
												return 0;
											end
										elseif SN > "PROGBVITALITY" then
											if SN == "PROGBVITALITYC" then
												return CalcStat("CreepProgB",L);
											else
												return 0;
											end
										else
											return CalcStat("ProgBHealth",L);
										end
									elseif SN > "PROGEXTCOMHIGHRAW" then
										if SN < "PROGEXTCOMLOWRAW" then
											if SN == "PROGEXTCOMHIGHRND" then
												if Lm <= 121 then
													return ExpFmod(N,121,20,L,0);
												elseif Lm <= 125 then
													return ExpFmod(CalcStat("ProgExtComHighRnd",121,N),122,5.5,L,0);
												elseif Lm <= 126 then
													return ExpFmod(CalcStat("ProgExtComHighRnd",125,N),126,20,L,0);
												elseif Lm <= 130 then
													return ExpFmod(CalcStat("ProgExtComHighRnd",126,N),127,5.5,L,0);
												elseif Lm <= 131 then
													return ExpFmod(CalcStat("ProgExtComHighRnd",130,N),131,20,L,0);
												elseif Lm <= 150 then
													return ExpFmod(CalcStat("ProgExtComHighRnd",131,N),132,5.5,L,0);
												else
													return CalcStat("ProgExtComHighRnd",150,N);
												end
											else
												return 0;
											end
										elseif SN > "PROGEXTCOMLOWRAW" then
											if SN == "PROGEXTCOMLOWRND" then
												if Lm <= 116 then
													return ExpFmod(N,116,20,L,0);
												elseif Lm <= 120 then
													return ExpFmod(CalcStat("ProgExtComLowRnd",116,N),117,5.5,L,0);
												else
													return CalcStat("ProgExtComHighRnd",L,CalcStat("ProgExtComLowRnd",120,N));
												end
											else
												return 0;
											end
										else
											if Lm <= 116 then
												return ExpFmod(N,116,20,L,nil);
											elseif Lm <= 120 then
												return ExpFmod(CalcStat("ProgExtComLowRaw",116,N),117,5.5,L,nil);
											else
												return CalcStat("ProgExtComHighRaw",L,CalcStat("ProgExtComLowRaw",120,N));
											end
										end
									else
										if Lm <= 121 then
											return ExpFmod(N,121,20,L,nil);
										elseif Lm <= 125 then
											return ExpFmod(CalcStat("ProgExtComHighRaw",121,N),122,5.5,L,nil);
										elseif Lm <= 126 then
											return ExpFmod(CalcStat("ProgExtComHighRaw",125,N),126,20,L,nil);
										elseif Lm <= 130 then
											return ExpFmod(CalcStat("ProgExtComHighRaw",126,N),127,5.5,L,nil);
										elseif Lm <= 131 then
											return ExpFmod(CalcStat("ProgExtComHighRaw",130,N),131,20,L,nil);
										elseif Lm <= 150 then
											return ExpFmod(CalcStat("ProgExtComHighRaw",131,N),132,5.5,L,nil);
										else
											return CalcStat("ProgExtComHighRaw",150,N);
										end
									end
								elseif SN > "PROGEXTHIGHLINEXPRND" then
									if SN < "REAVERCANBLOCK" then
										if SN < "PROGEXTMEDEXPRAW" then
											if SN == "PROGEXTLOWEXPRND" then
												if Lm <= 115 then
													return ExpFmod(N,106,5.5,L,0);
												else
													return CalcStat("ProgExtComLowRnd",L,CalcStat("ProgExtLowExpRnd",115,N));
												end
											else
												return 0;
											end
										elseif SN > "PROGEXTMEDEXPRAW" then
											if SN == "PROGEXTMPEXPRND" then
												if Lm <= 114 then
													return ExpFmod(N,106,7.5,L,0);
												elseif Lm <= 115 then
													return 2*N;
												elseif Lm <= 119 then
													return ExpFmod(CalcStat("ProgExtMpExpRnd",115,N),116,25,L,0);
												elseif Lm <= 120 then
													return RoundDbl((16/3)*N);
												else
													return CalcStat("ProgExtComHighRnd",L,CalcStat("ProgExtMpExpRnd",120,N));
												end
											else
												return 0;
											end
										else
											if Lm <= 106 then
												return ExpFmod(N,106,10,L,nil);
											elseif Lm <= 115 then
												return ExpFmod(CalcStat("ProgExtMedExpRaw",106,N),107,5.5,L,nil);
											else
												return CalcStat("ProgExtComLowRaw",L,CalcStat("ProgExtMedExpRaw",115,N));
											end
										end
									elseif SN > "REAVERCANBLOCK" then
										if SN < "REAVERCDCALCTYPENONPHYMIT" then
											if SN == "REAVERCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										elseif SN > "REAVERCDCALCTYPENONPHYMIT" then
											if SN == "REAVERCDCALCTYPETACMIT" then
												return 27;
											else
												return 0;
											end
										else
											return 14;
										end
									else
										return 1;
									end
								else
									if Lm <= 115 then
										return LinFmod(N,2,4,106,115,L,-1);
									else
										return CalcStat("ProgExtComLowRnd",L,CalcStat("ProgExtHighLinExpRnd",115,N));
									end
								end
							else
								return CalcStat("CreepProgB",L);
							end
						elseif SN > "REAVERCDHASPOWER" then
							if SN < "REPVITALITYL" then
								if SN < "REPMAINH" then
									if SN < "REPCRITHIT" then
										if SN < "REPAGILITYL" then
											if SN == "REPAGILITYH" then
												return CalcStat("RepMainH",L);
											else
												return 0;
											end
										elseif SN > "REPAGILITYL" then
											if SN == "REPCRITDEF" then
												if Lm <= 50 then
													return LinFmod(1,900,1488,1,50,L);
												elseif Lm <= 85 then
													return LinFmod(1,1488,1908,50,85,L);
												elseif Lm <= 105 then
													return LinFmod(1,1908,2148,85,105,L);
												else
													return LinFmod(1,2148,2328,105,120,L);
												end
											else
												return 0;
											end
										else
											return CalcStat("RepMainL",L);
										end
									elseif SN > "REPCRITHIT" then
										if SN < "REPFATEL" then
											if SN == "REPFATEH" then
												return CalcStat("RepMainH",L);
											else
												return 0;
											end
										elseif SN > "REPFATEL" then
											if SN == "REPFINESSE" then
												if Lm <= 50 then
													return LinFmod(1,322,557,1,50,L);
												elseif Lm <= 85 then
													return LinFmod(1,557,749.9477,50,85,L);
												elseif Lm <= 105 then
													return LinFmod(1,749.9477,859.1634,85,105,L);
												else
													return LinFmod(1,859.1634,939.2549,105,120,L);
												end
											else
												return 0;
											end
										else
											return CalcStat("RepMainL",L);
										end
									else
										if Lm <= 50 then
											return LinFmod(1,300,496,1,50,L);
										elseif Lm <= 85 then
											return LinFmod(1,496,636,50,85,L);
										elseif Lm <= 105 then
											return LinFmod(1,636,716,85,105,L);
										else
											return LinFmod(1,716,776,105,120,L);
										end
									end
								elseif SN > "REPMAINH" then
									if SN < "REPMORALE" then
										if SN < "REPMIGHTH" then
											if SN == "REPMAINL" then
												if Lm <= 50 then
													return RoundDblDown(LinFmod(1,53,102,1,50,L));
												elseif Lm <= 85 then
													return RoundDblDown(LinFmod(1,102,137,50,85,L));
												elseif Lm <= 105 then
													return RoundDblDown(LinFmod(1,137,157,85,105,L));
												else
													return RoundDblDown(LinFmod(1,157,172,105,120,L));
												end
											else
												return 0;
											end
										elseif SN > "REPMIGHTH" then
											if SN == "REPMIGHTL" then
												return CalcStat("RepMainL",L);
											else
												return 0;
											end
										else
											return CalcStat("RepMainH",L);
										end
									elseif SN > "REPMORALE" then
										if SN < "REPTACMIT" then
											if SN == "REPPOWER" then
												if Lm <= 50 then
													return LinFmod(1,94,212,1,50,L);
												elseif Lm <= 85 then
													return LinFmod(1,212,296,50,85,L);
												elseif Lm <= 105 then
													return LinFmod(1,296,344,85,105,L);
												else
													return LinFmod(1,344,380,105,120,L);
												end
											else
												return 0;
											end
										elseif SN > "REPTACMIT" then
											if SN == "REPVITALITYH" then
												return CalcStat("RepMainH",L);
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return LinFmod(1,675,1116,1,50,L);
											elseif Lm <= 85 then
												return LinFmod(1,1116,1431,50,85,L);
											elseif Lm <= 105 then
												return LinFmod(1,1431,1611,85,105,L);
											else
												return LinFmod(1,1611,1746,105,120,L);
											end
										end
									else
										if Lm <= 50 then
											return LinFmod(1,187,427,1,50,L);
										elseif Lm <= 85 then
											return LinFmod(1,427,599,50,85,L);
										elseif Lm <= 105 then
											return LinFmod(1,599,697,85,105,L);
										else
											return LinFmod(1,697,770,105,120,L);
										end
									end
								else
									if Lm <= 50 then
										return RoundDblDown(LinFmod(1,80,153,1,50,L));
									elseif Lm <= 85 then
										return RoundDblDown(LinFmod(1,153,206,50,85,L));
									elseif Lm <= 105 then
										return RoundDblDown(LinFmod(1,206,236,85,105,L));
									else
										return RoundDblDown(LinFmod(1,236,258,105,120,L));
									end
								end
							elseif SN > "REPVITALITYL" then
								if SN < "RESISTPRATP" then
									if SN < "RESISTADDT" then
										if SN < "REPWILLL" then
											if SN == "REPWILLH" then
												return CalcStat("RepMainH",L);
											else
												return 0;
											end
										elseif SN > "REPWILLL" then
											if SN == "RESIST" then
												return StatLinInter("PntMPResist","ItemPntS","ProgBResist","AdjUmbarItem",L,N,0);
											else
												return 0;
											end
										else
											return CalcStat("RepMainL",L);
										end
									elseif SN > "RESISTADDT" then
										if SN < "RESISTPBONUS" then
											if SN == "RESISTC" then
												return StatLinInter("PntMPResistC","CreepPntS","ProgBResistC","",L,N,0);
											else
												return 0;
											end
										elseif SN > "RESISTPBONUS" then
											if SN == "RESISTPPRAT" then
												return CalcRatAB(CalcStat("ResistPRatPA",L),CalcStat("ResistPRatPB",L),CalcStat("ResistPRatPCapR",L),N);
											else
												return 0;
											end
										else
											return 0;
										end
									else
										return CalcStat("ResistT",L,N);
									end
								elseif SN > "RESISTPRATP" then
									if SN < "RESISTPRATPCAP" then
										if SN < "RESISTPRATPB" then
											if SN == "RESISTPRATPA" then
												return 150;
											else
												return 0;
											end
										elseif SN > "RESISTPRATPB" then
											if SN == "RESISTPRATPC" then
												return 0.5;
											else
												return 0;
											end
										else
											return CalcStat("BRatRounded",L,"BRatExtra");
										end
									elseif SN > "RESISTPRATPCAP" then
										if SN < "RESISTT" then
											if SN == "RESISTPRATPCAPR" then
												return CalcStat("ResistPRatPB",L)*CalcStat("ResistPRatPC",L);
											else
												return 0;
											end
										elseif SN > "RESISTT" then
											if SN == "REVERSE" then
												return ReverseCalc(C,L);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPResist","TraitPntS","ProgBResist","AdjUmbarTrait",L,N,0);
										end
									else
										return 50;
									end
								else
									return CalcPercAB(CalcStat("ResistPRatPA",L),CalcStat("ResistPRatPB",L),CalcStat("ResistPRatPCap",L),N);
								end
							else
								return CalcStat("RepMainL",L);
							end
						else
							return 1;
						end
					else
						return CalcStat("BRatProgB",L,"BRatStandard");
					end
				elseif SN > "RIVERHOBBITRDPSVONENAME" then
					if SN < "STALKERCDCALCTYPECOMPHYMIT" then
						if SN < "RUNEKEEPERCDBASEVITALITY" then
							if SN < "RUNEKEEPERCDAGILITYTOEVADE" then
								if SN < "RIVHOBHARDYHOLBMORALE" then
									if SN < "RIVERHOBBITRDTRAITAGILITY" then
										if SN > "RIVERHOBBITRDPSVONEWILL" then
											if SN == "RIVERHOBBITRDPSVTWONAME" then
												return "";
											else
												return 0;
											end
										elseif SN == "RIVERHOBBITRDPSVONEWILL" then
											return CalcStat("RivHobSeenWorldWill",L);
										else
											return 0;
										end
									elseif SN > "RIVERHOBBITRDTRAITAGILITY" then
										if SN < "RIVERHOBBITRDTRAITMORALE" then
											if SN == "RIVERHOBBITRDTRAITFROSTMITP" then
												return CalcStat("RivHobSwimmerFrostMitP",L);
											else
												return 0;
											end
										elseif SN > "RIVERHOBBITRDTRAITMORALE" then
											if SN == "RIVERHOBBITRDTRAITWILL" then
												return CalcStat("RivHobSeclusionWill",L);
											else
												return 0;
											end
										else
											return CalcStat("RivHobHardyHolbMorale",L);
										end
									else
										return CalcStat("RivHobSlipperyAgility",L);
									end
								elseif SN > "RIVHOBHARDYHOLBMORALE" then
									if SN < "RIVHOBSWIMMERFROSTMITP" then
										if SN < "RIVHOBSEENWORLDWILL" then
											if SN == "RIVHOBSECLUSIONWILL" then
												return -CalcStat("WillT",L,0.4);
											else
												return 0;
											end
										elseif SN > "RIVHOBSEENWORLDWILL" then
											if SN == "RIVHOBSLIPPERYAGILITY" then
												return CalcStat("AgilityT",L,1.0);
											else
												return 0;
											end
										else
											return CalcStat("WillT",L,1.0);
										end
									elseif SN > "RIVHOBSWIMMERFROSTMITP" then
										if SN < "RKFORTUNESMILESFATE" then
											if SN == "RKDETERMINATIONWILL" then
												return CalcStat("WillT",L,CalcStat("Trait567810Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "RKFORTUNESMILESFATE" then
											if SN == "RUNEKEEPERCDAGILITYTOCRITHIT" then
												return 2;
											else
												return 0;
											end
										else
											return CalcStat("FateT",L,CalcStat("Trait567810Choice",N)*0.4);
										end
									else
										return 1;
									end
								else
									return CalcStat("MoraleT",L,1.0);
								end
							elseif SN > "RUNEKEEPERCDAGILITYTOEVADE" then
								if SN < "RUNEKEEPERCDBASEFATE" then
									if SN < "RUNEKEEPERCDARMOURTONONPHYMIT" then
										if SN < "RUNEKEEPERCDAGILITYTOTACMAS" then
											if SN == "RUNEKEEPERCDAGILITYTOFINESSE" then
												return 1;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDAGILITYTOTACMAS" then
											if SN == "RUNEKEEPERCDARMOURTOCOMPHYMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "RUNEKEEPERCDARMOURTONONPHYMIT" then
										if SN < "RUNEKEEPERCDARMOURTYPE" then
											if SN == "RUNEKEEPERCDARMOURTOTACMIT" then
												return 0.2;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDARMOURTYPE" then
											if SN == "RUNEKEEPERCDBASEAGILITY" then
												return CalcStat("ClassBaseAgilityL",L);
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 0.2;
									end
								elseif SN > "RUNEKEEPERCDBASEFATE" then
									if SN < "RUNEKEEPERCDBASEMORALE" then
										if SN < "RUNEKEEPERCDBASEICPR" then
											if SN == "RUNEKEEPERCDBASEICMR" then
												return CalcStat("ClassBaseICMRL",L);
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDBASEICPR" then
											if SN == "RUNEKEEPERCDBASEMIGHT" then
												return CalcStat("ClassBaseMightM",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseICPR",L);
										end
									elseif SN > "RUNEKEEPERCDBASEMORALE" then
										if SN < "RUNEKEEPERCDBASENCPR" then
											if SN == "RUNEKEEPERCDBASENCMR" then
												return CalcStat("ClassBaseNCMRL",L);
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDBASENCPR" then
											if SN == "RUNEKEEPERCDBASEPOWER" then
												return CalcStat("ClassBasePower",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseNCPR",L);
										end
									else
										return CalcStat("ClassBaseMorale",L);
									end
								else
									return CalcStat("ClassBaseFate",L);
								end
							else
								return 1;
							end
						elseif SN > "RUNEKEEPERCDBASEVITALITY" then
							if SN < "RUNEKEEPERCDVITALITYTOMORALE" then
								if SN < "RUNEKEEPERCDMIGHTTOCRITHIT" then
									if SN < "RUNEKEEPERCDCALCTYPETACMIT" then
										if SN < "RUNEKEEPERCDCALCTYPECOMPHYMIT" then
											if SN == "RUNEKEEPERCDBASEWILL" then
												return CalcStat("ClassBaseWillH",L);
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDCALCTYPECOMPHYMIT" then
											if SN == "RUNEKEEPERCDCALCTYPENONPHYMIT" then
												return 12;
											else
												return 0;
											end
										else
											return 12;
										end
									elseif SN > "RUNEKEEPERCDCALCTYPETACMIT" then
										if SN < "RUNEKEEPERCDFATETOPOWER" then
											if SN == "RUNEKEEPERCDFATETONCPR" then
												return 0.07;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDFATETOPOWER" then
											if SN == "RUNEKEEPERCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 25;
									end
								elseif SN > "RUNEKEEPERCDMIGHTTOCRITHIT" then
									if SN < "RUNEKEEPERCDPHYMITTOCOMPHYMIT" then
										if SN < "RUNEKEEPERCDMIGHTTOTACMAS" then
											if SN == "RUNEKEEPERCDMIGHTTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDMIGHTTOTACMAS" then
											if SN == "RUNEKEEPERCDMIGHTTOTACMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 2;
										end
									elseif SN > "RUNEKEEPERCDPHYMITTOCOMPHYMIT" then
										if SN < "RUNEKEEPERCDTACMASTOOUTHEAL" then
											if SN == "RUNEKEEPERCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDTACMASTOOUTHEAL" then
											if SN == "RUNEKEEPERCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								else
									return 1;
								end
							elseif SN > "RUNEKEEPERCDVITALITYTOMORALE" then
								if SN < "SHADOWMIT" then
									if SN < "RUNEKEEPERCDWILLTOPHYMIT" then
										if SN < "RUNEKEEPERCDWILLTOCRITHIT" then
											if SN == "RUNEKEEPERCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDWILLTOCRITHIT" then
											if SN == "RUNEKEEPERCDWILLTOEVADE" then
												return 2;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "RUNEKEEPERCDWILLTOPHYMIT" then
										if SN < "RUNEKEEPERCDWILLTOTACMAS" then
											if SN == "RUNEKEEPERCDWILLTORESIST" then
												return 1;
											else
												return 0;
											end
										elseif SN > "RUNEKEEPERCDWILLTOTACMAS" then
											if SN == "RUNEKEEPERCDWILLTOTACMIT" then
												return 1;
											else
												return 0;
											end
										else
											return 3;
										end
									else
										return 1;
									end
								elseif SN > "SHADOWMIT" then
									if SN < "SKILLPOWERCOST" then
										if SN < "SHIELDBLOCK" then
											if SN == "SHADOWMITT" then
												return CalcStat("DmgTypeMitT",L,N);
											else
												return 0;
											end
										elseif SN > "SHIELDBLOCK" then
											if SN == "SHIELDBRAWLERBLOCK" then
												return CalcStat("DwarfShieldBrwlBlock",L);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPShieldBlock","ItemPntS","ProgBBPE","AdjUmbarItem",L,N,0);
										end
									elseif SN > "SKILLPOWERCOST" then
										if SN < "SONGRESISTT" then
											if SN == "SKILLPOWERCOSTMOUNTED" then
												return CalcStat("CombatDamageModEnergy",L,0.64*N);
											else
												return 0;
											end
										elseif SN > "SONGRESISTT" then
											if SN == "STALKERCANBLOCK" then
												return 1;
											else
												return 0;
											end
										else
											return CalcStat("ResistAddT",L,N);
										end
									else
										if Lm <= 140 then
											return CalcStat("CombatDamageModEnergy",L,0.64*N);
										else
											return CalcStat("CombatDamageModEnergy",L,1.05*0.64*N);
										end
									end
								else
									return CalcStat("DmgTypeMit",L,N);
								end
							else
								return 4.5;
							end
						else
							return CalcStat("ClassBaseVitality",L);
						end
					elseif SN > "STALKERCDCALCTYPECOMPHYMIT" then
						if SN < "STOUTWRBLACKLMIGHT" then
							if SN < "STOUTAXERDPSVTWONAME" then
								if SN < "STDMORALERAW" then
									if SN < "STATC" then
										if SN < "STALKERCDCALCTYPETACMIT" then
											if SN == "STALKERCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN > "STALKERCDCALCTYPETACMIT" then
											if SN == "STALKERCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 27;
										end
									elseif SN > "STATC" then
										if SN < "STDMORALEL" then
											if SN == "STDMORALEH" then
												if Lm <= 105 then
													return RoundDbl(2*CalcStat("StdMoraleRaw",L));
												else
													return CalcStat("ProgExtLowExpRnd",L,CalcStat("StdMoraleH",105));
												end
											else
												return 0;
											end
										elseif SN > "STDMORALEL" then
											if SN == "STDMORALEM" then
												if Lm <= 105 then
													return RoundDbl(1.5*CalcStat("StdMoraleRaw",L));
												else
													return CalcStat("ProgExtLowExpRnd",L,CalcStat("StdMoraleM",105));
												end
											else
												return 0;
											end
										else
											if Lm <= 105 then
												return RoundDbl(CalcStat("StdMoraleRaw",L));
											else
												return CalcStat("ProgExtLowExpRnd",L,CalcStat("StdMoraleL",105));
											end
										end
									else
										return CalcStat(C,L);
									end
								elseif SN > "STDMORALERAW" then
									if SN < "STDPOWERRAW" then
										if SN < "STDPOWERH" then
											if SN == "STDPNTS" then
												return {{1,50,60,65,75,85,95,100,105,106,115,116,120,121,130,131,140,141,150,151,160},{1,50,60,65,75,85,95,100,105,106,115,116,120,121,130,131,140,141,150,151,160}};
											else
												return 0;
											end
										elseif SN > "STDPOWERH" then
											if SN == "STDPOWERL" then
												if Lm <= 105 then
													return RoundDbl(CalcStat("StdPowerRaw",L));
												else
													return CalcStat("ProgExtLowExpRnd",L,CalcStat("StdPowerL",105));
												end
											else
												return 0;
											end
										else
											if Lm <= 105 then
												return RoundDbl(2*CalcStat("StdPowerRaw",L));
											else
												return CalcStat("ProgExtLowExpRnd",L,CalcStat("StdPowerH",105));
											end
										end
									elseif SN > "STDPOWERRAW" then
										if SN < "STOUTAXERDPSVONENAME" then
											if SN == "STDPROG" then
												if Lm <= 50 then
													return LinFmod(N,1,10,1,50,L,"P");
												elseif Lm <= 60 then
													return LinFmod(CalcStat("StdProg",50,N),10/10,15/10,50,60,L,"P");
												elseif Lm <= 65 then
													return LinFmod(CalcStat("StdProg",60,N),15/15,20/15,60,65,L,"P");
												elseif Lm <= 75 then
													return LinFmod(CalcStat("StdProg",65,N),20/20,30/20,65,75,L,"P");
												elseif Lm <= 85 then
													return LinFmod(CalcStat("StdProg",75,N),30/30,45/30,75,85,L,"P");
												elseif Lm <= 95 then
													return LinFmod(CalcStat("StdProg",85,N),45/45,65/45,85,95,L,"P");
												elseif Lm <= 100 then
													return LinFmod(CalcStat("StdProg",95,N),65/65,90.27/65,95,100,L,"P");
												elseif Lm <= 105 then
													return LinFmod(CalcStat("StdProg",100,N),90.27/90.27,120.24/90.27,100,105,L,"P");
												elseif Lm <= 115 then
													return LinFmod(CalcStat("StdProg",105,N),1.1,1.5,106,115,L,"P");
												elseif Lm <= 120 then
													return LinFmod(CalcStat("StdProg",115,N),1.15,1.25,116,120,L,"P");
												elseif Lm <= 130 then
													return LinFmod(CalcStat("StdProg",120,N),1.15,1.5,121,130,L,"P");
												elseif Lm <= 140 then
													return LinFmod(CalcStat("StdProg",130,N),1.15,2,131,140,L,"P");
												elseif Lm <= 150 then
													return LinFmod(CalcStat("StdProg",140,N),1.3,2.205,141,150,L,"P");
												else
													return LinFmod(CalcStat("StdProg",150,N),1,2,151,160,L,"P");
												end
											else
												return 0;
											end
										elseif SN > "STOUTAXERDPSVONENAME" then
											if SN == "STOUTAXERDPSVONEVITALITY" then
												return CalcStat("StoutUnwritDestVitality",L);
											else
												return 0;
											end
										else
											return "Unwritten Destiny";
										end
									else
										if Lm <= 50 then
											return LinFmod(1,3,91.0375,1,50,L);
										else
											return LinFmod(1,91.0375,421,50,105,L);
										end
									end
								else
									if Lm <= 50 then
										return LinFmod(1,7.51,227.59,1,50,L);
									else
										return LinFmod(1,227.59,1327.5,50,105,L);
									end
								end
							elseif SN > "STOUTAXERDPSVTWONAME" then
								if SN < "STOUTAXERDTRAITWILL" then
									if SN < "STOUTAXERDTRAITMIGHT" then
										if SN < "STOUTAXERDTRAITDISEASERESISTP" then
											if SN == "STOUTAXERDTRAITAGILITY" then
												return CalcStat("StoutWrBlackLAgility",L);
											else
												return 0;
											end
										elseif SN > "STOUTAXERDTRAITDISEASERESISTP" then
											if SN == "STOUTAXERDTRAITFATE" then
												return CalcStat("StoutDoomDrasaFate",L);
											else
												return 0;
											end
										else
											return CalcStat("StoutWrBlackLDiseaseResistP",L);
										end
									elseif SN > "STOUTAXERDTRAITMIGHT" then
										if SN < "STOUTAXERDTRAITSHADOWMITP" then
											if SN == "STOUTAXERDTRAITPHYMITP" then
												return CalcStat("StoutUnyieldingPhyMitP",L);
											else
												return 0;
											end
										elseif SN > "STOUTAXERDTRAITSHADOWMITP" then
											if SN == "STOUTAXERDTRAITVITALITY" then
												return CalcStat("StoutShadowEyeVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("StoutWrBlackLShadowMitP",L);
										end
									else
										return CalcStat("StoutWrBlackLMight",L);
									end
								elseif SN > "STOUTAXERDTRAITWILL" then
									if SN < "STOUTUNYIELDINGPHYMITP" then
										if SN < "STOUTSHADOWEYEVITALITY" then
											if SN == "STOUTDOOMDRASAFATE" then
												return -CalcStat("FateT",L,0.4);
											else
												return 0;
											end
										elseif SN > "STOUTSHADOWEYEVITALITY" then
											if SN == "STOUTUNWRITDESTVITALITY" then
												return CalcStat("VitalityT",L,1.0);
											else
												return 0;
											end
										else
											return -CalcStat("VitalityT",L,0.4);
										end
									elseif SN > "STOUTUNYIELDINGPHYMITP" then
										if SN < "STOUTWRBLACKLAGILITY" then
											if SN == "STOUTUNYIELDINGWILL" then
												return CalcStat("WillT",L,1.0);
											else
												return 0;
											end
										elseif SN > "STOUTWRBLACKLAGILITY" then
											if SN == "STOUTWRBLACKLDISEASERESISTP" then
												return 1;
											else
												return 0;
											end
										else
											return CalcStat("AgilityT",L,1.0);
										end
									else
										return 1;
									end
								else
									return CalcStat("StoutUnyieldingWill",L);
								end
							else
								return "";
							end
						elseif SN > "STOUTWRBLACKLMIGHT" then
							if SN < "TACMASOLD" then
								if SN < "TACDMGPRATP" then
									if SN < "T2PENMIT" then
										if SN < "T2PENARMOUR" then
											if SN == "STOUTWRBLACKLSHADOWMITP" then
												return 1;
											else
												return 0;
											end
										elseif SN > "T2PENARMOUR" then
											if SN == "T2PENBPE" then
												if Lm <= 115 then
													return (-40)*L;
												else
													return CalcStat("ProgExtComLowRaw",L,CalcStat("T2PenBPE",115));
												end
											else
												return 0;
											end
										else
											return CalcStat("T2penMit",L);
										end
									elseif SN > "T2PENMIT" then
										if SN < "TACDMGPBONUS" then
											if SN == "T2PENRESIST" then
												if Lm <= 115 then
													return (-90)*L;
												else
													return CalcStat("ProgExtComLowRaw",L,CalcStat("T2PenResist",115));
												end
											else
												return 0;
											end
										elseif SN > "TACDMGPBONUS" then
											if SN == "TACDMGPPRAT" then
												return CalcStat("OutDmgPPRat",L,N);
											else
												return 0;
											end
										else
											return CalcStat("OutDmgPBonus",L);
										end
									else
										if Lm <= 115 then
											return RoundDblDown(L*13.5)*-5;
										else
											return CalcStat("ProgExtComLowRaw",L,CalcStat("T2PenMit",115));
										end
									end
								elseif SN > "TACDMGPRATP" then
									if SN < "TACDMGPRATPCAP" then
										if SN < "TACDMGPRATPB" then
											if SN == "TACDMGPRATPA" then
												return CalcStat("OutDmgPRatPA",L);
											else
												return 0;
											end
										elseif SN > "TACDMGPRATPB" then
											if SN == "TACDMGPRATPC" then
												return CalcStat("OutDmgPRatPC",L);
											else
												return 0;
											end
										else
											return CalcStat("OutDmgPRatPB",L);
										end
									elseif SN > "TACDMGPRATPCAP" then
										if SN < "TACMAS" then
											if SN == "TACDMGPRATPCAPR" then
												return CalcStat("OutDmgPRatPCapR",L);
											else
												return 0;
											end
										elseif SN > "TACMAS" then
											if SN == "TACMASC" then
												return CalcStat("MasteryC",L,N);
											else
												return 0;
											end
										else
											return CalcStat("Mastery",L,N);
										end
									else
										return CalcStat("OutDmgPRatPCap",L);
									end
								else
									return CalcStat("OutDmgPRatP",L,N);
								end
							elseif SN > "TACMASOLD" then
								if SN < "TACMITHPRATPB" then
									if SN < "TACMITHPBONUS" then
										if SN < "TACMIT" then
											if SN == "TACMAST" then
												return CalcStat("MasteryT",L,N);
											else
												return 0;
											end
										elseif SN > "TACMIT" then
											if SN == "TACMITC" then
												return StatLinInter("PntMPTacMitC","CreepPntS","ProgBMitigationC","",L,N,0);
											else
												return 0;
											end
										else
											return StatLinInter("PntMPTacMit","ItemPntS","ProgBMitigation","AdjUmbarItemMit",L,N,0);
										end
									elseif SN > "TACMITHPBONUS" then
										if SN < "TACMITHPRATP" then
											if SN == "TACMITHPPRAT" then
												return CalcStat("MitHeavyPPRat",L,N);
											else
												return 0;
											end
										elseif SN > "TACMITHPRATP" then
											if SN == "TACMITHPRATPA" then
												return CalcStat("MitHeavyPRatPA",L);
											else
												return 0;
											end
										else
											return CalcStat("MitHeavyPRatP",L,N);
										end
									else
										return CalcStat("MitHeavyPBonus",L);
									end
								elseif SN > "TACMITHPRATPB" then
									if SN < "TACMITLPBONUS" then
										if SN < "TACMITHPRATPCAP" then
											if SN == "TACMITHPRATPC" then
												return CalcStat("MitHeavyPRatPC",L);
											else
												return 0;
											end
										elseif SN > "TACMITHPRATPCAP" then
											if SN == "TACMITHPRATPCAPR" then
												return CalcStat("MitHeavyPRatPCapR",L);
											else
												return 0;
											end
										else
											return CalcStat("MitHeavyPRatPCap",L);
										end
									elseif SN > "TACMITLPBONUS" then
										if SN < "TACMITLPRATP" then
											if SN == "TACMITLPPRAT" then
												return CalcStat("MitLightPPRat",L,N);
											else
												return 0;
											end
										elseif SN > "TACMITLPRATP" then
											if SN == "TACMITLPRATPA" then
												return CalcStat("MitLightPRatPA",L);
											else
												return 0;
											end
										else
											return CalcStat("MitLightPRatP",L,N);
										end
									else
										return CalcStat("MitLightPBonus",L);
									end
								else
									return CalcStat("MitHeavyPRatPB",L);
								end
							else
								return CalcStat("Mastery",L,N);
							end
						else
							return CalcStat("MightT",L,1.0);
						end
					else
						return 13;
					end
				else
					return "Seen the World";
				end
			else
				return 40/1200;
			end
		elseif SN > "TACMITLPRATPB" then
			if SN < "WARDENCDMIGHTTOPHYMAS" then
				if SN < "VIRTWISDOMTACMAS" then
					if SN < "VIRTDETERMINATIONVPPHYMAS" then
						if SN < "TRAIT12345CHOICE" then
							if SN < "TOMEFATEDEC" then
								if SN < "TACMITMPRATPA" then
									if SN < "TACMITLPRATPCAPR" then
										if SN > "TACMITLPRATPC" then
											if SN == "TACMITLPRATPCAP" then
												return CalcStat("MitLightPRatPCap",L);
											else
												return 0;
											end
										elseif SN == "TACMITLPRATPC" then
											return CalcStat("MitLightPRatPC",L);
										else
											return 0;
										end
									elseif SN > "TACMITLPRATPCAPR" then
										if SN < "TACMITMPPRAT" then
											if SN == "TACMITMPBONUS" then
												return CalcStat("MitMediumPBonus",L);
											else
												return 0;
											end
										elseif SN > "TACMITMPPRAT" then
											if SN == "TACMITMPRATP" then
												return CalcStat("MitMediumPRatP",L,N);
											else
												return 0;
											end
										else
											return CalcStat("MitMediumPPRat",L,N);
										end
									else
										return CalcStat("MitLightPRatPCapR",L);
									end
								elseif SN > "TACMITMPRATPA" then
									if SN < "TACMITMPRATPCAPR" then
										if SN < "TACMITMPRATPC" then
											if SN == "TACMITMPRATPB" then
												return CalcStat("MitMediumPRatPB",L);
											else
												return 0;
											end
										elseif SN > "TACMITMPRATPC" then
											if SN == "TACMITMPRATPCAP" then
												return CalcStat("MitMediumPRatPCap",L);
											else
												return 0;
											end
										else
											return CalcStat("MitMediumPRatPC",L);
										end
									elseif SN > "TACMITMPRATPCAPR" then
										if SN < "TACRESISTT" then
											if SN == "TACMITT" then
												return StatLinInter("PntMPTacMit","TraitPntS","ProgBMitigation","AdjUmbarTraitMit",L,N,0);
											else
												return 0;
											end
										elseif SN > "TACRESISTT" then
											if SN == "TOMEFATE" then
												return CalcStat("TomeFateDec",RomanRankDecode(C));
											else
												return 0;
											end
										else
											return CalcStat("ResistAddT",L,N);
										end
									else
										return CalcStat("MitMediumPRatPCapR",L);
									end
								else
									return CalcStat("MitMediumPRatPA",L);
								end
							elseif SN > "TOMEFATEDEC" then
								if SN < "TOMETOTALVITALITY" then
									if SN < "TOMETOTALFATEDEC" then
										if SN < "TOMEMAINDEC" then
											if SN == "TOMEMAIN" then
												return CalcStat("TomeMainDec",RomanRankDecode(C));
											else
												return 0;
											end
										elseif SN > "TOMEMAINDEC" then
											if SN == "TOMETOTALFATE" then
												return CalcStat("TomeTotalFateDec",RomanRankDecode(C));
											else
												return 0;
											end
										else
											return CalcStat("TomeTotalMainDec",L)-CalcStat("TomeTotalMainDec",L-1);
										end
									elseif SN > "TOMETOTALFATEDEC" then
										if SN < "TOMETOTALMAIN" then
											if SN == "TOMETOTALLEVEL" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({4,15,27,38,48,54,60,63,67,71,75,78,85,90,95,98,101,104,106,110,114,116,121},L);
												end
											else
												return 0;
											end
										elseif SN > "TOMETOTALMAIN" then
											if SN == "TOMETOTALMAINDEC" then
												return CalcStat("MainT",CalcStat("TomeTotalLevel",L),2.0);
											else
												return 0;
											end
										else
											return CalcStat("TomeTotalMainDec",RomanRankDecode(C));
										end
									else
										return CalcStat("FateT",CalcStat("TomeTotalLevel",L),2.0);
									end
								elseif SN > "TOMETOTALVITALITY" then
									if SN < "TPENARMOUR" then
										if SN < "TOMEVITALITY" then
											if SN == "TOMETOTALVITALITYDEC" then
												return CalcStat("VitalityT",CalcStat("TomeTotalLevel",L),2.0);
											else
												return 0;
											end
										elseif SN > "TOMEVITALITY" then
											if SN == "TOMEVITALITYDEC" then
												return CalcStat("TomeTotalVitalityDec",L)-CalcStat("TomeTotalVitalityDec",L-1);
											else
												return 0;
											end
										else
											return CalcStat("TomeVitalityDec",RomanRankDecode(C));
										end
									elseif SN > "TPENARMOUR" then
										if SN < "TPENCHOICE" then
											if SN == "TPENBPE" then
												return -CalcStat("BPET",L,CalcStat("TpenChoice",N));
											else
												return 0;
											end
										elseif SN > "TPENCHOICE" then
											if SN == "TPENRESIST" then
												return -CalcStat("ResistT",L,CalcStat("TpenChoice",N)*2);
											else
												return 0;
											end
										else
											return DataTableValue({0.5,1,2},L);
										end
									else
										return -CalcStat("ArmourPenT",L,CalcStat("TpenChoice",N));
									end
								else
									return CalcStat("TomeTotalVitalityDec",RomanRankDecode(C));
								end
							else
								return CalcStat("TomeTotalFateDec",L)-CalcStat("TomeTotalFateDec",L-1);
							end
						elseif SN > "TRAIT12345CHOICE" then
							if SN < "VIRTCHARITYPHYMIT" then
								if SN < "TRAIT47101316CHOICE" then
									if SN < "TRAIT13510CHOICE" then
										if SN < "TRAIT1234CHOICE" then
											if SN == "TRAIT12347CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,2,3,4,7},L);
												end
											else
												return 0;
											end
										elseif SN > "TRAIT1234CHOICE" then
											if SN == "TRAIT123CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,2,3},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({1,2,3,4},L);
											end
										end
									elseif SN > "TRAIT13510CHOICE" then
										if SN < "TRAIT234CHOICE" then
											if SN == "TRAIT23456CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({2,3,4,5,6},L);
												end
											else
												return 0;
											end
										elseif SN > "TRAIT234CHOICE" then
											if SN == "TRAIT357912CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({3,5,7,9,12},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({2,3,4},L);
											end
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return DataTableValue({1,3,5,10},L);
										end
									end
								elseif SN > "TRAIT47101316CHOICE" then
									if SN < "TRAITPNTS" then
										if SN < "TRAIT56789CHOICE" then
											if SN == "TRAIT567810CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({5,6,7,8,10},L);
												end
											else
												return 0;
											end
										elseif SN > "TRAIT56789CHOICE" then
											if SN == "TRAIT58121620CHOICE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({5,8,12,16,20},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({5,6,7,8,9},L);
											end
										end
									elseif SN > "TRAITPNTS" then
										if SN < "U371LEGACYSTATFIX" then
											if SN == "TRAITPNTSVITAL" then
												return {{1,25,50,60,65,75,85,95,100,105,115,120,130,140,141,150},{1,25,50,60,65,75,85,95,100,105,115,120,130,140,141,150}};
											else
												return 0;
											end
										elseif SN > "U371LEGACYSTATFIX" then
											if SN == "VARMOUR" then
												return RoundDbl(StatLinInter("PntMPArmourVirtues","ItemPntS","ProgBArmourLight","ArmourAdjTypeOther",L,N,0));
											else
												return 0;
											end
										else
											if Lm <= 2 then
												return 0;
											else
												return RoundDblUp(CalcStat(C,L-2)*0.07);
											end
										end
									else
										return {{1,25,50,60,65,75,85,95,100,105,115,120,130,131,140,141,150},{1,25,50,60,65,75,85,95,100,105,115,120,130,131,140,141,150}};
									end
								else
									if Lm <= 0 then
										return 0;
									else
										return DataTableValue({4,7,10,13,16},L);
									end
								end
							elseif SN > "VIRTCHARITYPHYMIT" then
								if SN < "VIRTCONFIDENCECRITHIT" then
									if SN < "VIRTCOMPASSIONARMOUR" then
										if SN < "VIRTCHARITYVITALITY" then
											if SN == "VIRTCHARITYRESIST" then
												return CalcStat("VSResistH",L);
											else
												return 0;
											end
										elseif SN > "VIRTCHARITYVITALITY" then
											if SN == "VIRTCHARITYVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVitalityL",L);
										end
									elseif SN > "VIRTCOMPASSIONARMOUR" then
										if SN < "VIRTCOMPASSIONTACMIT" then
											if SN == "VIRTCOMPASSIONPHYMIT" then
												return CalcStat("VSPhyMitH",L);
											else
												return 0;
											end
										elseif SN > "VIRTCOMPASSIONTACMIT" then
											if SN == "VIRTCOMPASSIONVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSTacMitM",L);
										end
									else
										return CalcStat("VSArmourL",L);
									end
								elseif SN > "VIRTCONFIDENCECRITHIT" then
									if SN < "VIRTCONFIDENCEVPTACMAS" then
										if SN < "VIRTCONFIDENCEFINESSE" then
											if SN == "VIRTCONFIDENCEEVADE" then
												return CalcStat("VSEvadeL",L);
											else
												return 0;
											end
										elseif SN > "VIRTCONFIDENCEFINESSE" then
											if SN == "VIRTCONFIDENCEVPPHYMAS" then
												return CalcStat("VSVPPhyMas",L);
											else
												return 0;
											end
										else
											return CalcStat("VSFinesseM",L);
										end
									elseif SN > "VIRTCONFIDENCEVPTACMAS" then
										if SN < "VIRTDETERMINATIONCRITHIT" then
											if SN == "VIRTDETERMINATIONAGILITY" then
												return CalcStat("VSAgilityH",L);
											else
												return 0;
											end
										elseif SN > "VIRTDETERMINATIONCRITHIT" then
											if SN == "VIRTDETERMINATIONPHYMAS" then
												return CalcStat("VSPhyMasM",L);
											else
												return 0;
											end
										else
											return CalcStat("VSCritHitL",L);
										end
									else
										return CalcStat("VSVPTacMas",L);
									end
								else
									return CalcStat("VSCritHitH",L);
								end
							else
								return CalcStat("VSPhyMitM",L);
							end
						else
							if Lm <= 0 then
								return 0;
							else
								return DataTableValue({1,2,3,4,5},L);
							end
						end
					elseif SN > "VIRTDETERMINATIONVPPHYMAS" then
						if SN < "VIRTINNOCENCEPHYMIT" then
							if SN < "VIRTFORTITUDEMORALE" then
								if SN < "VIRTEMPATHYCRITDEF" then
									if SN < "VIRTDISCIPLINEPHYMIT" then
										if SN > "VIRTDETERMINATIONVPTACMAS" then
											if SN == "VIRTDISCIPLINEINHEAL" then
												return CalcStat("VSInHealM",L);
											else
												return 0;
											end
										elseif SN == "VIRTDETERMINATIONVPTACMAS" then
											return CalcStat("VSVPTacMas",L);
										else
											return 0;
										end
									elseif SN > "VIRTDISCIPLINEPHYMIT" then
										if SN < "VIRTDISCIPLINEVPMORALE" then
											if SN == "VIRTDISCIPLINERESIST" then
												return CalcStat("VSResistH",L);
											else
												return 0;
											end
										elseif SN > "VIRTDISCIPLINEVPMORALE" then
											if SN == "VIRTEMPATHYARMOUR" then
												return CalcStat("VSArmourH",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPMorale",L);
										end
									else
										return CalcStat("VSPhyMitL",L);
									end
								elseif SN > "VIRTEMPATHYCRITDEF" then
									if SN < "VIRTFIDELITYTACMIT" then
										if SN < "VIRTEMPATHYVPMORALE" then
											if SN == "VIRTEMPATHYRESIST" then
												return CalcStat("VSResistL",L);
											else
												return 0;
											end
										elseif SN > "VIRTEMPATHYVPMORALE" then
											if SN == "VIRTFIDELITYPHYMIT" then
												return CalcStat("VSPhyMitL",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPMorale",L);
										end
									elseif SN > "VIRTFIDELITYTACMIT" then
										if SN < "VIRTFIDELITYVPMORALE" then
											if SN == "VIRTFIDELITYVITALITY" then
												return CalcStat("VSVitalityM",L);
											else
												return 0;
											end
										elseif SN > "VIRTFIDELITYVPMORALE" then
											if SN == "VIRTFORTITUDECRITDEF" then
												return CalcStat("VSCritDefM",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPMorale",L);
										end
									else
										return CalcStat("VSTacMitH",L);
									end
								else
									return CalcStat("VSCritDefM",L);
								end
							elseif SN > "VIRTFORTITUDEMORALE" then
								if SN < "VIRTHONOURCRITDEF" then
									if SN < "VIRTHONESTYTACMAS" then
										if SN < "VIRTFORTITUDEVPMORALE" then
											if SN == "VIRTFORTITUDERESIST" then
												return CalcStat("VSResistL",L);
											else
												return 0;
											end
										elseif SN > "VIRTFORTITUDEVPMORALE" then
											if SN == "VIRTHONESTYCRITHIT" then
												return CalcStat("VSCritHitL",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPMorale",L);
										end
									elseif SN > "VIRTHONESTYTACMAS" then
										if SN < "VIRTHONESTYVPTACMAS" then
											if SN == "VIRTHONESTYVPPHYMAS" then
												return CalcStat("VSVPPhyMas",L);
											else
												return 0;
											end
										elseif SN > "VIRTHONESTYVPTACMAS" then
											if SN == "VIRTHONESTYWILL" then
												return CalcStat("VSWillM",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPTacMas",L);
										end
									else
										return CalcStat("VSTacMasH",L);
									end
								elseif SN > "VIRTHONOURCRITDEF" then
									if SN < "VIRTIDEALISMFATE" then
										if SN < "VIRTHONOURTACMIT" then
											if SN == "VIRTHONOURMORALE" then
												return CalcStat("VSMoraleH",L);
											else
												return 0;
											end
										elseif SN > "VIRTHONOURTACMIT" then
											if SN == "VIRTHONOURVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSTacMitM",L);
										end
									elseif SN > "VIRTIDEALISMFATE" then
										if SN < "VIRTIDEALISMMORALE" then
											if SN == "VIRTIDEALISMINHEAL" then
												return CalcStat("VSInHealM",L);
											else
												return 0;
											end
										elseif SN > "VIRTIDEALISMMORALE" then
											if SN == "VIRTIDEALISMVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSMoraleL",L);
										end
									else
										return CalcStat("VSFateH",L);
									end
								else
									return CalcStat("VSCritDefL",L);
								end
							else
								return CalcStat("VSMoraleH",L);
							end
						elseif SN > "VIRTINNOCENCEPHYMIT" then
							if SN < "VIRTPATIENCECRITHIT" then
								if SN < "VIRTLOYALTYARMOUR" then
									if SN < "VIRTJUSTICEICMR" then
										if SN < "VIRTINNOCENCETACMIT" then
											if SN == "VIRTINNOCENCERESIST" then
												return CalcStat("VSResistM",L);
											else
												return 0;
											end
										elseif SN > "VIRTINNOCENCETACMIT" then
											if SN == "VIRTINNOCENCEVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSTacMitL",L);
										end
									elseif SN > "VIRTJUSTICEICMR" then
										if SN < "VIRTJUSTICETACMIT" then
											if SN == "VIRTJUSTICEMORALE" then
												return CalcStat("VSMoraleM",L);
											else
												return 0;
											end
										elseif SN > "VIRTJUSTICETACMIT" then
											if SN == "VIRTJUSTICEVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSTacMitL",L);
										end
									else
										return CalcStat("VSICMRH",L);
									end
								elseif SN > "VIRTLOYALTYARMOUR" then
									if SN < "VIRTMERCYEVADE" then
										if SN < "VIRTLOYALTYVITALITY" then
											if SN == "VIRTLOYALTYINHEAL" then
												return CalcStat("VSInHealL",L);
											else
												return 0;
											end
										elseif SN > "VIRTLOYALTYVITALITY" then
											if SN == "VIRTLOYALTYVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVitalityH",L);
										end
									elseif SN > "VIRTMERCYEVADE" then
										if SN < "VIRTMERCYVITALITY" then
											if SN == "VIRTMERCYFATE" then
												return CalcStat("VSFateM",L);
											else
												return 0;
											end
										elseif SN > "VIRTMERCYVITALITY" then
											if SN == "VIRTMERCYVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVitalityL",L);
										end
									else
										return CalcStat("VSEvadeH",L);
									end
								else
									return CalcStat("VSArmourM",L);
								end
							elseif SN > "VIRTPATIENCECRITHIT" then
								if SN < "VIRTTOLERANCETACMIT" then
									if SN < "VIRTRNKCOST" then
										if SN < "VIRTPATIENCEPOWER" then
											if SN == "VIRTPATIENCEEVADE" then
												return CalcStat("VSEvadeM",L);
											else
												return 0;
											end
										elseif SN > "VIRTPATIENCEPOWER" then
											if SN == "VIRTPATIENCEVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("VSPowerH",L);
										end
									elseif SN > "VIRTRNKCOST" then
										if SN < "VIRTTOLERANCEPHYMIT" then
											if SN == "VIRTRNKCOSTTOT" then
												if Lm <= 0 then
													return 0;
												else
													return CalcStat("VirtRnkCostTot",L-1)+CalcStat("VirtRnkCost",L);
												end
											else
												return 0;
											end
										elseif SN > "VIRTTOLERANCEPHYMIT" then
											if SN == "VIRTTOLERANCERESIST" then
												return CalcStat("VSResistM",L);
											else
												return 0;
											end
										else
											return CalcStat("VSPhyMitL",L);
										end
									else
										if Lm <= 0 then
											return 0;
										elseif Lm <= 10 then
											return 1000;
										elseif Lm <= 60 then
											return RoundDbl(18*L+878,-2);
										elseif Lm <= 73 then
											return RoundDbl(18.75*L+878,-2);
										elseif Lm <= 90 then
											return RoundDbl(17.45*L+878,-2);
										else
											return 2500;
										end
									end
								elseif SN > "VIRTTOLERANCETACMIT" then
									if SN < "VIRTVALOURPHYMAS" then
										if SN < "VIRTVALOURCRITHIT" then
											if SN == "VIRTTOLERANCEVPMORALE" then
												return CalcStat("VSVPMorale",L);
											else
												return 0;
											end
										elseif SN > "VIRTVALOURCRITHIT" then
											if SN == "VIRTVALOURFINESSE" then
												return CalcStat("VSFinesseM",L);
											else
												return 0;
											end
										else
											return CalcStat("VSCritHitL",L);
										end
									elseif SN > "VIRTVALOURPHYMAS" then
										if SN < "VIRTVALOURVPTACMAS" then
											if SN == "VIRTVALOURVPPHYMAS" then
												return CalcStat("VSVPPhyMas",L);
											else
												return 0;
											end
										elseif SN > "VIRTVALOURVPTACMAS" then
											if SN == "VIRTWISDOMFINESSE" then
												return CalcStat("VSFinesseL",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPTacMas",L);
										end
									else
										return CalcStat("VSPhyMasH",L);
									end
								else
									return CalcStat("VSTacMitH",L);
								end
							else
								return CalcStat("VSCritHitL",L);
							end
						else
							return CalcStat("VSPhyMitH",L);
						end
					else
						return CalcStat("VSVPPhyMas",L);
					end
				elseif SN > "VIRTWISDOMTACMAS" then
					if SN < "VSMORALEH" then
						if SN < "VRNKLVLCAP" then
							if SN < "VITALITY" then
								if SN < "VIRTWITTACMAS" then
									if SN < "VIRTWISDOMWILL" then
										if SN > "VIRTWISDOMVPPHYMAS" then
											if SN == "VIRTWISDOMVPTACMAS" then
												return CalcStat("VSVPTacMas",L);
											else
												return 0;
											end
										elseif SN == "VIRTWISDOMVPPHYMAS" then
											return CalcStat("VSVPPhyMas",L);
										else
											return 0;
										end
									elseif SN > "VIRTWISDOMWILL" then
										if SN < "VIRTWITFINESSE" then
											if SN == "VIRTWITCRITHIT" then
												return CalcStat("VSCritHitM",L);
											else
												return 0;
											end
										elseif SN > "VIRTWITFINESSE" then
											if SN == "VIRTWITPHYMAS" then
												return CalcStat("VSPhyMasL",L);
											else
												return 0;
											end
										else
											return CalcStat("VSFinesseH",L);
										end
									else
										return CalcStat("VSWillH",L);
									end
								elseif SN > "VIRTWITTACMAS" then
									if SN < "VIRTZEALMIGHT" then
										if SN < "VIRTWITVPTACMAS" then
											if SN == "VIRTWITVPPHYMAS" then
												return CalcStat("VSVPPhyMas",L);
											else
												return 0;
											end
										elseif SN > "VIRTWITVPTACMAS" then
											if SN == "VIRTZEALCRITHIT" then
												return CalcStat("VSCritHitL",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPTacMas",L);
										end
									elseif SN > "VIRTZEALMIGHT" then
										if SN < "VIRTZEALVPPHYMAS" then
											if SN == "VIRTZEALPHYMAS" then
												return CalcStat("VSPhyMasM",L);
											else
												return 0;
											end
										elseif SN > "VIRTZEALVPPHYMAS" then
											if SN == "VIRTZEALVPTACMAS" then
												return CalcStat("VSVPTacMas",L);
											else
												return 0;
											end
										else
											return CalcStat("VSVPPhyMas",L);
										end
									else
										return CalcStat("VSMightH",L);
									end
								else
									return CalcStat("VSTacMasL",L);
								end
							elseif SN > "VITALITY" then
								if SN < "VMHIGH" then
									if SN < "VITALITYTADJ" then
										if SN < "VITALITYC" then
											if SN == "VITALITYADJ" then
												if Lm <= 25 then
													return 0.5;
												elseif Lm <= 50 then
													return 0.6;
												elseif Lm <= 60 then
													return 0.7;
												elseif Lm <= 79 then
													return 0.8;
												elseif Lm <= 80 then
													return 0.9;
												else
													return 1;
												end
											else
												return 0;
											end
										elseif SN > "VITALITYC" then
											if SN == "VITALITYT" then
												return RoundDblDown(StatLinInter("PntMPVitalityT","TraitPntSVital","ProgBVitality","VitalityTAdj",L,N,0));
											else
												return 0;
											end
										else
											return RoundDblDown(StatLinInter("PntMPVitalityC","CreepPntS","ProgBVitalityC","",L,N,0));
										end
									elseif SN > "VITALITYTADJ" then
										if SN < "VMASTERYADJ" then
											if SN == "VMASTERY" then
												return StatLinInter("PntMPMastery","ItemPntSVirtueMastery","ProgBMastery","VMasteryAdj",L,N,0);
											else
												return 0;
											end
										elseif SN > "VMASTERYADJ" then
											if SN == "VMASTERYOLD" then
												return CalcStat("VMastery",L,N);
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return CalcStat("MasteryAdj",L);
											end
										end
									else
										if Lm <= 25 then
											return 0.5;
										elseif Lm <= 50 then
											return 0.6;
										elseif Lm <= 60 then
											return 0.7;
										elseif Lm <= 65 then
											return 0.8;
										elseif Lm <= 75 then
											return 0.9;
										else
											return 1;
										end
									end
								elseif SN > "VMHIGH" then
									if SN < "VMMORALEPSV" then
										if SN < "VMMASTERYPSV" then
											if SN == "VMLOW" then
												if Lm <= 0 then
													return 0;
												else
													return CalcStat(C,CalcStat("VRnkToILvl",L),0.6);
												end
											else
												return 0;
											end
										elseif SN > "VMMASTERYPSV" then
											if SN == "VMMEDIUM" then
												if Lm <= 0 then
													return 0;
												else
													return CalcStat(C,CalcStat("VRnkToILvl",L),1.0);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return CalcStat("VMastery",CalcStat("VRnkToILvl",L),0.2);
											end
										end
									elseif SN > "VMMORALEPSV" then
										if SN < "VMORALEADJ" then
											if SN == "VMORALE" then
												return StatLinInter("PntMPMoraleVirtues","ItemPntSVirtueMorale","ProgBMorale","VMoraleAdj",L,N,0);
											else
												return 0;
											end
										elseif SN > "VMORALEADJ" then
											if SN == "VRNKCAP" then
												return 90;
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											elseif Lm <= 2 then
												return 1;
											elseif Lm <= 50 then
												return 2;
											elseif Lm <= 80 then
												return 1.5;
											elseif Lm <= 450 then
												return 1;
											elseif Lm <= 499 then
												return 0.9475;
											else
												return 1;
											end
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return CalcStat("VMorale",CalcStat("VRnkToILvl",L),0.3);
										end
									end
								else
									if Lm <= 0 then
										return 0;
									else
										return CalcStat(C,CalcStat("VRnkToILvl",L),2.0);
									end
								end
							else
								return RoundDblDown(StatLinInter("PntMPVitality","ItemPntSVital","ProgBVitality","VitalityAdj",L,N,0));
							end
						elseif SN > "VRNKLVLCAP" then
							if SN < "VSEVADEM" then
								if SN < "VSCRITDEFH" then
									if SN < "VSAGILITYM" then
										if SN < "VSAGILITYH" then
											if SN == "VRNKTOILVL" then
												if Lm <= 0 then
													return 0;
												elseif Lm <= 38 then
													return LinFmod(1,4,78,1,38,L);
												elseif Lm <= 48 then
													return LinFmod(1,78,178,38,48,L);
												elseif Lm <= 49 then
													return LinFmod(1,178,190,48,49,L);
												elseif Lm <= 50 then
													return LinFmod(1,190,210,49,50,L);
												elseif Lm <= 51 then
													return LinFmod(1,210,222,50,51,L);
												elseif Lm <= 52 then
													return LinFmod(1,222,236,51,52,L);
												elseif Lm <= 53 then
													return LinFmod(1,236,260,52,53,L);
												elseif Lm <= 55 then
													return LinFmod(1,260,292,53,55,L);
												elseif Lm <= 68 then
													return LinFmod(1,292,396,55,68,L);
												else
													return LinFmod(1,396,706,68,130,L);
												end
											else
												return 0;
											end
										elseif SN > "VSAGILITYH" then
											if SN == "VSAGILITYL" then
												return CalcStat("VMLow",L,"Agility");
											else
												return 0;
											end
										else
											return CalcStat("VMHigh",L,"Agility");
										end
									elseif SN > "VSAGILITYM" then
										if SN < "VSARMOURL" then
											if SN == "VSARMOURH" then
												return CalcStat("VMHigh",L,"Varmour");
											else
												return 0;
											end
										elseif SN > "VSARMOURL" then
											if SN == "VSARMOURM" then
												return CalcStat("VMMedium",L,"Varmour");
											else
												return 0;
											end
										else
											return CalcStat("VMLow",L,"Varmour");
										end
									else
										return CalcStat("VMMedium",L,"Agility");
									end
								elseif SN > "VSCRITDEFH" then
									if SN < "VSCRITHITL" then
										if SN < "VSCRITDEFM" then
											if SN == "VSCRITDEFL" then
												return CalcStat("VMLow",L,"CritDef");
											else
												return 0;
											end
										elseif SN > "VSCRITDEFM" then
											if SN == "VSCRITHITH" then
												return CalcStat("VMHigh",L,"CritHit");
											else
												return 0;
											end
										else
											return CalcStat("VMMedium",L,"CritDef");
										end
									elseif SN > "VSCRITHITL" then
										if SN < "VSEVADEH" then
											if SN == "VSCRITHITM" then
												return CalcStat("VMMedium",L,"CritHit");
											else
												return 0;
											end
										elseif SN > "VSEVADEH" then
											if SN == "VSEVADEL" then
												return CalcStat("VMLow",L,"Evade");
											else
												return 0;
											end
										else
											return CalcStat("VMHigh",L,"Evade");
										end
									else
										return CalcStat("VMLow",L,"CritHit");
									end
								else
									return CalcStat("VMHigh",L,"CritDef");
								end
							elseif SN > "VSEVADEM" then
								if SN < "VSICMRL" then
									if SN < "VSFINESSEH" then
										if SN < "VSFATEL" then
											if SN == "VSFATEH" then
												return CalcStat("VMHigh",L,"Fate");
											else
												return 0;
											end
										elseif SN > "VSFATEL" then
											if SN == "VSFATEM" then
												return CalcStat("VMMedium",L,"Fate");
											else
												return 0;
											end
										else
											return CalcStat("VMLow",L,"Fate");
										end
									elseif SN > "VSFINESSEH" then
										if SN < "VSFINESSEM" then
											if SN == "VSFINESSEL" then
												return CalcStat("VMLow",L,"Finesse");
											else
												return 0;
											end
										elseif SN > "VSFINESSEM" then
											if SN == "VSICMRH" then
												return CalcStat("VMHigh",L,"ICMR");
											else
												return 0;
											end
										else
											return CalcStat("VMMedium",L,"Finesse");
										end
									else
										return CalcStat("VMHigh",L,"Finesse");
									end
								elseif SN > "VSICMRL" then
									if SN < "VSINHEALM" then
										if SN < "VSINHEALH" then
											if SN == "VSICMRM" then
												return CalcStat("VMMedium",L,"ICMR");
											else
												return 0;
											end
										elseif SN > "VSINHEALH" then
											if SN == "VSINHEALL" then
												return CalcStat("VMLow",L,"InHeal");
											else
												return 0;
											end
										else
											return CalcStat("VMHigh",L,"InHeal");
										end
									elseif SN > "VSINHEALM" then
										if SN < "VSMIGHTL" then
											if SN == "VSMIGHTH" then
												return CalcStat("VMHigh",L,"Might");
											else
												return 0;
											end
										elseif SN > "VSMIGHTL" then
											if SN == "VSMIGHTM" then
												return CalcStat("VMMedium",L,"Might");
											else
												return 0;
											end
										else
											return CalcStat("VMLow",L,"Might");
										end
									else
										return CalcStat("VMMedium",L,"InHeal");
									end
								else
									return CalcStat("VMLow",L,"ICMR");
								end
							else
								return CalcStat("VMMedium",L,"Evade");
							end
						else
							if Lm <= 4 then
								return 2;
							elseif Lm <= 110 then
								return RoundDblDown(L/2);
							elseif Lm <= 139 then
								return L-55;
							elseif Lm <= 140 then
								return L-54;
							elseif Lm <= 149 then
								return L-53;
							else
								return 98;
							end
						end
					elseif SN > "VSMORALEH" then
						if SN < "WARDENCDAGILITYTOCRITHIT" then
							if SN < "VSTACMASH" then
								if SN < "VSPHYMITL" then
									if SN < "VSPHYMASH" then
										if SN > "VSMORALEL" then
											if SN == "VSMORALEM" then
												return CalcStat("VMMedium",L,"VMorale");
											else
												return 0;
											end
										elseif SN == "VSMORALEL" then
											return CalcStat("VMLow",L,"VMorale");
										else
											return 0;
										end
									elseif SN > "VSPHYMASH" then
										if SN < "VSPHYMASM" then
											if SN == "VSPHYMASL" then
												return CalcStat("VMLow",L,"PhyMas");
											else
												return 0;
											end
										elseif SN > "VSPHYMASM" then
											if SN == "VSPHYMITH" then
												return CalcStat("VMHigh",L,"PhyMit");
											else
												return 0;
											end
										else
											return CalcStat("VMMedium",L,"PhyMas");
										end
									else
										return CalcStat("VMHigh",L,"PhyMas");
									end
								elseif SN > "VSPHYMITL" then
									if SN < "VSPOWERM" then
										if SN < "VSPOWERH" then
											if SN == "VSPHYMITM" then
												return CalcStat("VMMedium",L,"PhyMit");
											else
												return 0;
											end
										elseif SN > "VSPOWERH" then
											if SN == "VSPOWERL" then
												return CalcStat("VMLow",L,"Power");
											else
												return 0;
											end
										else
											return CalcStat("VMHigh",L,"Power");
										end
									elseif SN > "VSPOWERM" then
										if SN < "VSRESISTL" then
											if SN == "VSRESISTH" then
												return CalcStat("VMHigh",L,"Resist");
											else
												return 0;
											end
										elseif SN > "VSRESISTL" then
											if SN == "VSRESISTM" then
												return CalcStat("VMMedium",L,"Resist");
											else
												return 0;
											end
										else
											return CalcStat("VMLow",L,"Resist");
										end
									else
										return CalcStat("VMMedium",L,"Power");
									end
								else
									return CalcStat("VMLow",L,"PhyMit");
								end
							elseif SN > "VSTACMASH" then
								if SN < "VSVITALITYM" then
									if SN < "VSTACMITL" then
										if SN < "VSTACMASM" then
											if SN == "VSTACMASL" then
												return CalcStat("VMLow",L,"TacMas");
											else
												return 0;
											end
										elseif SN > "VSTACMASM" then
											if SN == "VSTACMITH" then
												return CalcStat("VMHigh",L,"TacMit");
											else
												return 0;
											end
										else
											return CalcStat("VMMedium",L,"TacMas");
										end
									elseif SN > "VSTACMITL" then
										if SN < "VSVITALITYH" then
											if SN == "VSTACMITM" then
												return CalcStat("VMMedium",L,"TacMit");
											else
												return 0;
											end
										elseif SN > "VSVITALITYH" then
											if SN == "VSVITALITYL" then
												return CalcStat("VMLow",L,"Vitality");
											else
												return 0;
											end
										else
											return CalcStat("VMHigh",L,"Vitality");
										end
									else
										return CalcStat("VMLow",L,"TacMit");
									end
								elseif SN > "VSVITALITYM" then
									if SN < "VSWILLH" then
										if SN < "VSVPPHYMAS" then
											if SN == "VSVPMORALE" then
												return CalcStat("VMMoralePsv",L);
											else
												return 0;
											end
										elseif SN > "VSVPPHYMAS" then
											if SN == "VSVPTACMAS" then
												return CalcStat("VMMasteryPsv",L);
											else
												return 0;
											end
										else
											return CalcStat("VMMasteryPsv",L);
										end
									elseif SN > "VSWILLH" then
										if SN < "VSWILLM" then
											if SN == "VSWILLL" then
												return CalcStat("VMLow",L,"Will");
											else
												return 0;
											end
										elseif SN > "VSWILLM" then
											if SN == "WARDENCDAGILITYTOBLOCK" then
												return 2;
											else
												return 0;
											end
										else
											return CalcStat("VMMedium",L,"Will");
										end
									else
										return CalcStat("VMHigh",L,"Will");
									end
								else
									return CalcStat("VMMedium",L,"Vitality");
								end
							else
								return CalcStat("VMHigh",L,"TacMas");
							end
						elseif SN > "WARDENCDAGILITYTOCRITHIT" then
							if SN < "WARDENCDBASENCMR" then
								if SN < "WARDENCDARMOURTOTACMIT" then
									if SN < "WARDENCDAGILITYTOPHYMIT" then
										if SN < "WARDENCDAGILITYTOPARRY" then
											if SN == "WARDENCDAGILITYTOOUTHEAL" then
												return 3;
											else
												return 0;
											end
										elseif SN > "WARDENCDAGILITYTOPARRY" then
											if SN == "WARDENCDAGILITYTOPHYMAS" then
												return 3;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "WARDENCDAGILITYTOPHYMIT" then
										if SN < "WARDENCDARMOURTOCOMPHYMIT" then
											if SN == "WARDENCDAGILITYTOTACMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN > "WARDENCDARMOURTOCOMPHYMIT" then
											if SN == "WARDENCDARMOURTONONPHYMIT" then
												return 0.2;
											else
												return 0;
											end
										else
											return 1;
										end
									else
										return 1;
									end
								elseif SN > "WARDENCDARMOURTOTACMIT" then
									if SN < "WARDENCDBASEICMR" then
										if SN < "WARDENCDBASEAGILITY" then
											if SN == "WARDENCDARMOURTYPE" then
												return 2;
											else
												return 0;
											end
										elseif SN > "WARDENCDBASEAGILITY" then
											if SN == "WARDENCDBASEFATE" then
												return CalcStat("ClassBaseFate",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseAgilityH",L);
										end
									elseif SN > "WARDENCDBASEICMR" then
										if SN < "WARDENCDBASEMIGHT" then
											if SN == "WARDENCDBASEICPR" then
												return CalcStat("ClassBaseICPR",L);
											else
												return 0;
											end
										elseif SN > "WARDENCDBASEMIGHT" then
											if SN == "WARDENCDBASEMORALE" then
												return CalcStat("ClassBaseMorale",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBaseMightM",L);
										end
									else
										return CalcStat("ClassBaseICMRH",L);
									end
								else
									return 0.2;
								end
							elseif SN > "WARDENCDBASENCMR" then
								if SN < "WARDENCDCANBLOCK" then
									if SN < "WARDENCDBASEWILL" then
										if SN < "WARDENCDBASEPOWER" then
											if SN == "WARDENCDBASENCPR" then
												return CalcStat("ClassBaseNCPR",L);
											else
												return 0;
											end
										elseif SN > "WARDENCDBASEPOWER" then
											if SN == "WARDENCDBASEVITALITY" then
												return CalcStat("ClassBaseVitality",L);
											else
												return 0;
											end
										else
											return CalcStat("ClassBasePower",L);
										end
									elseif SN > "WARDENCDBASEWILL" then
										if SN < "WARDENCDCALCTYPENONPHYMIT" then
											if SN == "WARDENCDCALCTYPECOMPHYMIT" then
												return 13;
											else
												return 0;
											end
										elseif SN > "WARDENCDCALCTYPENONPHYMIT" then
											if SN == "WARDENCDCALCTYPETACMIT" then
												return 26;
											else
												return 0;
											end
										else
											return 13;
										end
									else
										return CalcStat("ClassBaseWillL",L);
									end
								elseif SN > "WARDENCDCANBLOCK" then
									if SN < "WARDENCDMIGHTTOBLOCK" then
										if SN < "WARDENCDFATETOPOWER" then
											if SN == "WARDENCDFATETONCPR" then
												return 0.07;
											else
												return 0;
											end
										elseif SN > "WARDENCDFATETOPOWER" then
											if SN == "WARDENCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "WARDENCDMIGHTTOBLOCK" then
										if SN < "WARDENCDMIGHTTOFINESSE" then
											if SN == "WARDENCDMIGHTTOCRITHIT" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "WARDENCDMIGHTTOFINESSE" then
											if SN == "WARDENCDMIGHTTOOUTHEAL" then
												return 2;
											else
												return 0;
											end
										else
											return 1.5;
										end
									else
										return 1;
									end
								else
									return 1;
								end
							else
								return CalcStat("ClassBaseNCMRH",L);
							end
						else
							return 1;
						end
					else
						return CalcStat("VMHigh",L,"VMorale");
					end
				else
					return CalcStat("VSTacMasM",L);
				end
			elseif SN > "WARDENCDMIGHTTOPHYMAS" then
				if SN < "WORTHTABM" then
					if SN < "WORTHTABAT" then
						if SN < "WORTHMPA" then
							if SN < "WARLEADERCANBLOCK" then
								if SN < "WARDENCDWILLTOFINESSE" then
									if SN < "WARDENCDTACMASTOOUTHEAL" then
										if SN > "WARDENCDPHYMITTOCOMPHYMIT" then
											if SN == "WARDENCDPHYMITTONONPHYMIT" then
												return 1;
											else
												return 0;
											end
										elseif SN == "WARDENCDPHYMITTOCOMPHYMIT" then
											return 1;
										else
											return 0;
										end
									elseif SN > "WARDENCDTACMASTOOUTHEAL" then
										if SN < "WARDENCDVITALITYTOMORALE" then
											if SN == "WARDENCDVITALITYTOICMR" then
												return 0.012;
											else
												return 0;
											end
										elseif SN > "WARDENCDVITALITYTOMORALE" then
											if SN == "WARDENCDVITALITYTONCMR" then
												return 0.12;
											else
												return 0;
											end
										else
											return 4.5;
										end
									else
										return 1;
									end
								elseif SN > "WARDENCDWILLTOFINESSE" then
									if SN < "WARDENCDWILLTORESIST" then
										if SN < "WARDENCDWILLTOPHYMAS" then
											if SN == "WARDENCDWILLTOOUTHEAL" then
												return 1;
											else
												return 0;
											end
										elseif SN > "WARDENCDWILLTOPHYMAS" then
											if SN == "WARDENCDWILLTOPHYMIT" then
												return 1.5;
											else
												return 0;
											end
										else
											return 1;
										end
									elseif SN > "WARDENCDWILLTORESIST" then
										if SN < "WARDINGLOREPHYMIT" then
											if SN == "WARDENCDWILLTOTACMIT" then
												return 1.5;
											else
												return 0;
											end
										elseif SN > "WARDINGLOREPHYMIT" then
											if SN == "WARDINGLORETACMIT" then
												if Lm <= 105 then
													return CalcStat("Mitigation",L,1.6);
												elseif Lm <= 119 then
													return CalcStat("TacMitT",L,1.2);
												elseif Lm <= 120 then
													return CalcStat("TacMitT",L,1.6);
												elseif Lm <= 129 then
													return CalcStat("TacMitT",L,1.2);
												elseif Lm <= 130 then
													return CalcStat("TacMitT",L,1.6);
												elseif Lm <= 139 then
													return CalcStat("TacMitT",L,1.2);
												else
													return CalcStat("TacMitT",L,1.6);
												end
											else
												return 0;
											end
										else
											if Lm <= 105 then
												return CalcStat("Mitigation",L,1.6);
											elseif Lm <= 119 then
												return CalcStat("PhyMitT",L,1.2);
											elseif Lm <= 120 then
												return CalcStat("PhyMitT",L,1.6);
											elseif Lm <= 129 then
												return CalcStat("PhyMitT",L,1.2);
											elseif Lm <= 130 then
												return CalcStat("PhyMitT",L,1.6);
											elseif Lm <= 139 then
												return CalcStat("PhyMitT",L,1.2);
											else
												return CalcStat("PhyMitT",L,1.6);
											end
										end
									else
										return 1;
									end
								else
									return 1;
								end
							elseif SN > "WARLEADERCANBLOCK" then
								if SN < "WEAVERCDCALCTYPETACMIT" then
									if SN < "WARLEADERCDHASPOWER" then
										if SN < "WARLEADERCDCALCTYPENONPHYMIT" then
											if SN == "WARLEADERCDCALCTYPECOMPHYMIT" then
												return 14;
											else
												return 0;
											end
										elseif SN > "WARLEADERCDCALCTYPENONPHYMIT" then
											if SN == "WARLEADERCDCALCTYPETACMIT" then
												return 27;
											else
												return 0;
											end
										else
											return 14;
										end
									elseif SN > "WARLEADERCDHASPOWER" then
										if SN < "WEAVERCDCALCTYPECOMPHYMIT" then
											if SN == "WEAVERCANBLOCK" then
												return 1;
											else
												return 0;
											end
										elseif SN > "WEAVERCDCALCTYPECOMPHYMIT" then
											if SN == "WEAVERCDCALCTYPENONPHYMIT" then
												return 14;
											else
												return 0;
											end
										else
											return 13;
										end
									else
										return 1;
									end
								elseif SN > "WEAVERCDCALCTYPETACMIT" then
									if SN < "WILLT" then
										if SN < "WILL" then
											if SN == "WEAVERCDHASPOWER" then
												return 1;
											else
												return 0;
											end
										elseif SN > "WILL" then
											if SN == "WILLC" then
												return CalcStat("MainC",L,N);
											else
												return 0;
											end
										else
											return CalcStat("Main",L,N);
										end
									elseif SN > "WILLT" then
										if SN < "WORTHEXT4LIN" then
											if SN == "WORTHEXT" then
												if Lm <= 360 then
													return RoundDbl(CalcStat("StatC",L,C));
												elseif Lm <= 601 then
													return RoundDbl(CalcStat("StatC",L-1,C));
												else
													return 0;
												end
											else
												return 0;
											end
										elseif SN > "WORTHEXT4LIN" then
											if SN == "WORTHEXT8LIN" then
												if Lm <= 501 then
													return CalcStat("WorthExt",L,C);
												elseif Lm <= 601 then
													return CalcStat("WorthExt",501,C)+(L-501)*8;
												else
													return 0;
												end
											else
												return 0;
											end
										else
											if Lm <= 501 then
												return CalcStat("WorthExt",L,C);
											elseif Lm <= 601 then
												return CalcStat("WorthExt",501,C)+(L-501)*4;
											else
												return 0;
											end
										end
									else
										return CalcStat("MainT",L,N);
									end
								else
									return 27;
								end
							else
								return 1;
							end
						elseif SN > "WORTHMPA" then
							if SN < "WORTHTABAE" then
								if SN < "WORTHMPI" then
									if SN < "WORTHMPE" then
										if SN < "WORTHMPC" then
											if SN == "WORTHMPB" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,1.2,2,3,4},L);
												end
											else
												return 0;
											end
										elseif SN > "WORTHMPC" then
											if SN == "WORTHMPD" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,1,1,2,3},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return 1;
											end
										end
									elseif SN > "WORTHMPE" then
										if SN < "WORTHMPG" then
											if SN == "WORTHMPF" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({0.5,1,1.25,1.5,2},L);
												end
											else
												return 0;
											end
										elseif SN > "WORTHMPG" then
											if SN == "WORTHMPH" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,1.2,1.8,3.2,5},L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({1,2,3,4,5},L);
											end
										end
									else
										if Lm <= 0 then
											return 0;
										else
											return DataTableValue({1,1.1,1.15,1.2,1.25},L);
										end
									end
								elseif SN > "WORTHMPI" then
									if SN < "WORTHTABAA" then
										if SN < "WORTHMPK" then
											if SN == "WORTHMPJ" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({1,1,1,1,5},L);
												end
											else
												return 0;
											end
										elseif SN > "WORTHMPK" then
											if SN == "WORTHTABA" then
												if Lm <= 1 then
													return 1;
												else
													return CalcStat("WorthTabAF",L);
												end
											else
												return 0;
											end
										else
											if Lm <= 0 then
												return 0;
											else
												return DataTableValue({1,1.2,1.3,1.35,1.4},L);
											end
										end
									elseif SN > "WORTHTABAA" then
										if SN < "WORTHTABAC" then
											if SN == "WORTHTABAB" then
												return 7*L+50;
											else
												return 0;
											end
										elseif SN > "WORTHTABAC" then
											if SN == "WORTHTABAD" then
												return 7*L+100;
											else
												return 0;
											end
										else
											return CalcStat("WorthTabE",L)-30;
										end
									else
										return CalcStat("WorthTabD",L)+20;
									end
								else
									if Lm <= 0 then
										return 0;
									else
										return DataTableValue({1,2,2.5,3,10},L);
									end
								end
							elseif SN > "WORTHTABAE" then
								if SN < "WORTHTABALBASE" then
									if SN < "WORTHTABAI" then
										if SN < "WORTHTABAG" then
											if SN == "WORTHTABAF" then
												if Lm <= 49 then
													return 2.5*L;
												else
													return 3*L-25;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABAG" then
											if SN == "WORTHTABAH" then
												if Lm <= 49 then
													return CalcStat("WorthTabALBase",L+7)-66;
												else
													return 9*L+72;
												end
											else
												return 0;
											end
										else
											return CalcStat("WorthTabAF",L)+25;
										end
									elseif SN > "WORTHTABAI" then
										if SN < "WORTHTABAK" then
											if SN == "WORTHTABAJ" then
												return CalcStat("WorthTabAH",L);
											else
												return 0;
											end
										elseif SN > "WORTHTABAK" then
											if SN == "WORTHTABAL" then
												if Lm <= 49 then
													return CalcStat("WorthTabALBase",L);
												else
													return 9*L+69;
												end
											else
												return 0;
											end
										else
											if Lm <= 49 then
												return CalcStat("WorthTabALBase",L+1);
											else
												return 9*L+78;
											end
										end
									else
										if Lm <= 16 then
											return 10.73*L+54.3;
										elseif Lm <= 34 then
											return 10.735*L+54;
										elseif Lm <= 35 then
											return 429;
										elseif Lm <= 41 then
											return 10.65*L+57.1;
										elseif Lm <= 49 then
											return 10.7*L+55.3;
										else
											return 9*L+141;
										end
									end
								elseif SN > "WORTHTABALBASE" then
									if SN < "WORTHTABAP" then
										if SN < "WORTHTABAN" then
											if SN == "WORTHTABAM" then
												return CalcStat("WorthTabB",L);
											else
												return 0;
											end
										elseif SN > "WORTHTABAN" then
											if SN == "WORTHTABAO" then
												return CalcStat("WorthTabE",L);
											else
												return 0;
											end
										else
											if Lm <= 50 then
												return 8.25*L+27.75;
											else
												return 8*L+40;
											end
										end
									elseif SN > "WORTHTABAP" then
										if SN < "WORTHTABAR" then
											if SN == "WORTHTABAQ" then
												if Lm <= 10 then
													return 7.5*L+60;
												elseif Lm <= 49 then
													return 5.5*L+80;
												else
													return 6*L+55;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABAR" then
											if SN == "WORTHTABAS" then
												return CalcStat("WorthTabU",L);
											else
												return 0;
											end
										else
											return CalcStat("WorthTabD",L)+37.5;
										end
									else
										return CalcStat("WorthTabAQ",L);
									end
								else
									return 9.86*L+23.51+RoundDbl(L*0.1+0.3)*0.4;
								end
							else
								return CalcStat("WorthTabE",L);
							end
						else
							if Lm <= 0 then
								return 0;
							else
								return DataTableValue({1,1.1,1.15,1.2,1.3},L);
							end
						end
					elseif SN > "WORTHTABAT" then
						if SN < "WORTHTABBW" then
							if SN < "WORTHTABBG" then
								if SN < "WORTHTABAZBASE" then
									if SN < "WORTHTABAW" then
										if SN > "WORTHTABAU" then
											if SN == "WORTHTABAV" then
												if Lm <= 4 then
													return RoundDbl(3*L+20,-1);
												elseif Lm <= 7 then
													return 70;
												elseif Lm <= 10 then
													return 140;
												elseif Lm <= 13 then
													return 270;
												elseif Lm <= 16 then
													return 400;
												elseif Lm <= 19 then
													return 460;
												elseif Lm <= 25 then
													return RoundDbl(3*L+447.5,-1);
												elseif Lm <= 46 then
													return RoundDbl(3.2*L+455,-1);
												elseif Lm <= 50 then
													return 620;
												else
													return 20*L-360;
												end
											else
												return 0;
											end
										elseif SN == "WORTHTABAU" then
											return CalcStat("WorthTabBN",L)*1.25;
										else
											return 0;
										end
									elseif SN > "WORTHTABAW" then
										if SN < "WORTHTABAY" then
											if SN == "WORTHTABAX" then
												if Lm <= 16 then
													return 10.75*L+54;
												elseif Lm <= 34 then
													return 10.75*L+53.7;
												elseif Lm <= 35 then
													return 429;
												elseif Lm <= 41 then
													return 10.65*L+57.1;
												elseif Lm <= 49 then
													return 10.68*L+56.25;
												else
													return 12*L-9;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABAY" then
											if SN == "WORTHTABAZ" then
												if Lm <= 10 then
													return CalcStat("WorthTabAZBase",L)*62.5;
												elseif Lm <= 65 then
													return CalcStat("WorthTabAZBase",L)*125;
												else
													return CalcStat("WorthTabAZBase",L)*25;
												end
											else
												return 0;
											end
										else
											return 5*L;
										end
									else
										if Lm <= 1 then
											return 50;
										elseif Lm <= 49 then
											return 2.5*L+102.5;
										elseif Lm <= 80 then
											return 3*L+78;
										elseif Lm <= 120 then
											return 2.97*L+79.5;
										else
											return 3*L+75;
										end
									end
								elseif SN > "WORTHTABAZBASE" then
									if SN < "WORTHTABBC" then
										if SN < "WORTHTABBA" then
											if SN == "WORTHTABB" then
												if Lm <= 50 then
													return 8.25*L+22.25;
												else
													return 8*L+35;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABBA" then
											if SN == "WORTHTABBB" then
												if Lm <= 1 then
													return 40;
												elseif Lm <= 10 then
													return RoundDbl(0.35*L-0.1)*20;
												elseif Lm <= 13 then
													return 100;
												elseif Lm <= 19 then
													return RoundDbl(0.35*L+1.6)*20;
												elseif Lm <= 25 then
													return RoundDbl(2*L+150,-1);
												elseif Lm <= 40 then
													return RoundDbl(2*L+164,-1);
												elseif Lm <= 49 then
													return RoundDbl(L+201,-1);
												else
													return 20*L-740;
												end
											else
												return 0;
											end
										else
											return 5*L+385;
										end
									elseif SN > "WORTHTABBC" then
										if SN < "WORTHTABBE" then
											if SN == "WORTHTABBD" then
												return CalcStat("WorthTabK",L)+1;
											else
												return 0;
											end
										elseif SN > "WORTHTABBE" then
											if SN == "WORTHTABBF" then
												return CalcStat("WorthTabAV",L)+20;
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 60;
											elseif Lm <= 7 then
												return RoundDbl(L/3)*40+30;
											elseif Lm <= 13 then
												return RoundDbl(L/3)*130-210;
											elseif Lm <= 19 then
												return RoundDbl(L/3)*60+140;
											elseif Lm <= 25 then
												return RoundDbl(L/3)*10+480;
											elseif Lm <= 46 then
												return RoundDbl(L/3)*10+490;
											elseif Lm <= 50 then
												return 660;
											else
												return 20*L-320;
											end
										end
									else
										if Lm <= 34 then
											return RoundDbl(L/15+0.8)*3750+1250;
										elseif Lm <= 35 then
											return 100000;
										else
											return 125500;
										end
									end
								else
									if Lm <= 44 then
										return RoundDbl(0.0525*L+0.7);
									elseif Lm <= 65 then
										return RoundDbl(0.19*L-4.85);
									elseif Lm <= 81 then
										return RoundDbl(0.19*L+28.15);
									else
										return RoundDbl(0.19*L+28.15+RoundDbl(L*0.05-4.55)*0.2);
									end
								end
							elseif SN > "WORTHTABBG" then
								if SN < "WORTHTABBO" then
									if SN < "WORTHTABBK" then
										if SN < "WORTHTABBI" then
											if SN == "WORTHTABBH" then
												if Lm <= 80 then
													return RoundDbl(0.05*L-0.05)+RoundDbl(0.05*L+0.45);
												else
													return RoundDbl(0.05*L-0.1)+RoundDbl(0.05*L+0.45);
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABBI" then
											if SN == "WORTHTABBJ" then
												return RoundDbl(0.1*L+0.45)*3;
											else
												return 0;
											end
										else
											return CalcStat("WorthTabG",L)-25;
										end
									elseif SN > "WORTHTABBK" then
										if SN < "WORTHTABBM" then
											if SN == "WORTHTABBL" then
												if Lm <= 35 then
													return 126600;
												elseif Lm <= 46 then
													return 150600;
												elseif Lm <= 47 then
													return 180720;
												else
													return 150600;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABBM" then
											if SN == "WORTHTABBN" then
												if Lm <= 1 then
													return 400;
												else
													return 20*L+800;
												end
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 10;
											else
												return 20*L-20;
											end
										end
									else
										if Lm <= 10 then
											return RoundDbl(0.1*L+0.45);
										else
											return RoundDbl(0.1*L-0.6)*2;
										end
									end
								elseif SN > "WORTHTABBO" then
									if SN < "WORTHTABBS" then
										if SN < "WORTHTABBQ" then
											if SN == "WORTHTABBP" then
												if Lm <= 10 then
													return 156.25*L+1562.5;
												elseif Lm <= 20 then
													return 312.5*L;
												elseif Lm <= 30 then
													return 625*L-6250;
												elseif Lm <= 40 then
													return 1250*L-25000;
												else
													return 2500*L-75000;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABBQ" then
											if SN == "WORTHTABBR" then
												if Lm <= 49 then
													return CalcStat("WorthTabBQ",L)*2;
												else
													return 4*L+250;
												end
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 50;
											elseif Lm <= 49 then
												return RoundDbl(2.5*L+100);
											else
												return 3*L+75;
											end
										end
									elseif SN > "WORTHTABBS" then
										if SN < "WORTHTABBU" then
											if SN == "WORTHTABBT" then
												return 62500;
											else
												return 0;
											end
										elseif SN > "WORTHTABBU" then
											if SN == "WORTHTABBV" then
												if Lm <= 29 then
													return 1250;
												else
													return RoundDbl(0.05*L-1)*2500;
												end
											else
												return 0;
											end
										else
											if Lm <= 80 then
												return 20*L+300;
											else
												return 10*L+1100;
											end
										end
									else
										return CalcStat("WorthTabBR",L)*2;
									end
								else
									if Lm <= 10 then
										return 10;
									elseif Lm <= 40 then
										return RoundDbl(0.1*L-0.55)*50-25;
									elseif Lm <= 80 then
										return RoundDbl(0.1*L-0.55)*50;
									else
										return RoundDbl(0.1*L-0.55)*25+175;
									end
								end
							else
								if Lm <= 7 then
									return RoundDbl(0.2*L-0.4)*2+1;
								elseif Lm <= 16 then
									return RoundDbl(L/3-2)*6;
								elseif Lm <= 22 then
									return RoundDbl(L/3+1)*3;
								elseif Lm <= 25 then
									return RoundDbl(L/3+1)*3-2;
								elseif Lm <= 80 then
									return RoundDbl(L/3+18)-2;
								else
									return L-37;
								end
							end
						elseif SN > "WORTHTABBW" then
							if SN < "WORTHTABCL" then
								if SN < "WORTHTABCD" then
									if SN < "WORTHTABC" then
										if SN < "WORTHTABBY" then
											if SN == "WORTHTABBX" then
												if Lm <= 10 then
													return RoundDbl(0.1*L+0.45)*3;
												elseif Lm <= 140 then
													return RoundDbl(0.1*L-0.6)*6;
												else
													return RoundDbl(0.1*L+0.4)*4+22;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABBY" then
											if SN == "WORTHTABBZ" then
												if Lm <= 10 then
													return 27.42*L+273.1;
												elseif Lm <= 20 then
													return 54.69*L;
												elseif Lm <= 30 then
													return 109.35*L-1093;
												elseif Lm <= 40 then
													return 218.75*L-4375;
												elseif Lm <= 80 then
													return 437.5*L-13125;
												else
													return 437*L-13085;
												end
											else
												return 0;
											end
										else
											return 90000;
										end
									elseif SN > "WORTHTABC" then
										if SN < "WORTHTABCB" then
											if SN == "WORTHTABCA" then
												if Lm <= 10 then
													return 7.25*L+72.25;
												elseif Lm <= 20 then
													return 14.49*L+0.11;
												elseif Lm <= 30 then
													return 29*L-290;
												elseif Lm <= 35 then
													return 57.99*L-1160.16;
												elseif Lm <= 40 then
													return 57.99*L-1160.12;
												elseif Lm <= 80 then
													return 115.94*L-3478.2;
												else
													return 116*L-3483;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABCB" then
											if SN == "WORTHTABCC" then
												return CalcStat("WorthTabBK",L)*5;
											else
												return 0;
											end
										else
											return 0.1;
										end
									else
										return CalcStat("WorthTabD",L)+20;
									end
								elseif SN > "WORTHTABCD" then
									if SN < "WORTHTABCH" then
										if SN < "WORTHTABCF" then
											if SN == "WORTHTABCE" then
												return CalcStat("WorthTabBN",L)*10;
											else
												return 0;
											end
										elseif SN > "WORTHTABCF" then
											if SN == "WORTHTABCG" then
												return 20;
											else
												return 0;
											end
										else
											if Lm <= 20 then
												return RoundDbl(0.1*L-0.55)*600+200;
											elseif Lm <= 40 then
												return RoundDbl(0.1*L-0.55)*1000-500;
											elseif Lm <= 60 then
												return RoundDbl(0.1*L-0.55)*2000-4000;
											elseif Lm <= 70 then
												return 8500;
											elseif Lm <= 140 then
												return RoundDbl(0.1*L-0.55)*2500-7500;
											elseif Lm <= 200 then
												return RoundDbl(0.1*L-0.55)*3000-14000;
											else
												return RoundDbl(0.1*L-0.55)*2500-3500;
											end
										end
									elseif SN > "WORTHTABCH" then
										if SN < "WORTHTABCJ" then
											if SN == "WORTHTABCI" then
												return 40000;
											else
												return 0;
											end
										elseif SN > "WORTHTABCJ" then
											if SN == "WORTHTABCK" then
												return 15000;
											else
												return 0;
											end
										else
											return 20000;
										end
									else
										return 50000;
									end
								else
									return CalcStat("WorthTabBK",L)*25;
								end
							elseif SN > "WORTHTABCL" then
								if SN < "WORTHTABE" then
									if SN < "WORTHTABCP" then
										if SN < "WORTHTABCN" then
											if SN == "WORTHTABCM" then
												return 7500;
											else
												return 0;
											end
										elseif SN > "WORTHTABCN" then
											if SN == "WORTHTABCO" then
												return CalcStat("WorthTabAB",L);
											else
												return 0;
											end
										else
											return RoundDbl(0.1*L+0.5)*10000;
										end
									elseif SN > "WORTHTABCP" then
										if SN < "WORTHTABCR" then
											if SN == "WORTHTABCQ" then
												if Lm <= 10 then
													return RoundDbl(0.3*L+0.2)*2;
												elseif Lm <= 16 then
													return RoundDbl(0.25*L-1)*6;
												elseif Lm <= 22 then
													return RoundDbl(0.3*L+5.5)*2;
												elseif Lm <= 50 then
													return RoundDbl((1/6)*L+8.75)*2;
												elseif Lm <= 80 then
													return RoundDbl((1/3)*L-11.5)*6;
												else
													return RoundDbl(0.25*L-4.6)*6;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABCR" then
											if SN == "WORTHTABD" then
												if Lm <= 49 then
													return 7.5*L;
												else
													return 8*L-25;
												end
											else
												return 0;
											end
										else
											return CalcStat("WorthTabM",L)-15;
										end
									else
										return 1;
									end
								elseif SN > "WORTHTABE" then
									if SN < "WORTHTABI" then
										if SN < "WORTHTABG" then
											if SN == "WORTHTABF" then
												return 0.1;
											else
												return 0;
											end
										elseif SN > "WORTHTABG" then
											if SN == "WORTHTABH" then
												if Lm <= 2 then
													return L;
												elseif Lm <= 9 then
													return 1.48*L-2.85;
												elseif Lm <= 11 then
													return 2.5*L-13;
												elseif Lm <= 24 then
													return 2.5*L-10;
												else
													return 5*L-70;
												end
											else
												return 0;
											end
										else
											if Lm <= 1 then
												return 50;
											else
												return CalcStat("WorthTabAF",L)+100;
											end
										end
									elseif SN > "WORTHTABI" then
										if SN < "WORTHTABK" then
											if SN == "WORTHTABJ" then
												if Lm <= 4 then
													return 2.5*L+7.5;
												elseif Lm <= 5 then
													return 23;
												else
													return 4*L;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABK" then
											if SN == "WORTHTABL" then
												return CalcStat("WorthTabB",L)+19.25;
											else
												return 0;
											end
										else
											if Lm <= 9 then
												return 12*L+24;
											else
												return 7*L+74;
											end
										end
									else
										if Lm <= 4 then
											return 1;
										elseif Lm <= 10 then
											return 0.7*L-1;
										elseif Lm <= 15 then
											return 1.4*L-7;
										elseif Lm <= 24 then
											return 1.25*L-5;
										elseif Lm <= 49 then
											return 2.5*L-35;
										else
											return 3*L-60;
										end
									end
								else
									if Lm <= 9 then
										return 30*L+50;
									else
										return 7*L+280;
									end
								end
							else
								return 12500;
							end
						else
							if Lm <= 1 then
								return 645;
							elseif Lm <= 9 then
								return 20*L+980;
							else
								return 50*L+920;
							end
						end
					else
						if Lm <= 4 then
							return RoundDbl(3*L+20,-1);
						elseif Lm <= 7 then
							return 60;
						elseif Lm <= 10 then
							return 100;
						elseif Lm <= 13 then
							return 180;
						elseif Lm <= 16 then
							return 270;
						elseif Lm <= 19 then
							return 310;
						elseif Lm <= 40 then
							return RoundDbl(3.2*L+274,-1);
						elseif Lm <= 43 then
							return 400;
						elseif Lm <= 53 then
							return RoundDbl(1.9*L+334,-1);
						elseif Lm <= 56 then
							return 460;
						elseif Lm <= 59 then
							return 480;
						else
							return 20*L-680;
						end
					end
				elseif SN > "WORTHTABM" then
					if SN < "WORTHVALBV" then
						if SN < "WORTHVALAQ" then
							if SN < "WORTHVALAA" then
								if SN < "WORTHTABT" then
									if SN < "WORTHTABP" then
										if SN > "WORTHTABN" then
											if SN == "WORTHTABO" then
												return CalcStat("WorthTabB",L)+11;
											else
												return 0;
											end
										elseif SN == "WORTHTABN" then
											return CalcStat("WorthTabAF",L)+25;
										else
											return 0;
										end
									elseif SN > "WORTHTABP" then
										if SN < "WORTHTABR" then
											if SN == "WORTHTABQ" then
												return 7*L+25;
											else
												return 0;
											end
										elseif SN > "WORTHTABR" then
											if SN == "WORTHTABS" then
												return CalcStat("WorthTabD",L)+17.5;
											else
												return 0;
											end
										else
											if Lm <= 9 then
												return 12*L+30;
											else
												return 7*L+75;
											end
										end
									else
										return CalcStat("WorthTabE",L);
									end
								elseif SN > "WORTHTABT" then
									if SN < "WORTHTABX" then
										if SN < "WORTHTABV" then
											if SN == "WORTHTABU" then
												if Lm <= 10 then
													return 9*L+20;
												elseif Lm <= 49 then
													return 5.5*L+55;
												else
													return 6*L+30;
												end
											else
												return 0;
											end
										elseif SN > "WORTHTABV" then
											if SN == "WORTHTABW" then
												return CalcStat("WorthTabD",L)+25;
											else
												return 0;
											end
										else
											return CalcStat("WorthTabB",L)-2.75;
										end
									elseif SN > "WORTHTABX" then
										if SN < "WORTHTABZ" then
											if SN == "WORTHTABY" then
												return CalcStat("WorthTabD",L)+30;
											else
												return 0;
											end
										elseif SN > "WORTHTABZ" then
											if SN == "WORTHVALA" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabA"));
											else
												return 0;
											end
										else
											return CalcStat("WorthTabR",L)-15;
										end
									else
										return CalcStat("WorthTabAF",L)+75;
									end
								else
									if Lm <= 1 then
										return 54;
									elseif Lm <= 17 then
										return 10.73*L+43.57;
									elseif Lm <= 35 then
										return 10.735*L+43.265;
									elseif Lm <= 36 then
										return 429;
									elseif Lm <= 42 then
										return 10.65*L+46.45;
									elseif Lm <= 49 then
										return 10.7*L+44.6;
									else
										return 9*L+130;
									end
								end
							elseif SN > "WORTHVALAA" then
								if SN < "WORTHVALAI" then
									if SN < "WORTHVALAE" then
										if SN < "WORTHVALAC" then
											if SN == "WORTHVALAB" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAB"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAC" then
											if SN == "WORTHVALAD" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAD"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAC"));
										end
									elseif SN > "WORTHVALAE" then
										if SN < "WORTHVALAG" then
											if SN == "WORTHVALAF" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAF"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAG" then
											if SN == "WORTHVALAH" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabAH"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAG"));
										end
									else
										return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAE"));
									end
								elseif SN > "WORTHVALAI" then
									if SN < "WORTHVALAM" then
										if SN < "WORTHVALAK" then
											if SN == "WORTHVALAJ" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabAJ"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAK" then
											if SN == "WORTHVALAL" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabAL"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabAK"));
										end
									elseif SN > "WORTHVALAM" then
										if SN < "WORTHVALAO" then
											if SN == "WORTHVALAN" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAN"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAO" then
											if SN == "WORTHVALAP" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAP"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAO"));
										end
									else
										return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAM"));
									end
								else
									return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabAI"));
								end
							else
								return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAA"));
							end
						elseif SN > "WORTHVALAQ" then
							if SN < "WORTHVALBF" then
								if SN < "WORTHVALAY" then
									if SN < "WORTHVALAU" then
										if SN < "WORTHVALAS" then
											if SN == "WORTHVALAR" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAR"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAS" then
											if SN == "WORTHVALAT" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAT"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAS"));
										end
									elseif SN > "WORTHVALAU" then
										if SN < "WORTHVALAW" then
											if SN == "WORTHVALAV" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAV"));
											else
												return 0;
											end
										elseif SN > "WORTHVALAW" then
											if SN == "WORTHVALAX" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAX"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAW"));
										end
									else
										return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAU"));
									end
								elseif SN > "WORTHVALAY" then
									if SN < "WORTHVALBB" then
										if SN < "WORTHVALB" then
											if SN == "WORTHVALAZ" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabAZ"));
											else
												return 0;
											end
										elseif SN > "WORTHVALB" then
											if SN == "WORTHVALBA" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBA"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabB"));
										end
									elseif SN > "WORTHVALBB" then
										if SN < "WORTHVALBD" then
											if SN == "WORTHVALBC" then
												return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBC"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBD" then
											if SN == "WORTHVALBE" then
												return RoundDbl(CalcStat("WorthMpJ",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBE"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBD"));
										end
									else
										return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBB"));
									end
								else
									return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabAY"));
								end
							elseif SN > "WORTHVALBF" then
								if SN < "WORTHVALBN" then
									if SN < "WORTHVALBJ" then
										if SN < "WORTHVALBH" then
											if SN == "WORTHVALBG" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBG"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBH" then
											if SN == "WORTHVALBI" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBI"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBH"));
										end
									elseif SN > "WORTHVALBJ" then
										if SN < "WORTHVALBL" then
											if SN == "WORTHVALBK" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBK"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBL" then
											if SN == "WORTHVALBM" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBM"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBL"));
										end
									else
										return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBJ"));
									end
								elseif SN > "WORTHVALBN" then
									if SN < "WORTHVALBR" then
										if SN < "WORTHVALBP" then
											if SN == "WORTHVALBO" then
												return RoundDbl(CalcStat("WorthMpG",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBO"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBP" then
											if SN == "WORTHVALBQ" then
												return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBQ"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBP"));
										end
									elseif SN > "WORTHVALBR" then
										if SN < "WORTHVALBT" then
											if SN == "WORTHVALBS" then
												return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBS"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBT" then
											if SN == "WORTHVALBU" then
												return RoundDbl(CalcStat("WorthMpF",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBU"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBT"));
										end
									else
										return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBR"));
									end
								else
									return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBN"));
								end
							else
								return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBF"));
							end
						else
							return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabAQ"));
						end
					elseif SN > "WORTHVALBV" then
						if SN < "WORTHVALL" then
							if SN < "WORTHVALCK" then
								if SN < "WORTHVALCC" then
									if SN < "WORTHVALBZ" then
										if SN < "WORTHVALBX" then
											if SN == "WORTHVALBW" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBW"));
											else
												return 0;
											end
										elseif SN > "WORTHVALBX" then
											if SN == "WORTHVALBY" then
												return RoundDbl(CalcStat("WorthMpE",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBY"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBX"));
										end
									elseif SN > "WORTHVALBZ" then
										if SN < "WORTHVALCA" then
											if SN == "WORTHVALC" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabC"));
											else
												return 0;
											end
										elseif SN > "WORTHVALCA" then
											if SN == "WORTHVALCB" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCB"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCA"));
										end
									else
										return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabBZ"));
									end
								elseif SN > "WORTHVALCC" then
									if SN < "WORTHVALCG" then
										if SN < "WORTHVALCE" then
											if SN == "WORTHVALCD" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabCD"));
											else
												return 0;
											end
										elseif SN > "WORTHVALCE" then
											if SN == "WORTHVALCF" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabCF"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpH",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCE"));
										end
									elseif SN > "WORTHVALCG" then
										if SN < "WORTHVALCI" then
											if SN == "WORTHVALCH" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCH"));
											else
												return 0;
											end
										elseif SN > "WORTHVALCI" then
											if SN == "WORTHVALCJ" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCJ"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCI"));
										end
									else
										return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCG"));
									end
								else
									return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabCC"));
								end
							elseif SN > "WORTHVALCK" then
								if SN < "WORTHVALD" then
									if SN < "WORTHVALCO" then
										if SN < "WORTHVALCM" then
											if SN == "WORTHVALCL" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCL"));
											else
												return 0;
											end
										elseif SN > "WORTHVALCM" then
											if SN == "WORTHVALCN" then
												return RoundDbl(CalcStat("WorthMpI",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCN"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCM"));
										end
									elseif SN > "WORTHVALCO" then
										if SN < "WORTHVALCQ" then
											if SN == "WORTHVALCP" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCP"));
											else
												return 0;
											end
										elseif SN > "WORTHVALCQ" then
											if SN == "WORTHVALCR" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCR"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpK",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCQ"));
										end
									else
										return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCO"));
									end
								elseif SN > "WORTHVALD" then
									if SN < "WORTHVALH" then
										if SN < "WORTHVALF" then
											if SN == "WORTHVALE" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabE"));
											else
												return 0;
											end
										elseif SN > "WORTHVALF" then
											if SN == "WORTHVALG" then
												return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabG"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabF"));
										end
									elseif SN > "WORTHVALH" then
										if SN < "WORTHVALJ" then
											if SN == "WORTHVALI" then
												return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabI"));
											else
												return 0;
											end
										elseif SN > "WORTHVALJ" then
											if SN == "WORTHVALK" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabK"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabJ"));
										end
									else
										return RoundDbl(CalcStat("WorthMpA",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabH"));
									end
								else
									return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabD"));
								end
							else
								return RoundDbl(CalcStat("WorthMpC",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabCK"));
							end
						elseif SN > "WORTHVALL" then
							if SN < "WPNDMGMAX" then
								if SN < "WORTHVALT" then
									if SN < "WORTHVALP" then
										if SN < "WORTHVALN" then
											if SN == "WORTHVALM" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabM"));
											else
												return 0;
											end
										elseif SN > "WORTHVALN" then
											if SN == "WORTHVALO" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabO"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabN"));
										end
									elseif SN > "WORTHVALP" then
										if SN < "WORTHVALR" then
											if SN == "WORTHVALQ" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabQ"));
											else
												return 0;
											end
										elseif SN > "WORTHVALR" then
											if SN == "WORTHVALS" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabS"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabR"));
										end
									else
										return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabP"));
									end
								elseif SN > "WORTHVALT" then
									if SN < "WORTHVALX" then
										if SN < "WORTHVALV" then
											if SN == "WORTHVALU" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabU"));
											else
												return 0;
											end
										elseif SN > "WORTHVALV" then
											if SN == "WORTHVALW" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabW"));
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabV"));
										end
									elseif SN > "WORTHVALX" then
										if SN < "WORTHVALZ" then
											if SN == "WORTHVALY" then
												return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabY"));
											else
												return 0;
											end
										elseif SN > "WORTHVALZ" then
											if SN == "WOUNDRESISTT" then
												return CalcStat("ResistAddT",L,N);
											else
												return 0;
											end
										else
											return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabZ"));
										end
									else
										return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabX"));
									end
								else
									return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt8Lin",L,"WorthTabT"));
								end
							elseif SN > "WPNDMGMAX" then
								if SN < "WRDPHYMAS" then
									if SN < "WRDBATSTRIKESCRITDEF" then
										if SN < "WPNDPS" then
											if SN == "WPNDMGMIN" then
												return ((2-2*CalcStat("WpnDPSVarianceType",WpnCodeIndex(C,2)))/(2-CalcStat("WpnDPSVarianceType",WpnCodeIndex(C,2))))*CalcStat("CombatBase",L,C);
											else
												return 0;
											end
										elseif SN > "WPNDPS" then
											if SN == "WPNDPSVARIANCETYPE" then
												if Lm <= 0 then
													return 0;
												else
													return DataTableValue({0.25,0.25,0.25},L);
												end
											else
												return 0;
											end
										else
											return CalcStat("CombatBase",L,C);
										end
									elseif SN > "WRDBATSTRIKESCRITDEF" then
										if SN < "WRDFINESSE" then
											if SN == "WRDCRITDEF" then
												return CalcStat("CritDefT",L,1.0);
											else
												return 0;
											end
										elseif SN > "WRDFINESSE" then
											if SN == "WRDIMPRBLADESPARRY" then
												return CalcStat("ParryT",L,2.8);
											else
												return 0;
											end
										else
											return CalcStat("FinesseT",L,CalcStat("Trait12345Choice",N)*0.4);
										end
									else
										return CalcStat("CritDefT",L,CalcStat("Trait123Choice",N)*0.4);
									end
								elseif SN > "WRDPHYMAS" then
									if SN < "WRDSSSHPIERCERBLOCK" then
										if SN < "WRDSHIELDMASBLOCK" then
											if SN == "WRDRECKLESSNCRITHIT" then
												return CalcStat("CritHitT",L,2.4);
											else
												return 0;
											end
										elseif SN > "WRDSHIELDMASBLOCK" then
											if SN == "WRDSHIELDTACTCRITDEF" then
												return CalcStat("CritDefT",L,2);
											else
												return 0;
											end
										else
											return CalcStat("BlockT",L,2.8);
										end
									elseif SN > "WRDSSSHPIERCERBLOCK" then
										if SN < "WRDSTDYOURGREVADE" then
											if SN == "WRDSTDYOURGRBLOCK" then
												return CalcStat("BlockT",L,CalcStat("Trait1234Choice",N)*0.4);
											else
												return 0;
											end
										elseif SN > "WRDSTDYOURGREVADE" then
											if SN == "WRDSTDYOURGRPARRY" then
												return CalcStat("ParryT",L,CalcStat("Trait1234Choice",N)*0.4);
											else
												return 0;
											end
										else
											return -CalcStat("EvadeT",L,CalcStat("Trait1234Choice",N)*0.4);
										end
									else
										return -CalcStat("BlockT",L,4);
									end
								else
									return CalcStat("PhyMasT",L,CalcStat("Trait12345Choice",N)*0.4);
								end
							else
								return (2/(2-CalcStat("WpnDPSVarianceType",WpnCodeIndex(C,2))))*CalcStat("CombatBase",L,C);
							end
						else
							return RoundDbl(CalcStat("WorthMpB",QualityCodeIndex(C))*CalcStat("WorthExt",L,"WorthTabL"));
						end
					else
						return RoundDbl(CalcStat("WorthMpD",QualityCodeIndex(C))*CalcStat("WorthExt4Lin",L,"WorthTabBV"));
					end
				else
					if Lm <= 9 then
						return 10*L+11;
					elseif Lm <= 49 then
						return 4*L+65;
					else
						return 5*L+15;
					end
				end
			else
				return 2;
			end
		else
			return CalcStat("MitLightPRatPB",L);
		end
	else
		return 12;
	end

end

-- Support functions for CalcStat. These consist of implementations of more complex calculation types, decode methods for parameter "C" and rounding/min/max/compare functions for floating point numbers.

-- ****************** Calculation Type support functions ******************

-- DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
-- DataTableValue: Takes a value from an array table.

function DataTableValue(vDataArray, dIndex)

	local lIndex = RoundDbl(dIndex);
	if lIndex <= 1 then
		return vDataArray[1];
	elseif lIndex > #vDataArray then
		return vDataArray[#vDataArray];
	else
		return vDataArray[lIndex];
	end

end

-- EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
-- ExpFmod: Exponential function based on percentage.
-- Common percentage values are around ~5.5% for between levels and ~20% jumps between level segments.

function ExpFmod(dVal, dLstart, dPlvl, dLvl, vDec, vAdd)

	local dRng = dLvl-dLstart+1;
	if dRng <= DblCalcDev then
		return dVal;
	else
		local dFac = 1+dPlvl/100;
		local dAdd;
		if vAdd == nil then
			dAdd = 0;
		else
			dAdd = vAdd;
		end
		if vDec == nil then
			local dFacExp = dFac^dRng;
			return dVal*dFacExp+dAdd*((dFacExp-1)/(dFac-1));
		else
			local dResult = dVal;
			local dLm = dLstart-DblCalcDev;
			while dLm <= dLvl do
				dResult = RoundDbl(dResult*dFac+dAdd,vDec);
				dLm = dLm+1;
			end
			return dResult;
		end
	end

end

-- PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
-- CalcPercAB: Calculates the percentage out of a rating based on the AB formula.

function CalcPercAB(dA, dB, dPCap, dR)

	if dR <= DblCalcDev then
		return 0.0;
	else
		local dResult = dA/(1+dB/dR);
		if dResult >= dPCap-DblCalcDev then
			return dPCap;
		else
			return dResult;
		end
	end

end

-- RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
-- CalcRatAB: Calculates the rating out of a percentage based on the AB formula.

function CalcRatAB(dA, dB, dCapR, dP)

	if dP <= DblCalcDev then
		return 0.0;
	else
		local dResult = dB/(dA/dP-1);
		if dResult >= dCapR-DblCalcDev then
			return dCapR;
		else
			return dResult;
		end
	end

end

-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
-- StatLinInter: (Normalized) Stat Linear Interpolating

function StatLinInter(sPntMP, sProgScheme, sProgBase, sAdj, dLvl, vNorC, vRoundType)

	-- parameter processing
	local dN = 1;
	local sC = "";
	if type(vNorC) == "number" then
		dN = vNorC;
	elseif type(vNorC) == "string" then
		sC = vNorC;
	end

	local dRoundType = 0;
	if type(vRoundType) == "number" then
		dRoundType = vRoundType;
	end
	
	local dProgScheme = CalcStat(sProgScheme,dLvl);
	if type(dProgScheme) ~= "table" then
		return 0.0;
	end

	-- find level interval
	local dLvlMinus = dLvl-DblCalcDev;
	local iPointIndexHigh = 2;
	local iPointIndexMax = #dProgScheme[1];
	while iPointIndexHigh < iPointIndexMax do
		if dLvlMinus <= dProgScheme[1][iPointIndexHigh] then
			break;
		end
		iPointIndexHigh = iPointIndexHigh+1;
	end
	local iPointIndexLow = iPointIndexHigh-1;
		
	local dAccessLvlLow = dProgScheme[1][iPointIndexLow];
	local dAccessLvlHigh = dProgScheme[1][iPointIndexHigh];
	local dBaseLvlLow = dProgScheme[2][iPointIndexLow];
	local dBaseLvlHigh = dProgScheme[2][iPointIndexHigh];
	
	-- get values from base progression
	local dValLow = CalcStat(sProgBase,dBaseLvlLow,sC);
	local dValHigh = CalcStat(sProgBase,dBaseLvlHigh,sC);

	-- graph point multiplications
	if type(sPntMP) == "string" and sPntMP ~= "" then
		dValLow = dValLow*CalcStat(sPntMP,dAccessLvlLow,sC);
		dValHigh = dValHigh*CalcStat(sPntMP,dAccessLvlHigh,sC);
	end
	if type(sAdj) == "string" and sAdj ~= "" then
		dValLow = dValLow*CalcStat(sAdj,dAccessLvlLow,sC);
		dValHigh = dValHigh*CalcStat(sAdj,dAccessLvlHigh,sC);
	end
	dValLow = dValLow*dN;
	dValHigh = dValHigh*dN;

	-- graph point roundings
	if dRoundType == 0 then
		dValLow = RoundDblLotro(dValLow);
		dValHigh = RoundDblLotro(dValHigh);
	elseif dRoundType == 1 then
		if -100.0 <= dValLow and dValLow <= 100.0 then
			dValLow = RoundDblUp(dValLow,2);
		elseif -1000.0 <= dValLow and dValLow <= 1000.0 then
			dValLow = RoundDblUp(dValLow,1);
		else
			dValLow = RoundDblLotro(dValLow);
		end
		if -100.0 <= dValHigh and dValHigh <= 100.0 then
			dValHigh = RoundDblUp(dValHigh,2);
		elseif -1000.0 <= dValHigh and dValHigh <= 1000.0 then
			dValHigh = RoundDblUp(dValHigh,1);
		else
			dValHigh = RoundDblLotro(dValHigh);
		end
	elseif dRoundType == 2 then
		dValLow = RoundDblLotro(dValLow);
		if dValLow == -1 then
			dValLow = -2;
		end
		dValHigh = RoundDblLotro(dValHigh);
		if dValHigh == -1 then
			dValHigh = -2;
		end
	elseif dRoundType == 3 then
		dValLow = RoundDblProg(dValLow);
		dValHigh = RoundDblProg(dValHigh);
	end

	-- return interpolated value from the calculated graph points
	return LinFmod(1,dValLow,dValHigh,dAccessLvlLow,dAccessLvlHigh,dLvl);

end

-- TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
-- LinFmod: Linear line function between 2 points with some optional modifications.
-- Connects point (dLstart,dVal*dFstart) with (dLend,dVal*dFend).
-- Usually used with dVal=1 and dFstart/dFend containing unrelated points or dVal=# and dFstart/dFend containing multiplier factors.
-- Modification for in-between points on the line: rounding.

function LinFmod(dVal, dFstart, dFend, dLstart, dLend, dLvl, vDec)

	if type(vDec) == "string" then
		local sRoundType = string.upper(vDec);
		if sRoundType == "P" then
			return LinFmod(1,RoundDblProg(dVal*dFstart),RoundDblProg(dVal*dFend),dLstart,dLend,dLvl);
		elseif sRoundType == "L" then
			return LinFmod(1,RoundDblLotro(dVal*dFstart),RoundDblLotro(dVal*dFend),dLstart,dLend,dLvl);
		else
			return LinFmod(1,dVal*dFstart,dVal*dFend,dLstart,dLend,dLvl);
		end
	end
	if dLstart-DblCalcDev <= dLvl and dLvl <= dLstart+DblCalcDev then
		return dVal*dFstart;
	elseif dLend-DblCalcDev <= dLvl and dLvl <= dLend+DblCalcDev then
		return dVal*dFend;
	elseif dLstart == dLend then
		return 0.0;
	elseif vDec == nil then
		return dVal*(dFstart*(dLend-dLvl)+(dLvl-dLstart)*dFend)/(dLend-dLstart);
	else
		return RoundDbl(dVal*(dFstart*(dLend-dLvl)+(dLvl-dLstart)*dFend)/(dLend-dLstart),vDec);
	end

end

-- ****************** Parameter "C" decode support functions ******************

-- ArmCodeIndex: returns a specified index from an Armour Code.
-- sACode string:
-- 1st position: H=heavy, M=medium, L=light
-- 2nd position: H=head, S=shoulders, CL=cloak/back, C=chest, G=gloves, L=leggings, B=boots, Sh=shield
-- 3rd position: W=white/common, Y=yellow/uncommon, P=purple/rare, T=teal/blue/incomparable, G=gold/legendary/epic
-- Note: no such thing exists as a heavy, medium or light cloak, so no H/M/L in cloak codes (cloaks go automatically in the M class since U23, although historically this was L)

function ArmCodeIndex(sACode, iI)

	if sACode == nil or iI == nil then
		return 0;
	end
	if type(sACode) ~= "string" or type(iI) ~= "number" then
		return 0;
	end

	local sArmCode = string.match(sACode,"(%a+)");
	if not sArmCode then
		return 0;
	end
	sArmCode = string.upper(sArmCode).."    ";
	
	local sArmCat = string.sub(sArmCode,1,1);
	local sArmType = string.sub(sArmCode,2,2);
	local sArmCol = string.sub(sArmCode,3,3);

	if sArmType == "S" and sArmCol == "H" then
		sArmType = "SH";
		sArmCol = string.sub(sArmCode,4,4);
	elseif sArmCat == "C" and sArmType == "L" then
		sArmCat = "M";
		sArmType = "CL";
	elseif sArmType then
		sArmType = " "..sArmType;
	end
	
	local result = 0;
	if iI == 1 then
		if sArmCat then
			result = string.find("HML",sArmCat);
		end
	elseif iI == 2 then
		if sArmType then
			result = string.find(" H SCL C G L BSH",sArmType);
			if result then
				result = (result+1)/2;
			end
		end
	elseif iI == 3 then
		if sArmCol then
			result = string.find("WYPTG",sArmCol);
		end
	end

	if result then
		return result;
	else
		return 0;
	end
	
end

-- QualityCodeIndex: returns a quality index from a Quality Code.
-- sQCode string: W=white/common, Y=yellow/uncommon, P=purple/rare, T=teal/blue/incomparable, G=gold/legendary/epic

function QualityCodeIndex(sQCode)

	if sQCode == nil then
		return 0;
	end
	if type(sQCode) ~= "string" then
		return 0;
	end

	local sQtyCode = string.match(sQCode,"(%a+)");
	if not sQtyCode then
		return 0;
	end
	sQtyCode = string.upper(sQtyCode).." ";

	local sQtyCol = string.sub(sQtyCode,1,1);
	
	local result = 0;
	if sQtyCol then
		result = string.find("WYPTG",sQtyCol);
	end
	
	if result then
		return result;
	else
		return 0;
	end
	
end

-- WpnCodeIndex: returns a specified index from a Weapon Code.
-- sWCode string:
-- 1st position: H=heavy, L=light
-- 2nd position: O=one-handed, T=two-handed, B=bow
-- 3rd position: W=white/common, Y=yellow/uncommon, P=purple/rare, T=teal/blue/incomparable, G=gold/legendary/epic

function WpnCodeIndex(sWCode, iI)

	if sWCode == nil or iI == nil then
		return 0;
	end
	if type(sWCode) ~= "string" or type(iI) ~= "number" then
		return 0;
	end

	local sWpnCode = string.match(sWCode,"(%a+)");
	if not sWpnCode then
		return 0;
	end
	sWpnCode = string.upper(sWpnCode).."   ";
	
	local sWpnCat = string.sub(sWpnCode,1,1);
	local sWpnType = string.sub(sWpnCode,2,2);
	local sWpnCol = string.sub(sWpnCode,3,3);

	local result = 0;
	if iI == 1 then
		if sWpnCat then
			result = string.find("HL",sWpnCat);
		end
	elseif iI == 2 then
		if sWpnType then
			result = string.find("OTB",sWpnType);
		end
	elseif iI == 3 then
		if sWpnCol then
			result = string.find("WYPTG",sWpnCol);
		end
	end

	if result then
		return result;
	else
		return 0;
	end
	
end

-- RomanRankDecode: converts a string with a Roman number in characters, to an integer number.
-- used for Legendary Item Title calculation.

local RomanCharsToValues = {["M"]=1000,["CM"]=900,["D"]=500,["CD"]=400,["C"]=100,["XC"]=90,["L"]=50,["XL"]=40,["X"]=10,["IX"]=9,["V"]=5,["IV"]=4,["I"]=1};

function RomanRankDecode(sNumber)

	if sNumber ~= nil and type(sNumber) == "string" and sNumber ~= "" then
		for sRomanRankChar, iRomanRankValue in pairs(RomanCharsToValues) do
			if string.sub(string.upper(sNumber),1,string.len(sRomanRankChar)) == sRomanRankChar then
				return iRomanRankValue+RomanRankDecode(string.sub(sNumber,string.len(sRomanRankChar)+1));
			end
		end
	end
	
	return 0;
	
end

-- ReverseCalc: tries to calculate back a calculation result to the original (integer) level.
-- Does not support N.

function ReverseCalc(sStat, dNum)

	if string.len(string.match(sStat,"([-%w]+)")) > 0 then
		local dNumMinus = dNum-DblCalcDev;
		local dNumPlus = dNum+DblCalcDev;
		local minlvl = 1;
		local maxlvl = 549;
		local devlvl = 3;
	
		local left = minlvl-1;
		local right = maxlvl;
		local middle;
		
		local count = minlvl;

		while right > left+1 and count <= maxlvl do
			count = count+1;
			middle = math.floor((left+right)/2);
			if CalcStat(sStat,middle) >= dNumMinus then
				right = middle;
			else
				left = middle;
			end
		end

		local mintest = right-devlvl;
		if mintest < minlvl then
			mintest = minlvl;
		end
		local maxtest = right+devlvl;
		if maxtest > maxlvl then
			maxtest = maxlvl;
		end

		local dFound;
	
		-- we check nearby in case the progression is not completely ascending/sorted.
		for test = mintest, maxtest do
			dFound = CalcStat(sStat,test);
			if dNumMinus <= dFound and dFound <= dNumPlus then
				return test;
			end
		end
	end

	return 0;

end

-- ****************** Misc. floating point support functions ******************

-- Misc. functions for floating point rounding.
-- 2nd parameter is number of decimals.

function RoundDbl(dNum, vDec)

	local dCorrection = 0.5+DblCalcDev;
	local iSign = 1;
	if dNum < 0 then
		iSign = -1;
	end
	if vDec == nil or (-DblCalcDev <= vDec and vDec <= DblCalcDev) then
		return iSign*math.floor(iSign*dNum+dCorrection);
	else
		local dFactor = 10^vDec;
		return iSign*math.floor(iSign*dNum*dFactor+dCorrection)/dFactor;
	end
	
end

function RoundDblDown(dNum, vDec)

	local dCorrection = DblCalcDev;
	local iSign = 1;
	if dNum < 0 then
		iSign = -1;
	end
	if vDec == nil or (-DblCalcDev <= vDec and vDec <= DblCalcDev) then
		return iSign*math.floor(iSign*dNum+dCorrection);
	else
		local dFactor = 10^vDec;
		return iSign*math.floor(iSign*dNum*dFactor+dCorrection)/dFactor;
	end
	
end

function RoundDblUp(dNum, vDec)

	local dCorrection = 1-DblCalcDev;
	local iSign = 1;
	if dNum < 0 then
		iSign = -1;
	end
	if vDec == nil or (-DblCalcDev <= vDec and vDec <= DblCalcDev) then
		return iSign*math.floor(iSign*dNum+dCorrection);
	else
		local dFactor = 10^vDec;
		return iSign*math.floor(iSign*dNum*dFactor+dCorrection)/dFactor;
	end
	
end

function RoundDblLotro(dNum)

	local dCorrection = 1-DblCalcDev;
	local iSign = 1;
	if dNum < 0 then
		iSign = -1;
	end

	local iNumCeiled = math.floor(iSign*dNum+dCorrection);
	if iNumCeiled <= 1000 then
		return iSign*iNumCeiled;
	end

	local iFactor = 1;
	local iTestNum = math.floor(iNumCeiled/1000);
	while iTestNum > 0 do
		iTestNum = math.floor(iTestNum/10);
		iFactor = iFactor*10;
	end

	return iSign*math.floor(iNumCeiled/iFactor+dCorrection)*iFactor;

end

function RoundDblProg(dNum)

	local dCorrection = 0.5+DblCalcDev;
	local iSign = 1;
	if dNum < 0 then
		iSign = -1;
	end
	
	local dTestNum = dNum/(0.5*(iSign*63));
	local dDec = -math.floor(math.log10(dTestNum));

	if -DblCalcDev <= dDec and dDec <= DblCalcDev then
		return iSign*math.floor(iSign*dNum+dCorrection);
	else
		local dFactor = 10^dDec;
		return iSign*math.floor(iSign*dNum*dFactor+dCorrection)/dFactor;
	end

end

-- to be used by other modules
p.DblCalcDev = DblCalcDev;
p.CalcStat = CalcStat;

-- ******************************* End CalcStat *******************************

-- *********************** Start CalcStat Expressions *************************

local TRANS_EXPRESSION = 1;
local TRANS_EXPRWIP = 2;
local TRANS_ERRCODE = 3;
local TRANS_OPERATIONS = 4;
local TRANS_OPERANDS = 5;
local TRANS_VARIABLES = 6;

local OPERAND_SOURCE = 1; -- source expression for operand (should be unique)
local OPERAND_VALUE = 2; -- current value of operand
local OPERAND_OPERATION = 3; -- source operation which gives value to this operand
local OPERAND_DEPENDSON = 4; -- collection of variables (indexes) on which operand depends for it's value

local OPERAND_OPERATION_GETVAR = -1; -- custom operation: retrieve variable value

local VAR_NAME = 1;
local VAR_VALUE = 2;
local VAR_OPERANDS = 3; -- list of operands which depend on this variable

local OPERATION_DEFINITION = 1; -- index into aOperationDefs table
local OPERATION_OPERANDS = 2; -- parameter operand indexes into TRANS_OPERANDS
local OPERATION_RESULTOP = 3; -- result operand index into TRANS_OPERANDS

local OPERATION_FORMAT_FUNCTION = 1; -- like functionname(op1,op2,op3,etc) - needs an unspecified number of operands
local OPERATION_FORMAT_UNARY = 2; -- like: operator op2 - always needs 1 operand
local OPERATION_FORMAT_BINARY = 3; -- like: op1 operator op2 - always needs 2 operands

-- operation definition Id's (not to be confused with indexes into aOperationDefs)
local UNARYOP_LOGICNEG = 1
local UNARYOP_NEGATE = 2;
local UNARYOP_POSITIVE = 3;
local BINARYOP_CONCAT = 4;
local BINARYOP_OR = 5;
local BINARYOP_AND = 6;
local BINARYOP_GREQTH = 7;
local BINARYOP_SMEQTH = 8;
local BINARYOP_EQUALS = 9;
local BINARYOP_NOTEQUALS = 10;
local BINARYOP_GRTH = 11;
local BINARYOP_SMTH = 12;
local BINARYOP_SUBSTRACT = 13;
local BINARYOP_ADD = 14;
local BINARYOP_MOD = 15;
local BINARYOP_MULTIPLY = 16;
local BINARYOP_DIVIDE = 17;
local BINARYOP_POWER = 18;
local FUNCTIONOP_IIF = 19;
local FUNCTIONOP_CALCSTAT = 20;
local FUNCTIONOP_ABS = 21;
local FUNCTIONOP_CEIL = 22;
local FUNCTIONOP_FLOOR = 23;
local FUNCTIONOP_MAX = 24;
local FUNCTIONOP_MIN = 25;
local FUNCTIONOP_LOG10 = 26;
local FUNCTIONOP_SQRT = 27;
local FUNCTIONOP_AFD = 28;
local FUNCTIONOP_FORMAT = 29;
local FUNCTIONOP_SWITCH = 30;
local FUNCTIONOP_SESEL = 31;
local FUNCTIONOP_WITH = 32;
local FUNCTIONOP_WHILE = 33;
local FUNCTIONOP_CHOOSE = 34;
local FUNCTIONOP_REPLACE = 35;
local FUNCTIONOP_UNTIL = 36;

-- operators and function names to detect (always in uppercase)
local OPERATOR_LOGICNEG = "NOT";
local OPERATOR_NEGATE = "-";
local OPERATOR_POSITIVE = "+";
local OPERATOR_CONCAT = "..";
local OPERATOR_OR = "OR";
local OPERATOR_AND = "AND";
local OPERATOR_GREQTH = ">=";
local OPERATOR_SMEQTH = "<=";
local OPERATOR_EQUALS = "==";
local OPERATOR_NOTEQUALS = "~=";
local OPERATOR_GRTH = ">";
local OPERATOR_SMTH = "<";
local OPERATOR_SUBSTRACT = "-";
local OPERATOR_ADD = "+";
local OPERATOR_MOD = "%";
local OPERATOR_MULTIPLY = "*";
local OPERATOR_DIVIDE = "/";
local OPERATOR_POWER = "^";
local FUNCNAME_IIF = "IIF";
local FUNCNAME_CALCSTAT = "CALCSTAT";
local FUNCNAME_ABS = "ABS";
local FUNCNAME_CEIL = "CEIL";
local FUNCNAME_FLOOR = "FLOOR";
local FUNCNAME_MAX = "MAX";
local FUNCNAME_MIN = "MIN";
local FUNCNAME_LOG10 = "LOG10";
local FUNCNAME_SQRT = "SQRT";
local FUNCNAME_AFD = "AFD";
local FUNCNAME_FORMAT = "FORMAT";
local FUNCNAME_SWITCH = "SWITCH";
local FUNCNAME_SESEL = "SESEL";
local FUNCNAME_WITH = "WITH";
local FUNCNAME_WHILE = "WHILE";
local FUNCNAME_CHOOSE = "CHOOSE";
local FUNCNAME_REPLACE = "REPLACE";
local FUNCNAME_UNTIL = "UNTIL";

local OPERATIONDEF_ID = 1;
local OPERATIONDEF_FORMAT = 2;
local OPERATIONDEF_FUNCNAME = 3;
local OPERATIONDEF_OPERATOR = 3;

local aOperationDefs = {
						{UNARYOP_LOGICNEG,OPERATION_FORMAT_UNARY,OPERATOR_LOGICNEG},
						{UNARYOP_NEGATE,OPERATION_FORMAT_UNARY,OPERATOR_NEGATE},
						{UNARYOP_POSITIVE,OPERATION_FORMAT_UNARY,OPERATOR_POSITIVE},
						{BINARYOP_CONCAT,OPERATION_FORMAT_BINARY,OPERATOR_CONCAT},
						{BINARYOP_OR,OPERATION_FORMAT_BINARY,OPERATOR_OR},
						{BINARYOP_AND,OPERATION_FORMAT_BINARY,OPERATOR_AND},
						{BINARYOP_GREQTH,OPERATION_FORMAT_BINARY,OPERATOR_GREQTH},
						{BINARYOP_SMEQTH,OPERATION_FORMAT_BINARY,OPERATOR_SMEQTH},
						{BINARYOP_EQUALS,OPERATION_FORMAT_BINARY,OPERATOR_EQUALS},
						{BINARYOP_NOTEQUALS,OPERATION_FORMAT_BINARY,OPERATOR_NOTEQUALS},
						{BINARYOP_GRTH,OPERATION_FORMAT_BINARY,OPERATOR_GRTH},
						{BINARYOP_SMTH,OPERATION_FORMAT_BINARY,OPERATOR_SMTH},
						{BINARYOP_SUBSTRACT,OPERATION_FORMAT_BINARY,OPERATOR_SUBSTRACT},
						{BINARYOP_ADD,OPERATION_FORMAT_BINARY,OPERATOR_ADD},
						{BINARYOP_MOD,OPERATION_FORMAT_BINARY,OPERATOR_MOD},
						{BINARYOP_MULTIPLY,OPERATION_FORMAT_BINARY,OPERATOR_MULTIPLY},
						{BINARYOP_DIVIDE,OPERATION_FORMAT_BINARY,OPERATOR_DIVIDE},
						{BINARYOP_POWER,OPERATION_FORMAT_BINARY,OPERATOR_POWER},
						{FUNCTIONOP_IIF,OPERATION_FORMAT_FUNCTION,FUNCNAME_IIF},
						{FUNCTIONOP_CALCSTAT,OPERATION_FORMAT_FUNCTION,FUNCNAME_CALCSTAT},
						{FUNCTIONOP_ABS,OPERATION_FORMAT_FUNCTION,FUNCNAME_ABS},
						{FUNCTIONOP_CEIL,OPERATION_FORMAT_FUNCTION,FUNCNAME_CEIL},
						{FUNCTIONOP_FLOOR,OPERATION_FORMAT_FUNCTION,FUNCNAME_FLOOR},
						{FUNCTIONOP_MAX,OPERATION_FORMAT_FUNCTION,FUNCNAME_MAX},
						{FUNCTIONOP_MIN,OPERATION_FORMAT_FUNCTION,FUNCNAME_MIN},
						{FUNCTIONOP_LOG10,OPERATION_FORMAT_FUNCTION,FUNCNAME_LOG10},
						{FUNCTIONOP_SQRT,OPERATION_FORMAT_FUNCTION,FUNCNAME_SQRT},
						{FUNCTIONOP_AFD,OPERATION_FORMAT_FUNCTION,FUNCNAME_AFD},
						{FUNCTIONOP_FORMAT,OPERATION_FORMAT_FUNCTION,FUNCNAME_FORMAT},
						{FUNCTIONOP_SWITCH,OPERATION_FORMAT_FUNCTION,FUNCNAME_SWITCH},
						{FUNCTIONOP_SESEL,OPERATION_FORMAT_FUNCTION,FUNCNAME_SESEL},
						{FUNCTIONOP_WITH,OPERATION_FORMAT_FUNCTION,FUNCNAME_WITH},
						{FUNCTIONOP_WHILE,OPERATION_FORMAT_FUNCTION,FUNCNAME_WHILE},
						{FUNCTIONOP_CHOOSE,OPERATION_FORMAT_FUNCTION,FUNCNAME_CHOOSE},
						{FUNCTIONOP_REPLACE,OPERATION_FORMAT_FUNCTION,FUNCNAME_REPLACE},
						{FUNCTIONOP_UNTIL,OPERATION_FORMAT_FUNCTION,FUNCNAME_UNTIL}
						};

local OPPRIOGRP_OPERATIONDEF_IDS = 1;
local OPPRIOGRP_SCANDIRECTION = 2;
local OPPRIOGRP_SCANFORMAT = 3;

local SCANDIRECTION_LEFTRIGHT = 1;
local SCANDIRECTION_RIGHTLEFT = 2;

local ERR_TOOMANYVARIABLES = 1;
local ERR_EXPRESSIONSYNTAX = 2;
local ERR_INVALIDOPCOUNT = 3;
local ERR_INVALIDOPTYPE = 4;
local ERR_OUTOFRANGE = 5;

local aErrMsgs = {
					"Too many variables used",
					"Syntax error",
					"Invalid number of operands",
					"Invalid operand type",
					"Out of range"
					};

-- defines priority process order and scan direction for grouped binary and unary operations
-- same as Lua operation order, highest priority first
-- you can't mix unary and binary operations in the same group: it's either all unary or all binary
local aOperationPriorityGroups = {
									{{BINARYOP_POWER},SCANDIRECTION_RIGHTLEFT,OPERATION_FORMAT_BINARY},
									{{UNARYOP_LOGICNEG,UNARYOP_NEGATE,UNARYOP_POSITIVE},SCANDIRECTION_RIGHTLEFT,OPERATION_FORMAT_UNARY},
									{{BINARYOP_MULTIPLY,BINARYOP_DIVIDE,BINARYOP_MOD},SCANDIRECTION_LEFTRIGHT,OPERATION_FORMAT_BINARY},
									{{BINARYOP_ADD,BINARYOP_SUBSTRACT},SCANDIRECTION_LEFTRIGHT,OPERATION_FORMAT_BINARY},
									{{BINARYOP_CONCAT},SCANDIRECTION_RIGHTLEFT,OPERATION_FORMAT_BINARY},
									{{BINARYOP_SMTH,BINARYOP_GRTH,BINARYOP_SMEQTH,BINARYOP_GREQTH,BINARYOP_NOTEQUALS,BINARYOP_EQUALS},SCANDIRECTION_LEFTRIGHT,OPERATION_FORMAT_BINARY},
									{{BINARYOP_AND},SCANDIRECTION_LEFTRIGHT,OPERATION_FORMAT_BINARY},
									{{BINARYOP_OR},SCANDIRECTION_LEFTRIGHT,OPERATION_FORMAT_BINARY}
									};

-- returns operand number from operand string like 9 from "[9]"
local function OPStonumber(sOPS)
	local sOPn = sOPS:match("^%s*%[(%d+)%]%s*$");
	if sOPn == nil then
		return nil;
	else
		return tonumber(sOPn);
	end
end

-- returns operand string from operand number/string like "[9]" from 9
local function OPNtostring(xOPN)
	if xOPN == nil then
		return nil;
	else
		return "["..xOPN.."]";
	end
end

-- returns index into TRANS_OPERANDS for a given sSource
local function FindOperandBySource(aTranslation,sSource)
	for i, o in pairs(aTranslation[TRANS_OPERANDS]) do
		if o[OPERAND_SOURCE] == sSource then
			return i;
		end
	end
	return nil;
end

-- checks if a variable is in the variable table and returns its index if so
local function FindVariableByName(aTranslation,sName)
	for i, v in pairs(aTranslation[TRANS_VARIABLES]) do
		if v[VAR_NAME] == sName then
			return i;
		end
	end
	return nil;
end

-- returns an index into the Operation Definition table (aOperationDefs) given an Id
local function GetOperationDefById(nDefId)
	for i, d in pairs(aOperationDefs) do
		if d[OPERATIONDEF_ID] == nDefId then
			return i;
		end
	end
	return nil;
end

-- returns an index into the Operation Definition table (aOperationDefs) given a function name
local function GetOperationDefByFunctionName(sName)
	for i, d in pairs(aOperationDefs) do
		if d[OPERATIONDEF_FORMAT] == OPERATION_FORMAT_FUNCTION and d[OPERATIONDEF_FUNCNAME] == sName then
			return i;
		end
	end
	return nil;
end

-- register operand to variables as dependable
local function RegisterOperandWithDependsOn(aTranslation,aDependsOn,nOp)
	local nVar;
	for nVar, _ in pairs(aDependsOn) do
		-- operand depends on this variable
		table.insert(aTranslation[TRANS_VARIABLES][nVar][VAR_OPERANDS],nOp); -- register operand number in variable as dependable
	end
end

-- detects a boolean value in a text, creates an operand for it and returns operand index
-- if the value already exists then it returns the existing operand index
-- pattern matches FALSE, TRUE
local function CreateBooleanConstant(aTranslation,sBoolean)
    local sSource = sBoolean:match("%s*(FALSE)%s*");
	if sSource == nil then
		sSource = sBoolean:match("%s*(TRUE)%s*");
	end
	local nOp = FindOperandBySource(aTranslation,sSource);
	if nOp == nil then
		-- add new operand if not exists yet
		nOp = #aTranslation[TRANS_OPERANDS]+1;
		local aOperand = {};
		aOperand[OPERAND_SOURCE] = sSource;
		aOperand[OPERAND_VALUE] = (sSource == "TRUE"); -- assign value to this static operand
		aOperand[OPERAND_OPERATION] = nil; -- value is not created by an operation
		aOperand[OPERAND_DEPENDSON] = nil; -- doesn't depend on any either down the chain (isn't any)
		aTranslation[TRANS_OPERANDS][nOp] = aOperand;
	end
	return OPNtostring(nOp);
end

-- detects a number value in a text, creates an operand for it and returns operand index
-- if the value already exists then it returns the existing operand index
-- pattern matches the minimal 9 and 9.9 or more digits
local function CreateNumberConstant(aTranslation,sNumber)
    local sSource = sNumber:match("%s*(%d+%.%d+)%s*");
	if sSource == nil then
		sSource = sNumber:match("%s*(%d+)%s*");
	end
	local nOp = FindOperandBySource(aTranslation,sSource);
	if nOp == nil then
		-- add new operand if not exists yet
		nOp = #aTranslation[TRANS_OPERANDS]+1;
		local aOperand = {};
		aOperand[OPERAND_SOURCE] = sSource;
		aOperand[OPERAND_VALUE] = tonumber(sSource); -- assign value to this static operand
		aOperand[OPERAND_OPERATION] = nil; -- value is not created by an operation
		aOperand[OPERAND_DEPENDSON] = nil; -- doesn't depend on any either down the chain (isn't any)
		aTranslation[TRANS_OPERANDS][nOp] = aOperand;
	end
	return OPNtostring(nOp);
end

-- detects a string value in a text, creates an operand for it and returns operand index
-- if the value already exists then it returns the existing operand index
-- pattern matches characters between ""
local function CreateStringConstant(aTranslation,sString)
	local sSource = sString:match("%s*(\".-\")%s*");
	local nOp = FindOperandBySource(aTranslation,sSource);
	if nOp == nil then
		-- add new operand if not exists yet
		nOp = #aTranslation[TRANS_OPERANDS]+1;
		local aOperand = {};
		aOperand[OPERAND_SOURCE] = sSource;
		aOperand[OPERAND_VALUE] = sSource:gsub("\\.",function(sEscapeChar)
					if sEscapeChar == "\\n" then return "\n"
					elseif sEscapeChar == "\\q" then return "\""
					elseif sEscapeChar == "\\\\" then return "\\"
					else return ""
					end
				end):sub(2,-2); -- assign value to this static operand
		aOperand[OPERAND_OPERATION] = nil; -- value is not created by an operation
		aOperand[OPERAND_DEPENDSON] = nil; -- doesn't depend on any either down the chain (isn't any)
		aTranslation[TRANS_OPERANDS][nOp] = aOperand;
	end
	return OPNtostring(nOp);
end

-- extracts string operands out of the expression and replaces them with the operand index indicator '[n]'
local function CreateStringConstants(aTranslation)
	aTranslation[TRANS_EXPRWIP] = aTranslation[TRANS_EXPRWIP]:gsub("\\.",function(sEscapeChar)
					if sEscapeChar == "\\\"" then return "\\q"
					else return sEscapeChar
					end
				end):gsub("%s*\".-\"%s*",function(sString) return CreateStringConstant(aTranslation,sString) end);
end

-- detects a variable in a text, creates an operand for it and returns operand index
-- if an operand for the variable already exists then it returns the existing operand index
-- pattern matches the minimal $A (or with more letters)
-- operand index is registered with the variable's entry in the variable table
-- dependson flag ensures that every operand that uses this operand will also depend on the variable and be registered as such
local function CreateVariableOperand(aTranslation,sVar)
    local sSource = sVar:match("%s*(%$%a+)%s*");
	local nVar = FindVariableByName(aTranslation,sSource);
	if nVar == nil then
		-- add new 'on the fly' variable. inside With function?
		nVar = #aTranslation[TRANS_VARIABLES]+1;
		if nVar > 1000 then
			aTranslation[TRANS_ERRCODE] = ERR_TOOMANYVARIABLES;
			return nil;
		end
		local aVar = {};
		aVar[VAR_NAME] = sSource;
		aVar[VAR_VALUE] = nil; -- initial value
		aVar[VAR_OPERANDS] = {}; -- operands registration table
		aTranslation[TRANS_VARIABLES][nVar] = aVar;
	end
	local nOp = FindOperandBySource(aTranslation,sSource);
	if nOp == nil then
		-- add new operand if not exists yet
		nOp = #aTranslation[TRANS_OPERANDS]+1;
		local aOperand = {};
		aOperand[OPERAND_SOURCE] = sSource;
		aOperand[OPERAND_VALUE] = nil;
		aOperand[OPERAND_OPERATION] = OPERAND_OPERATION_GETVAR; -- value needs to be picked up from variable
		aOperand[OPERAND_DEPENDSON] = {};
		aOperand[OPERAND_DEPENDSON][nVar] = true; -- depends on variable flag
		aTranslation[TRANS_OPERANDS][nOp] = aOperand;
		RegisterOperandWithDependsOn(aTranslation,aOperand[OPERAND_DEPENDSON],nOp); -- register operand with variable(s) it depends on
	end
	return OPNtostring(nOp);
end

-- replaces the short stat notations for the calcstat function, like @STATNAME# etc
-- the short notations will be replaced by the normal CALCSTAT("STATNAME",$L,$N) or more complex
-- while we are at it, any variable operand use for $L/$N implicated or constant number operands detected, are being processed on the fly
local function ReplaceCalcStatShorts(aTranslation)
	local sReplExpr = aTranslation[TRANS_EXPRWIP];
	local aPatterns = {
						{"%s*@(%w+)%s*(%b())%s*(#)%s*(%b())%s*",true,true,true}, -- @a ( $L ) # ( $N ) 
						{"%s*@(%w+)%s*(%b())%s*(#)%s*(%d+%.%d+)%s*",true,true,true}, -- @a ( $L ) # 0.1 
						{"%s*@(%w+)%s*(%b())%s*(#)%s*(%d+)%s*",true,true,true}, -- @a ( $L ) # 1 
						{"%s*@(%w+)%s*(%b())%s*(#)%s*",true,true,false}, -- @a ( $L ) # 
						{"%s*@(%w+)%s*(%b())%s*",true,false,false}, -- @a ( $L ) 
						{"%s*@(%w+)%s*(#)%s*(%b())%s*",false,true,true}, -- @a # ( $N ) 
						{"%s*@(%w+)%s*(#)%s*(%d+%.%d+)%s*",false,true,true}, -- @a # 0.1 
						{"%s*@(%w+)%s*(#)%s*(%d+)%s*",false,true,true}, -- @a # 1 
						{"%s*@(%w+)%s*(#)%s*",false,true,false}, -- @a # 
						{"%s*@(%w+)%s*",false,false,false}, -- @a  
					};
	local nShortStart, nShortEnd, sSN, sL, sHash, sN;
	local nSNLevelStart, nSNLevelEnd, sSNLevel;
	for _, aPattern in pairs(aPatterns) do
		repeat
			if aPattern[2] then
				-- contains level
				nShortStart, nShortEnd, sSN, sL, sHash, sN = sReplExpr:find(aPattern[1]);
			else
				nShortStart, nShortEnd, sSN, sHash, sN = sReplExpr:find(aPattern[1]);
				sL = nil;
			end
			if nShortStart ~= nil then
				if aPattern[2] then
					sL = sL:match("^%(%s*(.-)%s*%)$"); -- remove brackets
				else
					-- test for level in sSN
					nSNLevelStart, nSNLevelEnd, sSNLevel = sSN:find("(%d+)$");
					if nSNLevelStart == nil then
						sL = CreateVariableOperand(aTranslation,"$L"); -- create level variable (or get if already exists)
						if sL == nil then
							break;
						end
					else
						sSN = sSN:sub(1,nSNLevelStart-1); -- first part minus level
						sL = CreateNumberConstant(aTranslation,sSNLevel); -- transform level to number constant
					end
				end
				sSN = CreateStringConstant(aTranslation,"\""..sSN.."\""); -- transform statname to string constant
				if aPattern[3] then
					if aPattern[4] then
						if sN:sub(1,1) == "(" then
							sN = sN:match("^%(%s*(.-)%s*%)$"); -- remove brackets if expression
						else
							sN = CreateNumberConstant(aTranslation,sN); -- transform value for $N to number constant
						end
					else
						sN = CreateVariableOperand(aTranslation,"$N"); -- create N variable (or get if already exists);
						if sN == nil then
							break;
						end
					end
					sReplExpr = sReplExpr:sub(1,nShortStart-1).." CALCSTAT("..sSN..","..sL..","..sN..")"..sReplExpr:sub(nShortEnd+1);
				else
					-- sN = "nil";
					sReplExpr = sReplExpr:sub(1,nShortStart-1).." CALCSTAT("..sSN..","..sL..")"..sReplExpr:sub(nShortEnd+1); -- just leave out $N|$C parameter if default
				end
			end
		until nShortStart == nil
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			break;
		end
	end
	aTranslation[TRANS_EXPRWIP] = sReplExpr;
end

-- removes all variable references from the expression and replaces them with operand identifiers (indexes in operand table)
-- for example "blah blah $TY lefhoihfoe $HIG fslhf" will look like "blah blah [1] lefhoihfoe [2] fslhf"
-- operands with indexes 1 and 2 have then been created in the operand table
local function CreateVariableOperands(aTranslation)
	aTranslation[TRANS_EXPRWIP] = aTranslation[TRANS_EXPRWIP]:gsub("%s*%$%a+%s*",function(sVar) if aTranslation[TRANS_ERRCODE] == 0 then return CreateVariableOperand(aTranslation,sVar) else return sVar end end);
end

-- removes number and boolean constant values from an expression text and replaces them with operand identifiers (indexes in operand table)
-- for example " TRUE , 1.55 " will look something like "[1],[2]"
-- operands with indexes 1 and 2 have then been created in the operand table
local function CreateConstantOperands(aTranslation,sExpression)
	local sReplExpr = sExpression;
	-- booleans
	sReplExpr = sReplExpr:gsub("%s*FALSE%s*",function(sBoolean) return CreateBooleanConstant(aTranslation,sBoolean) end);
	sReplExpr = sReplExpr:gsub("%s*TRUE%s*",function(sBoolean) return CreateBooleanConstant(aTranslation,sBoolean) end);
	-- numbers
	sReplExpr = sReplExpr:gsub("%s*%d+%.%d+%s*",function(sNumber) return CreateNumberConstant(aTranslation,sNumber) end)
	-- problem: numbers without dot in operand references [n]
	sReplExpr = sReplExpr:gsub("(%s*)([^%d]?)(%d+)([^%d]?)(%s*)",function(sStart,sTest1,sNumber,sTest2,sEnd) if not (sTest1 == "[" and sTest2 == "]") then return sStart..sTest1..CreateNumberConstant(aTranslation,sNumber)..sTest2..sEnd else return sStart..sTest1..sNumber..sTest2..sEnd end end); -- just %s*%d+%s* would match n in [n]
	return sReplExpr;
end

local DecomposeExpression;

-- splits an expression into (parameter)parts, based on a splitting token
-- calls a supplied function for each detected part
-- tokens in nested expressions between () are ignored
local function DecomposeParameters(sParams,sSplitToken,fDecomposeParameter)
	local nLevel = 0; -- to keep track of nested ()
	local nCharIndex;
	local nParamIndex = 1; -- points to start position of parameter
	local nLastIndex = sParams:len();
	local sChar;
	local nParam = 0;
	for nCharIndex = 1, nLastIndex do
		sChar = sParams:sub(nCharIndex,nCharIndex);
		if sChar == "(" then
			nLevel = nLevel+1
		elseif sChar == ")" then
			nLevel = nLevel-1
		end
		if nLevel == 0 then
			if sChar == sSplitToken then
				-- we have a parameter when we detect a splitting token at level 0
				nParam = nParam+1;
				fDecomposeParameter(sParams:sub(nParamIndex,nCharIndex-1),nParam,false);
				nParamIndex = nCharIndex+1;
			end
			if nCharIndex == nLastIndex then
				-- last parameter at the end
				fDecomposeParameter(sParams:sub(nParamIndex),nParam+1,true);
			end
		end
	end
end

-- sParams = param1,param2,etc
-- returns an array with operand numbers, containing parameter expression results
local function DecomposeFunctionParameters(aTranslation,sParams)
	-- extract parameters
	local aParamOps = {};

	local DecomposeFunctionParameter = function(sParam,nParam,bIsLastParam)
		if sParam == "" then
			aParamOps[#aParamOps+1] = 999999999; -- empty parameter, might be used for default behaviours
		else
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sParam));
		end
	end
	
	DecomposeParameters(sParams,",",DecomposeFunctionParameter);
	
	return aParamOps;
end

-- transform CASE>=compexpr1:CASE<=compexpr2:..etc:resultexpr
-- expand to: (testexpr>=compexpr1)OR(testexpr<=compexpr2)OR..etc
local function DecomposeCaseConditions(aTranslation,sParams,sTestOp,aParamOps)
	local sCombinedExpr = "";

	local DecomposeCaseCondition = function(sParam,nParam,bIsLastParam)
		if bIsLastParam then
			-- add combined logical expression
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sCombinedExpr));
			-- add last: should be result expression
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sParam));
		else
			-- construct combined logical expression
			local sCompareExpr = sParam:match("^%s*CASE%s*(.-)%s*$");
			if sCombinedExpr ~= "" then
				sCombinedExpr = sCombinedExpr.."OR";
			end
			sCombinedExpr = sCombinedExpr..DecomposeExpression(aTranslation,sTestOp..sCompareExpr);
		end
	end
	
	DecomposeParameters(sParams,":",DecomposeCaseCondition);
end

-- SWITCH(testexpr,CASE>=compexpr1:CASE<=compexpr2:resultexpr1,DEFAULT:resultexpr2)
-- expand to: SWITCH((testexpr>=compexpr1)OR(testexpr<=compexpr2),resultexpr1,True,resultexpr2)
-- parameter results should be like bBoolean1,xValue1,bBoolean2,xValue2,bBoolean3,xValue3,etc
local function DecomposeSwitchParameters(aTranslation,sParams)
	-- extract parameters
	local aParamOps = {};
	local sTestOp;
	
	local DecomposeSwitchParameter = function(sParam,nParam,bIsLastParam)
		if nParam == 1 then
			-- should be test expression
			sTestOp = DecomposeExpression(aTranslation,sParam);
		else
			-- test for CASE or DEFAULT at the start
			if sParam:match("^%s*CASE") ~= nil then
				-- CASE parameter, possibly multiple conditions
				-- CASE>=compexpr1:CASE<=compexpr2:resultexpr1
				DecomposeCaseConditions(aTranslation,sParam,sTestOp,aParamOps);
			elseif sParam:match("^%s*DEFAULT") ~= nil then
				-- default parameter
				-- DEFAULT:resultexpr2
				local sDefaultExpr = sParam:match("^%s*DEFAULT%s*:%s*(.-)%s*$");
				-- add true parameter operand
				aParamOps[#aParamOps+1] = OPStonumber(CreateBooleanConstant(aTranslation,"TRUE"));
				-- add default result parameter operand
				aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sDefaultExpr));
			end
		end
	end
	
	DecomposeParameters(sParams,",",DecomposeSwitchParameter);
	
	return aParamOps;
end

-- var1=varexpr1, var2=varexpr2, etc.
-- expand to: varcount, var1, varexpr1, var2, varexpr2, etc.
local function DecomposeVarAssignments(aTranslation,sParams,aParamOps)
	local nVarCountOpIdx = #aParamOps+1;
	aParamOps[nVarCountOpIdx] = -1; -- reserve position for assignment count

	local DecomposeVarAssignment = function(sParam,nParam,bIsLastParam)
		local sVar, sVarExpr = sParam:match("^%s*(%[%d+%])%s*=%s*(.-)%s*$"); -- variable should already be an operand
		if sVar ~= nil and sVarExpr ~= nil then
			-- add variable operand
			aParamOps[#aParamOps+1] = OPStonumber(sVar);
			-- add assigned expression
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sVarExpr));
		end
	end
	
	DecomposeParameters(sParams,",",DecomposeVarAssignment);

	-- store variable assignment count
	aParamOps[nVarCountOpIdx] = OPStonumber(CreateNumberConstant(aTranslation,""..((#aParamOps-nVarCountOpIdx)/2)));
end

-- WITH(var1=varexpr1, var2=varexpr2, etc. : resultexpr)
-- expand to: WITH(varcount, var1, varexpr1, var2, varexpr2, etc. , resultexpr)
-- parameter results should be like a pair for each variable assignment plus one result operand at the end
local function DecomposeWithParameters(aTranslation,sParams)
	-- extract parameters
	local aParamOps = {};

	local DecomposeWithParameter = function(sParam,nParam,bIsLastParam)
		if nParam == 1 then
			-- should be variable assignments
			DecomposeVarAssignments(aTranslation,sParam,aParamOps);
		elseif bIsLastParam then
			-- should be the result expression
			-- add result parameter operand
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sParam));
		end
	end
	
	DecomposeParameters(sParams,":",DecomposeWithParameter);

	return aParamOps;
end

-- WHILE(initvar1=varexpr1, initvar2=varexpr2, etc. : loopconditionexpr : loopvar1=varexp1, loopvar2=varexp2, etc. : resultexpr)
-- expand to: WHILE(initvarcount, initvar1, initvarexpr1, initvar2, initvarexpr2, etc. , loopconditionexpr, loopvarcount, loopvar1, loopvarexpr1, loopvar2, loopvarexpr2, etc. , resultexpr)
-- UNTIL(initvar1=varexpr1, initvar2=varexpr2, etc. : loopvar1=varexp1, loopvar2=varexp2, etc. : loopconditionexpr : resultexpr)
-- expand to: UNTIL(initvarcount, initvar1, initvarexpr1, initvar2, initvarexpr2, etc., loopvarcount, loopvar1, loopvarexpr1, loopvar2, loopvarexpr2, etc. , loopconditionexpr , resultexpr)
-- parameter results should be like a pair for each variable assignment plus one operand for loopcondition and one for result at the end
local function DecomposeLoopParameters(aTranslation,sParams,bPreCondition)
	-- extract parameters
	local aParamOps = {};

	local DecomposeLoopParameter = function(sParam,nParam,bIsLastParam)
		if nParam == 1 then
			-- should be initial variable assignments
			DecomposeVarAssignments(aTranslation,sParam,aParamOps);
		elseif (nParam == 2 and bPreCondition) or (nParam == 3 and not bPreCondition) then
			-- should be loop condition expression
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sParam));
		elseif (nParam == 3 and bPreCondition) or (nParam == 2 and not bPreCondition) then
			-- should be loop variable assignments
			DecomposeVarAssignments(aTranslation,sParam,aParamOps);
		elseif bIsLastParam then
			-- should be the result expression
			-- add result parameter operand
			aParamOps[#aParamOps+1] = OPStonumber(DecomposeExpression(aTranslation,sParam));
		end
	end
	
	DecomposeParameters(sParams,":",DecomposeLoopParameter);

	return aParamOps;
end

local function GetSourceParameterOperands(aParamOps)
	local sSource = "";
	for i, nOp in pairs(aParamOps) do
		if sSource ~= "" then
			sSource = sSource..",";
		end
		if nOp ~= nil then
			sSource = sSource..OPNtostring(nOp);
		end
	end
	return sSource;
end

local ExecuteOperation;
local function CreateOperation(aTranslation,sSource,nOperationDef,aParamOps)
	-- test if a result not yet exists for this source
	local nResultOp = FindOperandBySource(aTranslation,sSource);
	if nResultOp == nil then
		-- compose combined dependson for these operands
		local aDependsOn;
		local aOpDependsOn;
		if aParamOps ~= nil then
			local nOp;
			local nVar;
			for _, nOp in pairs(aParamOps) do
				if nOp ~= nil then
					aOpDependsOn = aTranslation[TRANS_OPERANDS][nOp][OPERAND_DEPENDSON];
					if aOpDependsOn ~= nil then
						if aDependsOn == nil then
							aDependsOn = {};
						end
						for nVar, _ in pairs(aOpDependsOn) do
							aDependsOn[nVar] = true;
						end
					end
				end
			end
		end

		-- create result operand
		nResultOp = #aTranslation[TRANS_OPERANDS]+1;
		local aOperand = {};
		aOperand[OPERAND_SOURCE] = sSource;
		aOperand[OPERAND_VALUE] = nil;
		aOperand[OPERAND_OPERATION] = nil;
		aOperand[OPERAND_DEPENDSON] = aDependsOn;
		aTranslation[TRANS_OPERANDS][nResultOp] = aOperand;
		if aDependsOn ~= nil then
			RegisterOperandWithDependsOn(aTranslation,aDependsOn,nResultOp); -- register operand with variable(s) it depends on
		end

		-- create the operation
		local aOperation = {};
		aOperation[OPERATION_DEFINITION] = nOperationDef;
		aOperation[OPERATION_OPERANDS] = aParamOps;
		aOperation[OPERATION_RESULTOP] = nResultOp;

		if aDependsOn == nil then
			-- does not depend on any variable, so operand values should be all constants
			-- calculate constant value now and don't store operation after
			ExecuteOperation(aTranslation,aOperation);
		else
			-- depends on variable(s), so operation needs to be stored, but not executed now
			local nResultOperation = #aTranslation[TRANS_OPERATIONS]+1;
			aTranslation[TRANS_OPERANDS][nResultOp][OPERAND_OPERATION] = nResultOperation; -- register operation in operand
			aTranslation[TRANS_OPERATIONS][nResultOperation] = aOperation; -- store in operation table
		end
	end
	return nResultOp;
end

-- sName = name of function like CALCSTAT, LINFMOD, etc.
-- sParams = param1,param2,etc (normally)
-- parameters need to be extracted and each treated like an expression (which should return a result in an operand)
-- an operation for this function needs to be created, which takes a list of operands (the parameters) and gives a result in an operand
local function DecomposeFunction(aTranslation,sName,sParams)
	-- get function definition
	local nOperationDef = GetOperationDefByFunctionName(sName);
	if nOperationDef == nil then
		-- unknown function
		return nil;
	end

	-- get an array with parameter operand numbers
	local aParamOps;
	local nFunctionOp = aOperationDefs[nOperationDef][OPERATIONDEF_ID];
	if nFunctionOp == FUNCTIONOP_SWITCH then
		aParamOps = DecomposeSwitchParameters(aTranslation,sParams); -- Switch($L, case<=10: case>=100: 25, default: 13)
	elseif nFunctionOp == FUNCTIONOP_WITH then
		aParamOps = DecomposeWithParameters(aTranslation,sParams); -- With($A=@Agility#2, $B=20: IIf($A>$B,$A,$B))
	elseif nFunctionOp == FUNCTIONOP_WHILE then
		aParamOps = DecomposeLoopParameters(aTranslation,sParams,true);
	elseif nFunctionOp == FUNCTIONOP_UNTIL then
		aParamOps = DecomposeLoopParameters(aTranslation,sParams,false);
	else
		aParamOps = DecomposeFunctionParameters(aTranslation,sParams); -- sName(operand1, operand2, etc.)
	end

	-- compose funcname([n],[n],etc) as source identifier
	local sSource = sName.."("..GetSourceParameterOperands(aParamOps)..")";

	-- create an operation for this function (returns result operand number)
	local nResultOp = CreateOperation(aTranslation,sSource,nOperationDef,aParamOps);

	return OPNtostring(nResultOp);
end

local function DecomposeFunctions(aTranslation,sExpression)
	return sExpression:gsub("%s*(%a+%w*)%s*(%b())%s*",function(sName,sParams) return DecomposeFunction(aTranslation,sName,sParams:sub(2,-2)) end);
end

local function DecomposeParantheses(aTranslation,sExpression)
	return sExpression:gsub("%s*(%b())%s*",function(sNestedExpr) return DecomposeExpression(aTranslation,sNestedExpr:sub(2,-2)) end);
end

-- separate binary and unary operators
-- like "+" and "-" from "+-" (like from the source "1+-2") or
-- like "or" and "not" from "ornot" (like from the source "true or not false")
-- should contain one or no binary operators, but can contain multiple unary operators
-- bSearchBinary: if false then only do unary operators
local function ReadOperatorElements(sOperators, bSearchBinary)
	sTempOps = sOperators;
	local aOperators = {};
	local nFoundOpLen;
	local nTestLen;

	local nBinaryOpId = nil;
	if bSearchBinary then
		-- find the longest matching binary operator from the left
		nFoundOpLen = 0;
		for _, d in pairs(aOperationDefs) do
			if d[OPERATIONDEF_FORMAT] == OPERATION_FORMAT_BINARY then
				nTestLen = d[OPERATIONDEF_OPERATOR]:len();
				if (nTestLen > nFoundOpLen) and (sTempOps:sub(1,nTestLen) == d[OPERATIONDEF_OPERATOR]) then
					nBinaryOpId = d[OPERATIONDEF_ID];
					nFoundOpLen = nTestLen;
				end
			end
		end
		if nFoundOpLen > 0 then
			-- remove found binary operator from operators
			sTempOps = sTempOps:sub(nFoundOpLen+1);
			sTempOps = sTempOps:match("%s*(.*)"); -- remove leading whitespace
		end
	end
	aOperators[1] = nBinaryOpId;
	
	local aUnaryOpIds = nil;
	local nUnaryOpId;
	while sTempOps ~= nil and sTempOps ~= "" do
		-- find the longest matching unary operator from the left
		nUnaryOpId = nil;
		nFoundOpLen = 0;
		for _, d in pairs(aOperationDefs) do
			if d[OPERATIONDEF_FORMAT] == OPERATION_FORMAT_UNARY then
				nTestLen = d[OPERATIONDEF_OPERATOR]:len();
				if (nTestLen > nFoundOpLen) and (sTempOps:sub(1,nTestLen) == d[OPERATIONDEF_OPERATOR]) then
					nUnaryOpId = d[OPERATIONDEF_ID];
					nFoundOpLen = nTestLen;
				end
			end
		end
		if nFoundOpLen > 0 then
			if aUnaryOpIds == nil then
				aUnaryOpIds = {};
			end
			aUnaryOpIds[#aUnaryOpIds+1] = nUnaryOpId;
			-- remove found unary operator from operators
			sTempOps = sTempOps:sub(nFoundOpLen+1);
			sTempOps = sTempOps:match("%s*(.*)"); -- remove leading whitespace
		else
			-- didn't find any - just break off
			break;
		end
	end
	aOperators[2] = aUnaryOpIds;
	
	return aOperators;
end

-- create a table of Elements out of an expression
-- an operand Element wil contain the operand id value
-- an operators Element wil contain a table of 2 items:
-- [1]: binary operator id value
-- [2]: table of unary operator id values
local function ReadExpressionElements(sExpression)
	local sTempExpr = "!"..sExpression.."!"; -- add some character to start and end for pattern matching
	local sBinaryOpEndSearch = "^(.*)%[(%d+)%]%s*(.-)%s*%[(%d+)%](.-)$"; -- find match at the end
	local sUnaryOpStartSearch = "^(!)%s*(.-)%s*%[(%d+)%](.-)$"; -- find match at the start
	local aElements = {};
	local sPre, sFoundOperand1, sFoundOperator, sFoundOperand2, sPost;

	sPre, sFoundOperand1, sFoundOperator, sFoundOperand2, sPost = sTempExpr:match(sBinaryOpEndSearch);
	while sFoundOperator ~= nil do
		aElements[1] = tonumber(sFoundOperand1); -- 1 is always last operand1 index number found
		table.insert(aElements,2,tonumber(sFoundOperand2)); -- store second operand index number
		table.insert(aElements,2,ReadOperatorElements(sFoundOperator,true)); -- operator may be combination of binary and unary operators
		-- remove operand2 and operator(s) from search expression
		sTempExpr = sPre..OPNtostring(sFoundOperand1)..sPost;
		sPre, sFoundOperand1, sFoundOperator, sFoundOperand2, sPost = sTempExpr:match(sBinaryOpEndSearch);
	end

	-- we might have a unary operation left at the start like in the expression "NOT true or false"
	sPre, sFoundOperator, sFoundOperand1, sPost = sTempExpr:match(sUnaryOpStartSearch);
	if sFoundOperator ~= "" then
		table.insert(aElements,1,ReadOperatorElements(sFoundOperator,false)); -- operator must be a one or more unary operators
		if sPre == nil then
			sTempExpr = "";
		else
			sTempExpr = sPre;
		end
		if #aElements == 1 then
			-- no operand yet for this unary, so get it
			table.insert(aElements,2,tonumber(sFoundOperand1));
		else
			sTempExpr = sTempExpr..OPNtostring(sFoundOperand1);
		end
		if sPost ~= nil then
			sTempExpr = sTempExpr..sPost;
		end
	end

	return aElements;
end

local function FindBinaryOperationInPrioGroup(aElements,nElemIndex,aGroupOperatorDefIds)
	local aCombinedOperators = aElements[nElemIndex];
	if type(aCombinedOperators) == "table" then
		local nBinaryOperator = aCombinedOperators[1];
		local nGroupOperationDefId;
		for _, nGroupOperationDefId in pairs(aGroupOperatorDefIds) do
			if nGroupOperationDefId == nBinaryOperator then
				return nBinaryOperator;
			end
		end
	end
	return nil;
end

local function ProcessUnaryOperations(aTranslation,aElements,nElemIndex,aGroupOperatorDefIds,nScanDirection)
	local aCombinedOperators = aElements[nElemIndex];
	local bRemoveElement = false;
	if type(aCombinedOperators) == "table" then
		local aUnaryOperators = aCombinedOperators[2];
		if type(aUnaryOperators) == "table" then
			-- has unary operators
			local nCurrentUnary, nStartUnary, nEndUnary, nUnaryStep;
			local nUnaryOperator;
			local nGroupOperationDefId;
			local nOperationDef;
			local aParamOps;
			local sSource;
			local nResultOp;

			if nScanDirection == SCANDIRECTION_RIGHTLEFT then
				nStartUnary = #aUnaryOperators;
				nEndUnary = 1;
				nUnaryStep = -1;
			elseif nScanDirection == SCANDIRECTION_LEFTRIGHT then
				nStartUnary = 1;
				nEndUnary = #aUnaryOperators;
				nUnaryStep = 1;
			end

			nCurrentUnary = nStartUnary;
			repeat
				nUnaryOperator = aUnaryOperators[nCurrentUnary];
				for _, nGroupOperationDefId in pairs(aGroupOperatorDefIds) do
					if nGroupOperationDefId == nUnaryOperator then
						-- process found unary operator
						nOperationDef = GetOperationDefById(nGroupOperationDefId);

						aParamOps = {aElements[nElemIndex+1]};
						sSource = aOperationDefs[nOperationDef][OPERATIONDEF_OPERATOR]..OPNtostring(aParamOps[1]);

						-- create an operation for this unary operation (returns result operand number)
						nResultOp = CreateOperation(aTranslation,sSource,nOperationDef,aParamOps);

						-- replace source operand with result operand
						aElements[nElemIndex+1] = nResultOp;
					
						-- remove processed unary operator from unary operators
						table.remove(aUnaryOperators,nCurrentUnary);
						if nScanDirection == SCANDIRECTION_LEFTRIGHT then
							nCurrentUnary = nCurrentUnary-1;
							nEndUnary = nEndUnary-1;
						end
						
						break;
					end
				end
				nCurrentUnary = nCurrentUnary+nUnaryStep;
			until (nScanDirection == SCANDIRECTION_LEFTRIGHT and nCurrentUnary > nEndUnary) or (nScanDirection == SCANDIRECTION_RIGHTLEFT and nCurrentUnary < nEndUnary)
			
			if #aUnaryOperators == 0 then
				aCombinedOperators[2] = nil;
				bRemoveElement = (aCombinedOperators[1] == nil);
			else
				aCombinedOperators[2] = aUnaryOperators;
			end
			aElements[nElemIndex] = aCombinedOperators;
		end
	end
	return bRemoveElement;
end

local function ProcessBinaryOperation(aTranslation,aElements,nElemIndex,aGroupOperatorDefIds)
	local aCombinedOperators = aElements[nElemIndex];
	local bRemoveElement = false;
	if type(aCombinedOperators) == "table" then
		local nBinaryOperator = aCombinedOperators[1];
		if type(nBinaryOperator) == "number" then
			-- has binary operator
			local nOperationDef;
			local aParamOps;
			local sSource;
			local nResultOp;
			
			nOperationDef = GetOperationDefById(nBinaryOperator);
			
			aParamOps = {aElements[nElemIndex-1],aElements[nElemIndex+1]};
			sSource = OPNtostring(aParamOps[1])..aOperationDefs[nOperationDef][OPERATIONDEF_OPERATOR]..OPNtostring(aParamOps[2]);

			-- create an operation for this binary operation (returns result operand number)
			nResultOp = CreateOperation(aTranslation,sSource,nOperationDef,aParamOps);
			
			aCombinedOperators[1] = nil;
			aElements[nElemIndex-1] = nResultOp;
			aElements[nElemIndex] = aCombinedOperators;
			aElements[nElemIndex+1] = nResultOp;
			
			bRemoveElement = true;
		end
	end
	return bRemoveElement;
end

local function CreateExpressionFromElements(aElements)
	local sResult = "";
	local nOperationDef;
	for _, e in pairs(aElements) do
		if type(e) == "number" then
			-- operand number
			sResult = sResult..OPNtostring(e);
		elseif type(e) == "table" then
			if e[1] ~= nil then
				-- binary operatordefid
				nOperationDef = GetOperationDefById(e[1]);
				sResult = sResult..aOperationDefs[nOperationDef][OPERATIONDEF_OPERATOR];
			end
			if e[2] ~= nil then
				-- unary operatordefid(s)
				for _, o in pairs(e[2]) do
					nOperationDef = GetOperationDefById(o);
					sResult = sResult..aOperationDefs[nOperationDef][OPERATIONDEF_OPERATOR];
				end
			end
		end
	end
	return sResult;
end

local function CreateOperations(aTranslation,sExpression)
	local aElements = ReadExpressionElements(sExpression);
	local aOperationPriorityGroup;
	local aOperationDefIds;
	local nScanDirection;
	local nScanFormat;
	local nCurrentElem, nStartElem, nEndElem, nElemStep;
	local nBinaryOperatorId;

	for _, aOperationPriorityGroup in pairs(aOperationPriorityGroups) do
		aOperationDefIds = aOperationPriorityGroup[OPPRIOGRP_OPERATIONDEF_IDS]; -- need to search for these IDs
		nScanDirection = aOperationPriorityGroup[OPPRIOGRP_SCANDIRECTION]; -- from which direction to search
		nScanFormat = aOperationPriorityGroup[OPPRIOGRP_SCANFORMAT]; -- search binary or unary operations
		
		if nScanDirection == SCANDIRECTION_RIGHTLEFT then
			nStartElem = #aElements-1; -- last Element should be operand, so just before are first operators
			nEndElem = 1; -- last operator Element should be either 1 (only unary) or 2 (ending with binary/unary)
			nElemStep = -2; -- skip an operand and an operator(s) Element to the left
		elseif nScanDirection == SCANDIRECTION_LEFTRIGHT then
			if type(aElements[1]) == "number" then
				-- Element 1 operand, 2 operator(s), etc
				nStartElem = 2;
			else
				-- Element 1 unary operator, 2 operand, 3 operator(s) etc
				if nScanFormat == OPERATION_FORMAT_BINARY then
					nStartElem = 3; -- skip unary operator at the start
				elseif nScanFormat == OPERATION_FORMAT_UNARY then
					nStartElem = 1; -- start with the unary operator at 1
				end
			end
			nEndElem = #aElements-1; -- last Element should be an operand, so just before
			nElemStep = 2; -- skip an operand and an operator(s) Element to the right
		end

		nCurrentElem = nStartElem;
		repeat
			if nScanFormat == OPERATION_FORMAT_BINARY then
				nBinaryOperatorId = FindBinaryOperationInPrioGroup(aElements,nCurrentElem,aOperationDefIds);
				if nBinaryOperatorId ~= nil then
					-- found a binary operation which is in current priority group
					
					-- right to left ^: -[2]^-[3]^+[4] -> -[2]^-([3]^+[4]) -> (-([2]^(-([3]^(+[4])))))
					-- left to right *: -[2]*-[3]*+[4] -> ((-[2])*(-[3]))*+[4] -> (((-[2])*(-[3]))*(+[4]))

					-- always process all unaries (if still any) before processing the binary operation
					ProcessUnaryOperations(aTranslation,aElements,nCurrentElem,aOperationPriorityGroups[2][OPPRIOGRP_OPERATIONDEF_IDS],SCANDIRECTION_RIGHTLEFT); --group 2 contains the unary operations

					if ProcessBinaryOperation(aTranslation,aElements,nCurrentElem,nBinaryOperatorId) then
						-- should remove operation Element if here
						-- this means that binary has been processed and should be removed
						table.remove(aElements,nCurrentElem); -- remove operation
						table.remove(aElements,nCurrentElem); -- remove operand2
						if nScanDirection == SCANDIRECTION_LEFTRIGHT then
							nCurrentElem = nCurrentElem-2;
							nEndElem = nEndElem-2;
						end
					end
				end
			elseif nScanFormat == OPERATION_FORMAT_UNARY then
				if ProcessUnaryOperations(aTranslation,aElements,nCurrentElem,aOperationDefIds,nScanDirection) then
					-- should remove operation Element if here
					-- this means that the unary at the start has been processed and can now be removed
					table.remove(aElements,nCurrentElem); -- remove operation
					if nScanDirection == SCANDIRECTION_LEFTRIGHT then
						nCurrentElem = nCurrentElem-1;
						nEndElem = nEndElem-1;
					end
				end
			end
			nCurrentElem = nCurrentElem+nElemStep;
		until (nScanDirection == SCANDIRECTION_LEFTRIGHT and nCurrentElem > nEndElem) or (nScanDirection == SCANDIRECTION_RIGHTLEFT and nCurrentElem < nEndElem)
	end

	return CreateExpressionFromElements(aElements);
end

-- recursive function which decomposes (parts of) an expression
function DecomposeExpression(aTranslation,sExpression)

	if aTranslation[TRANS_ERRCODE] ~= 0 then
		-- error state: don't continue
		return sExpression;
	end

	local nResultOp;
	local sTempExpr = sExpression;
	
	while true do
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			break;
		end
	
		-- contains only [n] ?
		nResultOp = OPStonumber(sTempExpr);
		if nResultOp ~= nil then
			-- expression already contains final result (in operand)
			sTempExpr = OPNtostring(nResultOp);
			break;
		end
	
		-- process functions funcname(expr1,expr2,expr3,..)
		sTempExpr = DecomposeFunctions(aTranslation,sTempExpr);
	
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			-- error state: don't continue
			break;
		end
		-- contains only [n] ?
		nResultOp = OPStonumber(sTempExpr);
		if nResultOp ~= nil then
			-- result is from a single function
			sTempExpr = OPNtostring(nResultOp);
			break;
		end
	
		-- process parantheses (expr)
		sTempExpr = DecomposeParantheses(aTranslation,sTempExpr);
	
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			-- error state: don't continue
			break;
		end
		-- contains only [n] ?
		nResultOp = OPStonumber(sTempExpr);
		if nResultOp ~= nil then
			-- result is from a single nested ()
			sTempExpr = OPNtostring(nResultOp);
			break;
		end
	
		-- create operands from remaining constant types (number, boolean)
		-- not sooner because of possible numbers in function names
		sTempExpr = CreateConstantOperands(aTranslation,sTempExpr);
	
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			-- error state: don't continue
			break;
		end
		-- contains only [n] ?
		nResultOp = OPStonumber(sTempExpr);
		if nResultOp ~= nil then
			--- result is from a single constant
			sTempExpr = OPNtostring(nResultOp);
			break;
		end
	
		sTempExpr = CreateOperations(aTranslation,sTempExpr);

		if aTranslation[TRANS_ERRCODE] ~= 0 then
			-- error state: don't continue
			break;
		end
		-- contains only [n] ?
		nResultOp = OPStonumber(sTempExpr);
		if nResultOp ~= nil then
			-- result is from simple operations
			sTempExpr = OPNtostring(nResultOp);
			break;
		end

		-- here when not finalized completely because of a syntax error.
		aTranslation[TRANS_ERRCODE] = ERR_EXPRESSIONSYNTAX;
		break;
	end

	return sTempExpr;
end

-- translates an expression to an intermediate object, given a definition of runtime variables.
-- resulting object may be evaluated/executed (see ExecuteExpression()), while providing runtime variables with values.
function TranslateExpression(sExpression,aVariables)

	-- basic initialization of translation object
	local aTranslation = {};
	aTranslation[TRANS_EXPRESSION] = sExpression; -- Original expression which translation will represent
	aTranslation[TRANS_EXPRWIP] = sExpression; -- expression work in progress: expression in various states of translation
	aTranslation[TRANS_ERRCODE] = 0; -- indicating errors during translation or execution
	aTranslation[TRANS_OPERATIONS] = {}; -- Operations table
	aTranslation[TRANS_OPERANDS] = {}; -- Operands table
	aTranslation[TRANS_VARIABLES] = {}; -- Variables table

	-- populate variable table with supplied variables
	local aTransVars = aTranslation[TRANS_VARIABLES];
	for i, v in pairs(aVariables) do
		aTransVars[i] = {};
		aTransVars[i][VAR_NAME] = "$"..v[VAR_NAME]:upper();
		aTransVars[i][VAR_VALUE] = v[VAR_VALUE]; -- initial value
		aTransVars[i][VAR_OPERANDS] = {}; -- operands registration table
	end

	-- create operands for string constants
	CreateStringConstants(aTranslation);

	-- convert expression to uppercase now we have processed the strings
	aTranslation[TRANS_EXPRWIP] = aTranslation[TRANS_EXPRWIP]:upper();
	
	-- replace CalcStat shorts: @StatName etc with function call expressions
	ReplaceCalcStatShorts(aTranslation);
	
	-- create operands for variables
	CreateVariableOperands(aTranslation);

	-- extract operations - returns "[n]", with indicating operand index n containing the final result
	aTranslation[TRANS_EXPRWIP] = DecomposeExpression(aTranslation,aTranslation[TRANS_EXPRWIP]);
		
	return aTranslation;
end

local function GetOperandValue(aTranslation,nOp)
	local aOperand = aTranslation[TRANS_OPERANDS][nOp];
	
	if aOperand[OPERAND_VALUE] == nil then
		-- need to get the value from an operation (a constant would always have a value)
		if aOperand[OPERAND_OPERATION] == OPERAND_OPERATION_GETVAR then
			-- need to get value from variable (DependsOn should contain only 1 variable reference)
			local nVar;
			for nVar, _ in pairs(aOperand[OPERAND_DEPENDSON]) do
				-- operand depends on this variable
				aOperand[OPERAND_VALUE] = aTranslation[TRANS_VARIABLES][nVar][VAR_VALUE];
				break;
			end
		else
			-- we should get the value when we execute its operation
			ExecuteOperation(aTranslation,aTranslation[TRANS_OPERATIONS][aOperand[OPERAND_OPERATION]]);
		end
	end
	
	return aOperand[OPERAND_VALUE];
end

local adjustfordisplay;
local stringformatvalue;

-- executes a loop operation with pre-condition (While) or post-condition (Until)
local function ExecuteLoopOperation(aTranslation,aOperation,bPreCondition)
	local aOperands = aOperation[OPERATION_OPERANDS];

	if #aOperands < 4 then
		aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
		return;
	end

	local xExprValue;

	-- process initial variable assignments
	local nInitVarCount = GetOperandValue(aTranslation,aOperands[1]);
	local nInitVarOpIdx = 2;
	for nInitVarIdx = 1, nInitVarCount do
		xExprValue = GetOperandValue(aTranslation,aOperands[nInitVarOpIdx+1]);
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			return;
		end
		SetExpressionVariable(aTranslation,aTranslation[TRANS_OPERANDS][aOperands[nInitVarOpIdx]][OPERAND_SOURCE],xExprValue);
		nInitVarOpIdx = nInitVarOpIdx+2;
	end

	-- init indexes
	local nLoopCondOpIdx;
	local nLoopVarCount;
	local nLoopVarOpIdxInit;
	local nResultingOpIdx;
	
	if bPreCondition then
		nLoopCondOpIdx = nInitVarOpIdx;
		nLoopVarCount = GetOperandValue(aTranslation,aOperands[nInitVarOpIdx+1]);
		nLoopVarOpIdxInit = nInitVarOpIdx+2;
		nResultingOpIdx = nInitVarOpIdx+2+nLoopVarCount*2;
	else
		nLoopVarCount = GetOperandValue(aTranslation,aOperands[nInitVarOpIdx]);
		nLoopCondOpIdx = nInitVarOpIdx+nLoopVarCount*2+1;
		nLoopVarOpIdxInit = nInitVarOpIdx+1;
		nResultingOpIdx = nLoopCondOpIdx+1;
	end

	local nLoopVarOpIdx;

	local nLoops = 0; -- counter for limiting number of loops
	while nLoops < 1000 do
		if bPreCondition then
			-- process pre-loop condition
			xExprValue = GetOperandValue(aTranslation,aOperands[nLoopCondOpIdx]);
			if not (type(xExprValue) == "boolean" or type(xExprValue) == "number") then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
				return;
			end
			if not xExprValue then
				break; -- end if false
			end
		end
			
		-- process loop variable assignments
		nLoopVarOpIdx = nLoopVarOpIdxInit;
		for nLoopVarIdx = 1, nLoopVarCount do
			xExprValue = GetOperandValue(aTranslation,aOperands[nLoopVarOpIdx+1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			SetExpressionVariable(aTranslation,aTranslation[TRANS_OPERANDS][aOperands[nLoopVarOpIdx]][OPERAND_SOURCE],xExprValue);
			nLoopVarOpIdx = nLoopVarOpIdx+2;
		end
		nLoops = nLoops+1;

		if not bPreCondition then
			-- process post-loop condition
			xExprValue = GetOperandValue(aTranslation,aOperands[nLoopCondOpIdx]);
			if not (type(xExprValue) == "boolean" or type(xExprValue) == "number") then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
				return;
			end
			if xExprValue then
				break; -- end if true
			end
		end
	end

	-- process result
	local xExprValue = GetOperandValue(aTranslation,aOperands[nResultingOpIdx]);
	if aTranslation[TRANS_ERRCODE] ~= 0 then
		return;
	end
	
	return xExprValue;
end

-- executes a single operation and stores the outcome in a (intermediate) result operand
function ExecuteOperation(aTranslation,aOperation)
	local aOperationDef = aOperationDefs[aOperation[OPERATION_DEFINITION]];
	local nOpDefId = aOperationDef[OPERATIONDEF_ID];
	local nOpDefFormat = aOperationDef[OPERATIONDEF_FORMAT];
	local aOperands = aOperation[OPERATION_OPERANDS];
	local nOperandCount = #aOperands;
	local xOperand1, xOperand2, xOperand3;
	local xResult;
	
	if aTranslation[TRANS_ERRCODE] ~= 0 then
		return;
	end
	
	if nOpDefFormat == OPERATION_FORMAT_UNARY then
		if nOperandCount ~= 1 then
			aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
			return;
		end
		xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			return;
		end
		if nOpDefId == UNARYOP_LOGICNEG then
			-- logic negate
			if type(xOperand1) == "boolean" or type(xOperand1) == "number" then 
				xResult = (not xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == UNARYOP_NEGATE then
			-- number negate
			if type(xOperand1) == "number" then 
				xResult = -xOperand1;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == UNARYOP_POSITIVE then
			-- number positive
			if type(xOperand1) == "number" then 
				xResult = xOperand1; -- just copy
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		end
	elseif nOpDefFormat == OPERATION_FORMAT_BINARY then
		if nOperandCount ~= 2 then
			aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
			return;
		end
		xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			return;
		end
		xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
		if aTranslation[TRANS_ERRCODE] ~= 0 then
			return;
		end
		if nOpDefId == BINARYOP_CONCAT then
			-- concatenate 2 operands into a string (first need to be a string)
			if (type(xOperand1) == "boolean" or type(xOperand1) == "number" or type(xOperand1) == "string") and (type(xOperand2) == "boolean" or type(xOperand2) == "number" or type(xOperand2) == "string") then 
				if type(xOperand1) == "boolean" then
					if xOperand1 then
						xOperand1 = "True";
					else
						xOperand1 = "False";
					end
				end
				if type(xOperand2) == "boolean" then
					if xOperand2 then
						xOperand2 = "True";
					else
						xOperand2 = "False";
					end
				end
				xResult = xOperand1..""..xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_OR then
			if (type(xOperand1) == "boolean" or type(xOperand1) == "number") and (type(xOperand2) == "boolean" or type(xOperand2) == "number") then 
				xResult = (xOperand1 or xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_AND then
			if (type(xOperand1) == "boolean" or type(xOperand1) == "number") and (type(xOperand2) == "boolean" or type(xOperand2) == "number") then 
				xResult = (xOperand1 and xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_GREQTH then
			if (type(xOperand1) == "number" and type(xOperand2) == "number") or (type(xOperand1) == "string" and type(xOperand2) == "string") then 
				xResult = (xOperand1 >= xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_SMEQTH then
			if (type(xOperand1) == "number" and type(xOperand2) == "number") or (type(xOperand1) == "string" and type(xOperand2) == "string") then 
				xResult = (xOperand1 <= xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_EQUALS then
			xResult = (xOperand1 == xOperand2);
		elseif nOpDefId == BINARYOP_NOTEQUALS then
			xResult = (xOperand1 ~= xOperand2);
		elseif nOpDefId == BINARYOP_GRTH then
			if (type(xOperand1) == "number" and type(xOperand2) == "number") or (type(xOperand1) == "string" and type(xOperand2) == "string") then 
				xResult = (xOperand1 > xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_SMTH then
			if (type(xOperand1) == "number" and type(xOperand2) == "number") or (type(xOperand1) == "string" and type(xOperand2) == "string") then 
				xResult = (xOperand1 < xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_SUBSTRACT then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 - xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_ADD then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 + xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_MOD then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 % xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_DIV then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = math.floor(xOperand1 / xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_MULTIPLY then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 * xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_DIVIDE then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 / xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == BINARYOP_POWER then
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = xOperand1 ^ xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		end
	elseif nOpDefFormat == OPERATION_FORMAT_FUNCTION then
		if nOpDefId == FUNCTIONOP_IIF then
			if nOperandCount ~= 3 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if (type(xOperand1) == "boolean" or type(xOperand1) == "number") then 
				if xOperand1 then
					xResult = GetOperandValue(aTranslation,aOperands[2]);
				else
					xResult = GetOperandValue(aTranslation,aOperands[3]);
				end
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_CALCSTAT then
			if nOperandCount < 1 or nOperandCount > 3 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xOperand2 = nil;
			xOperand3 = nil;
			if nOperandCount >= 2 then
				xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
				if nOperandCount == 3 then
					xOperand3 = GetOperandValue(aTranslation,aOperands[3]);
					if aTranslation[TRANS_ERRCODE] ~= 0 then
						return;
					end
				end
			end
			if (type(xOperand1) == "string") and (type(xOperand2) == "nil" or type(xOperand2) == "number") then 
				if xOperand3 == nil then
					xResult = CalcStat(xOperand1,xOperand2);
				else
					xResult = CalcStat(xOperand1,xOperand2,xOperand3);
				end
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_ABS then
			if nOperandCount ~= 1 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xResult = math.abs(xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_CEIL then
			if nOperandCount ~= 1 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xResult = math.ceil(xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_FLOOR then
			if nOperandCount ~= 1 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xResult = math.floor(xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_MAX then
			if nOperandCount ~= 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = math.max(xOperand1,xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_MIN then
			if nOperandCount ~= 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" and type(xOperand2) == "number" then 
				xResult = math.min(xOperand1,xOperand2);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_LOG10 then
			if nOperandCount ~= 1 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xResult = math.log10(xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_SQRT then
			if nOperandCount ~= 1 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xResult = math.sqrt(xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_AFD then
			if nOperandCount < 1 or nOperandCount > 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if nOperandCount == 2 then
				xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
			else
				xOperand2 = "CORR"; --default: 0.0002 correction
			end
			if type(xOperand2) == "string" then 
				xResult = adjustfordisplay(xOperand2,xOperand1,nil);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_FORMAT then
			if nOperandCount < 1 or nOperandCount > 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if nOperandCount == 2 then
				xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
			elseif type(xOperand1) == "number" then
				xOperand2 = "%.0f"; --default: number without decimals
			elseif type(xOperand1) == "string" then
				xOperand2 = "%s"; --default: just same string
			end
			if (type(xOperand1) == "number" or type(xOperand1) == "string") and (type(xOperand2) == "string") then 
				xResult = stringformatvalue(xOperand2,xOperand1);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_SWITCH then
			local nOp;
			for nOp = 1, nOperandCount, 2 do
				-- process logical + result operand pairs
				-- default logical is a constant true, so will always be the result once encountered
				if nOp+1 > nOperandCount then
					aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
					return;
				end
				xOperand1 = GetOperandValue(aTranslation,aOperands[nOp]);
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
				if type(xOperand1) == "boolean" then
					if xOperand1 then
						xOperand2 = GetOperandValue(aTranslation,aOperands[nOp+1]);
						if aTranslation[TRANS_ERRCODE] ~= 0 then
							return;
						end
						xResult = xOperand2;
						break;
					end
				else
					aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
					break;
				end
			end
		elseif nOpDefId == FUNCTIONOP_SESEL then
			if nOperandCount < 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then
				 -- compare number value minus a little for small discrepancies
				 -- like 79.0000001 should be treated like 79 so <= 79
				xOperand1 = xOperand1-DblCalcDev;
			end
			if (type(xOperand1) == "number" or type(xOperand1) == "string") then 
				local nOp;
				for nOp = 2, nOperandCount, 2 do
					xOperand2 = GetOperandValue(aTranslation,aOperands[nOp]);
					if aTranslation[TRANS_ERRCODE] ~= 0 then
						return;
					end
					if nOp == nOperandCount then
						-- last operand is default value
						xResult = xOperand2;
					else
						if (type(xOperand1) == "number" and type(xOperand2) == "number") or (type(xOperand1) == "string" and type(xOperand2) == "string") then
							if xOperand1 <= xOperand2 then
								xOperand3 = GetOperandValue(aTranslation,aOperands[nOp+1]);
								if aTranslation[TRANS_ERRCODE] ~= 0 then
									return;
								end
								xResult = xOperand3;
								break;
							end
						else
							aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
							break;
						end
					end
				end
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_WITH then
			if nOperandCount < 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			local nOp;
			for nOp = 2, nOperandCount, 2 do
				if nOp == nOperandCount then
					-- last operand is result value
					xOperand1 = GetOperandValue(aTranslation,aOperands[nOp]);
					if aTranslation[TRANS_ERRCODE] ~= 0 then
						return;
					end
					xResult = xOperand1;
				else
					-- process variable assignments
					xOperand2 = GetOperandValue(aTranslation,aOperands[nOp+1]);
					if aTranslation[TRANS_ERRCODE] ~= 0 then
						return;
					end
					SetExpressionVariable(aTranslation,aTranslation[TRANS_OPERANDS][aOperands[nOp]][OPERAND_SOURCE],xOperand2);
				end
			end
		elseif nOpDefId == FUNCTIONOP_WHILE then
			xOperand1 = ExecuteLoopOperation(aTranslation,aOperation,true);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xResult = xOperand1;
		elseif nOpDefId == FUNCTIONOP_CHOOSE then
			if nOperandCount < 2 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "number" then 
				xOperand1 = math.floor(xOperand1+0.5+DblCalcDev);
				if xOperand1 < 1 or xOperand1 > nOperandCount-1 then
					aTranslation[TRANS_ERRCODE] = ERR_OUTOFRANGE;
					return;
				end
				xOperand2 = GetOperandValue(aTranslation,aOperands[1+xOperand1]);
				if aTranslation[TRANS_ERRCODE] ~= 0 then
					return;
				end
				xResult = xOperand2;
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_REPLACE then
			if nOperandCount < 3 then
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPCOUNT;
				return;
			end
			xOperand1 = GetOperandValue(aTranslation,aOperands[1]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xOperand2 = GetOperandValue(aTranslation,aOperands[2]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xOperand3 = GetOperandValue(aTranslation,aOperands[3]);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			if type(xOperand1) == "string" and type(xOperand2) == "string" and type(xOperand3) == "string" then
				local sSearch = xOperand2:gsub("[%(%)%.%%%+%-%*%?%[%^%$%]]","%%%1");
				local sReplace = xOperand3:gsub("%%","%%%%");
				xResult = xOperand1:gsub(sSearch,sReplace);
			else
				aTranslation[TRANS_ERRCODE] = ERR_INVALIDOPTYPE;
			end
		elseif nOpDefId == FUNCTIONOP_UNTIL then
			xOperand1 = ExecuteLoopOperation(aTranslation,aOperation,false);
			if aTranslation[TRANS_ERRCODE] ~= 0 then
				return;
			end
			xResult = xOperand1;
		end
	end
	
	-- store result in result operand
	aTranslation[TRANS_OPERANDS][aOperation[OPERATION_RESULTOP]][OPERAND_VALUE] = xResult;
end

-- execute translated expression and return result
function ExecuteExpression(aTranslation)
	if aTranslation[TRANS_ERRCODE] ~= 0 then
		return "ErrCode:"..aTranslation[TRANS_ERRCODE];
	end
	-- return result from last created operand
	local xResultValue = GetOperandValue(aTranslation,#aTranslation[TRANS_OPERANDS]);
	if aTranslation[TRANS_ERRCODE] ~= 0 then
		return "ErrCode:"..aTranslation[TRANS_ERRCODE];
	end
	return xResultValue;
end

-- sets a variable to a value and nullifies depending operands' values, so they'll be recalculated at execution time
function SetExpressionVariable(aTranslation,sVarName,xNewValue)
	local sSearchVar;
	if sVarName:sub(1,1) == "$" then
		sSearchVar = sVarName:upper();
	else
		sSearchVar = "$"..sVarName:upper();
	end
	local aVar, xOldValue, bNew;
	for _, aVar in pairs(aTranslation[TRANS_VARIABLES]) do
		if aVar[VAR_NAME] == sSearchVar then
			xOldValue = aVar[VAR_VALUE];
			if type(xOldValue) ~= type(xNewValue) then
				bNew = true;
			else
				bNew = (xOldValue ~= xNewValue);
			end
			if bNew then
				-- store new value
				aVar[VAR_VALUE] = xNewValue;
				-- nullify registered operands values
				local aTransOperands = aTranslation[TRANS_OPERANDS];
				local nOp;
				for _, nOp in pairs(aVar[VAR_OPERANDS]) do
					-- sets value of registered operand to nil
					aTransOperands[nOp][OPERAND_VALUE] = nil;
				end
				return xOldValue;
			end
			return nil;
		end
	end
	return nil;
end

function GetExpressionError(aTranslation)
	if aTranslation[TRANS_ERRCODE] == 0 then
		return 0, nil, nil;
	else
		return aTranslation[TRANS_ERRCODE], aErrMsgs[aTranslation[TRANS_ERRCODE]], aTranslation[TRANS_EXPRWIP];
	end
end

-- to be used by other modules
p.TranslateExpression = TranslateExpression;
p.ExecuteExpression = ExecuteExpression;
p.SetExpressionVariable = SetExpressionVariable;
p.GetExpressionError = GetExpressionError;

-- ************************ End CalcStat Expressions **************************

-- ******************** Start Formatting/Display Support **********************

-- small number correction for display purposes only (like in-game)
local function correctvalue(nValue)

	if nValue < -DblCalcDev then
		return nValue-0.0002
	elseif nValue > DblCalcDev then
		return nValue+0.0002
	else
		return 0
	end

end

-- uses template Worth to output value(format ..ggggssscc) as currency (..gggg gold sss silver cc copper)
local function currencyvalue(nValue,frame)

	local nTemp = math.floor(nValue+0.5+DblCalcDev);
	local nCopper = nTemp%100;
	nTemp = (nTemp-nCopper)/100;
	local nSilver = nTemp%1000;
	nTemp = (nTemp-nSilver)/1000;
	local nGold = nTemp;
	
	local aTemplateArgs;
	if nGold > 0 then
		aTemplateArgs = {g=nGold,s=nSilver,c=nCopper};
	elseif nSilver > 0 then
		aTemplateArgs = {s=nSilver,c=nCopper};
	else
		aTemplateArgs = {c=nCopper};
	end

	return frame:expandTemplate{title="Worth",args=aTemplateArgs};

end

function adjustfordisplay(sOption,xValue,frame)

	local xTemp = xValue;

	if type(xTemp) == "number" then
		-- optional display options for percentages
		-- for display purposes only (same as in-game)
		if sOption == "MULTIP" then
			-- multiplier percentage
			xTemp = correctvalue(xTemp-100);
		elseif sOption == "MULTIP100" then
			-- multiplier percentage & multiply by 100
			xTemp = correctvalue(xTemp*100-100);
		elseif sOption == "ADDP" then
			-- additive percentage
			xTemp = correctvalue(xTemp);
		elseif sOption == "ADDP100" then
			-- additive percentage & multiply by 100
			xTemp = correctvalue(xTemp*100);
		elseif sOption == "WORTH" then
			-- currency display
			if frame ~= nil then
				xTemp = currencyvalue(xTemp,frame);
			end
		elseif sOption == "CORR" then
			-- fractured value which needs a correction for rounded display
			xTemp = correctvalue(xTemp);
		elseif sOption == "NOADJ" then
			-- no adjustment
		end
	end

	return xTemp;

end

local function AddCommas(pre,post) return pre..post:reverse():gsub("(%d%d%d)","%1"..","):reverse(); end
local function SplitDecimal(str) return str:gsub("^(%d)(%d+)",AddCommas); end
local function ReformatThousSep(str) return str:gsub("[%d%.]+",SplitDecimal); end

-- adds trailing zero removal option (set minimum precision): %.0.3f
-- adds thousand separator option to formatting: %'d
function stringformatvalue(sFormat,xValue)

	if type(xValue) == "number" then
		local sPreFormat = sFormat;

		local bPostThousSep = string.find(sPreFormat,"%%'");
		if bPostThousSep then
			sPreFormat = string.gsub(sPreFormat,"%%'","%%");
		end

		local bPostFormatTrailZeroes = string.find(sPreFormat,".%d+.%d+%a");
		local nTrailZeroesMinPrec;

		if bPostFormatTrailZeroes then
			local _, _, sTrailZeroesMinPrec = string.find(sPreFormat,".(%d+).%d+%a");
			nTrailZeroesMinPrec = tonumber(sTrailZeroesMinPrec);
			sPreFormat = string.gsub(sPreFormat,".%d+(.%d+%a)","%1");
		end

		local sPostFormat = string.format(sPreFormat,xValue);

		if bPostFormatTrailZeroes then
			local sTrailZeroesGetDecimals = "%d+(.%d+)";
			local sTrailZeroesSetDecimals = "(%d+).%d+";
			local _, _, sDotDecimals = string.find(sPostFormat,sTrailZeroesGetDecimals);

			while sDotDecimals ~= nil and string.len(sDotDecimals) > nTrailZeroesMinPrec+1 and string.sub(sDotDecimals,-1,-1) == "0" do
				sDotDecimals = string.sub(sDotDecimals,1,-2);
			end

			if sDotDecimals == "." then
				sPostFormat = string.gsub(sPostFormat,sTrailZeroesSetDecimals,"%1");
			elseif sDotDecimals ~= nil then
				sPostFormat = string.gsub(sPostFormat,sTrailZeroesSetDecimals,"%1"..sDotDecimals);
			end
		end

		if bPostThousSep then
			sPostFormat = ReformatThousSep(sPostFormat);
		end

		return sPostFormat;
	else
		return string.format(sFormat,xValue);
	end
	
end

-- ********************* End Formatting/Display Support ***********************

-- ********************** from here EXTRA for Wiki use ************************

-- to be called by #invoke
function p.calc(frame)

	local result;
	local bUseExpression = false;
	local sSN, nL, xNorC, nN, sC;

	-- test for stat name or expression
	if type(frame.args[1]) == "string" then
		sSN = string.match(frame.args[1],"^%s*(-?%a+%d*%a+)%s*$"); -- allow nested digits in stat name and a starting -
		if sSN == nil then
			sSN = string.match(frame.args[1],"^%s*(-?%a+)%s*$"); -- to allow single character stat name
			if sSN == nil then
				bUseExpression = true;
			end
		end
	else
		return "Missing stat name";
	end
	
	-- convert string parameters for L and N to numbers
	if type(frame.args[2]) ~= "nil" then
		if type(tonumber(frame.args[2])) == "number" then
			-- level
			nL = tonumber(frame.args[2]);
		end
	end
	if type(frame.args[3]) ~= "nil" then
		if type(tonumber(frame.args[3])) == "number" then
			-- optional N
			xNorC = tonumber(frame.args[3]);
			nN = xNorC;
		else
			-- optional C
			xNorC = frame.args[3];
			sC = xNorC;
		end
	end

	if bUseExpression then
		-- function did not get a valid stat name
		-- try for an expression instead
		result = ExecuteExpression(TranslateExpression(frame.args[1],{{"L",nL},{"N",nN},{"C",sC}}));
		if type(result) == "boolean" then
			if result then
				result = "True";
			else
				result = "False";
			end
		end
	else
		result = CalcStat(sSN,nL,xNorC);
	end

	-- display option. default = "CORR" for numbers.
	local sStatDisplay = "";
	if type(result) == "number" then
		sStatDisplay = "CORR";
	end
	if type(frame.args[5]) ~= "nil" then
		if frame.args[5] ~= "" then
			sStatDisplay = string.upper(frame.args[5]);
		end
	end
	if sStatDisplay ~= "" then
		result = adjustfordisplay(sStatDisplay,result,frame);
	end
	
	-- optional format string. default = "%.0f" for numbers.
	local sStatFormat = "";
	if type(result) == "number" then
		if bUseExpression then
			sStatFormat = "%.0f";
		else
			sSN = string.upper(sSN);
			if sSN == "SKILLPOWERCOST" then
				sStatFormat = "%'.0f"; -- fractured number with thousand separator format by default
			elseif sSN == "ICMR" or sSN == "ICPR" or sSN == "NCMR" or sSN == "NCPR" or sSN == "POWER" or sSN == "VIRTJUSTICEICMR" or sSN == "VIRTPATIENCEPOWER" then
				sStatFormat = "%.0.3f"; -- fractured number with up to 3 decimals
			else
				sStatFormat = "%.0f";
			end
		end
	end
	if type(frame.args[4]) ~= "nil" then
		if frame.args[4] ~= "" then
			sStatFormat = frame.args[4];
		end
	end
	if sStatFormat ~= "" then
		result = stringformatvalue(sStatFormat,result);
	end

	return result;

end

return p