Module:CalcStat
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
- Format: optional format string. Default for number results is %.0f. See also Printf_format_string.
- Assuming a value of 12345.016:
- %'d displays a thousand separated number for main stats (whole numbers; rounded down when fractured) like: 12,345
- %'+d displays a thousand separated number for main stats (whole numbers; rounded down when fractured) with a forced sign like: +12,345
- %.0f (default) displays a number for rating stats (fractured numbers; normal rounding to given precision 0 decimals) like: 12345
- %+.0f displays a number for rating stats (fractured numbers; normal rounding to given precision 0 decimals) with a forced sign like: +12345
- %'.1f displays a thousand separated number for DPS (fractured numbers; normal rounding to given precision 1 decimal) like: 12,345.0
- %'.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
- %'.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:
- AddP: Display Additive Percentage (with a 0.0002 correction).
- AddP100: Mutltiply by 100 & display as Additive Percentage (with a 0.0002 correction).
- MultiP: Display Multiplier Percentage (with a 0.0002 correction).
- MultiP100: Mutltiply by 100 & display as Multiplier Percentage (with a 0.0002 correction).
- Worth: Displays value in gold/silver/copper (from number value in format ..ggggssscc).
- Corr: Correction. 0.0002 is added to any number (this is the default for numbers).
- 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.
|
|
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.
|
|
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.
|
|
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.
|
|
- ↑ 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: |
|
Position 2: |
|
Position 3: |
|
---|
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: |
|
Position 2: |
|
Position 3: |
|
---|
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