Thanks to the efforts of the development team, a dedicated and engaged group of players, and especially DarkGod, ToME is an amazingly well balanced game across a wide range of race/class combinations and a range of scenarios. Starting with ToME development version SVN 6783 (for release version 1.0.5) improved "infinite" scaling methods have been applied to most talents and many game mechanics. The objective of the new changes is to project current game balance ahead into higher character/difficulty levels, the upcoming Orc Campaign, and beyond.

This guide is intended to be an introduction to the scaling methods for developers of ToME (including both official content and addons). It describes the math and functional support recently added to ToME (previously used in the Infinite 500 add-on) which enables the character level limit to be increased from 50 to more than 500. Most of this material can be applied directly to other modules as well.

The balance considerations needed to accomplish this are pretty simple. From most to least important they are:

I. Don't break anything. (Keep the game running.)

It's no good if it doesn't work. For any conceivable range of talent levels, stats, and other character attributes, you don't want the game to crash. The most common problems of this sort are things like negative talent cool-downs, speeds, or other properties that have to be positive, divide by zero errors (in lua, you usually get inf or nan, which just pushes the error away from where the problem originates), or bad scaling that can overpower or obviate core game mechanics and result in strange behavior. The t-engine and the ToME module are pretty robust and tolerant of many coding errors, but nonsense results must still be avoided.

II. Maintain fairness. (Provide a consistent challenge.)

Make sure that individual talents or combinations of abilities don't become over- or under-powered at various points in the game. ToME accommodates a wide range of play styles because of the diverse range of abilities that are balanced with respect to each other. While there is considerable variation in effectiveness of various builds (race/class combinations) and the talent selections that go with them (which also supports more play styles), it is possible, if not easy, to clear the entire Maj'Eyal campaign with virtually any of them.

To make this happen, the effectiveness of core game mechanics must scale consistently. That is, things like damage output, resistances, health, resources (and recovery), etc. must be of similar effectiveness across a variety of builds from level 1 onwards. This means, among other things, that an archmage and a berserker of similar level, using similar quality equipment, and played with equivalent skill can produce fairly similar amounts of damage (even if the mage is better at AOE and the berzerker is better at focused damage) and have similar survivability (the berserker is tougher and can recover more quickly, but the mage is better at avoiding damage).

III. Provide continuous improvement. (Reward character progress.)

Character development is a tenet of RPG game design. It's what makes games like ToME so engaging (addictive) and have great replayability. ToME excels at this because of all of the choice available to the player on how to develop a character including 26 classes, over 1,000 individually programmed unique talents, and strongly player-directed character development.

To maintain this choice going forward, the game must support character improvment with investment in as wide a range character attributes as possible. For example, the Weapon Mastery talent steadily improves damage at all talent levels. On the other hand, the Hide In Plain Sight and Unseen Actions talents previously (ToME 1.0.4) had a flat % chance of success that increased in equal increments with talent level. 100% success chance was reached at about talent level 9 or 10, and then there there was no room for further improvement. The scaling changes replace this mechanic with an opposed skill system that rewards talent investment with a skill multiplier that is countered by the various detection and sensing abilities of enemys. As a result, investment in these skills is useful far past the previous limits.

Scaling Factors:

To provide consistent scaling, scaling factors (formula exponents) were chosen with which to guide improvement of various characteristics with character level and to stay consistent with existing game code and values. This applies equally to both players and NPC's, since all actors in ToME use the same game mechanics. Consistent with a diminishing returns philosophy, none of these factors are greater than 1.0:

**Code:**

Scaling factors (with character level)

Attribute Power

Health/Damage* 1.0 (consistent scaling here is the objective of the other scaling factors)

Duration 0.5

Range/Radius 0.5

Damage Multipliers 0.5 (some exceptions)

Crit multiplier 0.75

Armour/APR 0.5-0.75 (except armor training @ 1.0)

Attack/Defense** 0.75-1.0 (some exceptions)

Raw Saves/Power** 0.75-1.0

Speed 0.75

Stat bonus/penalty 0.5-1.0 (0.75)

Resistances/reduction 0.5 (except thick skin, note caps and penetration)

Stealth/Invis 1.0 (includes detection)

Effect removal log (includes talents limited by the number of targets)

Crit rate/penalty 0.5-0.75

Resource recovery 0.75

*Health actually has a small tl^2 component, and damage can be greatly affected by equipment.

** These directly opposed values have an extra scaling step (rescaleCombatStats) designed to keep values from diverging too much.

The core of this system requires that both character health (and most resources in general) and offensive ability (damage) scale more or less in proportion to character level. That is, advancing a character to twice its level will result in it having around twice as many hit points and it will deal approximately twice as much damage (everything else being equal).

The duration of most talent effects, on the other hand, is proportional to the square root (0.5 power) of character level. So, if a character keeps investing in a typical talent while going from level 10 to level 40 the talent duration will increase by a factor of 2x. There are exceptions to this, of course.

Tiered scaling:

Some of the scaling factors have a range of powers. These characteristics are scaled in tiers in order to maintain competitive play balance between opposed abilities. For example, armor from the Armor Training skill, which almost every class has access to, scales in proportion to character level (1.0 power with talent level) in order to keep pace with melee damage, which also scales in proportion to character level. Other abilities that affect this balance (addional armor talents like Stoneskin (0.5 power with talent level) or armor piercing talents like Deadly Strikes (0.5 power with Cunning)) scale more slowly than the base because they can provide a strong differential advantage for or against this balance and are not available to all characters.

Reference Characters:

The new scaling changes are designed to maintain the previous game balance as much as possible. It is assumed that a character invests as heavily as possible in the appropriate talent and stats and takes into account a few properties of ToME's leveling system. Once higher character levels are reached, the maximum (raw) talent level that can be learned is level/10 and the maximum (base) stat that can be trained is level + 10. So talent levels and stats are both proportional to character level also.

When matching the new formulas to the old, two standard reference characters were chosen:

**Code:**

STARTING CHARACTER HIGH LEVEL CHARACTER

Level 1 Level 50

Primary stats 10 Primary stats 100

Talent Mastery 1.0 Talent Mastery 1.0

Talent level 1.0 (effective) Talent level 5.0 (effective)

The stats for the level 50 reference are typical for an end game character on normal difficulty in the Maj'Eyal campaign and were given priority when matching existing talent values. When considering the Stealth talent, for example, an end game character was assumed to be level 50, with 100 Cunning (including the base stat and 40 bonus points from equipment and other sources) and to have an effective talent level of 5.0. While every character is different (Many classes have 1.3 talent mastery for their core talents.), deviations from the old formulas for characters similar to the reference characters, particularly the end game character, are small.

As an example, using the original formula for stealth (power = 4 + 0.1 * Cunning * Talent Level), the hypothetical starting reference character would have a stealth power of 5, and the high level character would have 54. The old formula calculated stealth power in proportion to the square of character level, since both maximum Cunning and maximum Talent Level are proportional to character level and they are multiplied together. The new formula (computed in a lua call like power = combatScale(Cunning * Talent Level, 5, 1, 54, 50), see the expanation of the scaling functions below) takes the square root of Cunning * Talent Level (so 1.0 power with character level) and scales this value so that when Cunning * Talent Level = 1, stealth power is 5 and when it's 50, stealth power is 54.

Limits:

In a number of places, characteristics are subject to limits. Limits are needed primarily to keep certain characteristics within bounds, like preventing total invulnerability to status effects, or to limit talent effects that could break game scaling from other sources. Some of the more important issues include (with some examples):

Speed reduction cannot create negative speeds. (Cripple, Thorn Grab. There are also some hard limits that prevent negative speeds as well to prevent game breaking bugs.)

No negative cooldowns. (Supercharge Golem, Rush - can get to zero with other talents and equipment, but has a substantial stamina cost.)

Most absolute status immunities, like stun, confusion, pinning, knockback, etc., are limited to less than 100%, at least for a single talent. (Shield Wall, Relentless)

Some activated abilities with a lasting effect cannot have a duration longer than the cooldown. These include most instant use talents (many racial abilities) since otherwise they could be kept up continuously like a sustained skill, and certain very powerful effects that can unbalance the game if they are kept up continuously (Unstoppable, Paradox Clone, Adrenalin Surge).

Resistance penetration (from a single talent) is limited to less than 100%. (Wildfire, Vulnerability Poison)

Core stat multipliers. (Battle Shout <50% extra life, Greater Weapon Focus <100% chance, effectively a damage multiplier)

Healing and damge penalties are limited to less than < 100% to prevent overpowering too many NPC's, which may not have an offsetting bonus. (Curse of Impotence, Insidious Poison)

Function Support for Scaling:

As of SVN 6783 for release version 1.0.5, new functions have been added to Combat.lua in order to make scaling much easier to manage. These include scaling functions and limit functions. To use these functions in addons prior to ToME 1.0.5's release you can superload them:

Attachment:

Combat.txt [7.66 KiB]
Downloaded 110 times
(change the extension to .lua)

Scaling functions:

These functions are designed to manage diminishing returns effects. One is for talents and the other is for raw stats, but they both employ a variation of the same formula:

f(x) = m*(x + shift)^power + b + add)

where shift, power, and add are inputs, and m and b are internally computed to match desired values.

**Code:**

-- Compute a diminishing returns value based on talent level that scales with a power

-- t = talent def table or a numeric value

-- low = value to match at talent level 1

-- high = value to match at talent level 5

-- power = scaling factor (default 0.5) or "log" for log10

-- add = amount to add the result (default 0)

-- shift = amount to add to the talent level before computation (default 0)

-- raw if true specifies use of raw talent level

function _M:combatTalentScale(t, low, high, power, add, shift, raw)

-- Compute a diminishing returns value based on a stat value that scales with a power

-- stat = "str", "con",.... or a numeric value

-- low = value to match when stat = 10

-- high = value to match when stat = 100

-- power = scaling factor (default 0.5) or "log" for log10

-- add = amount to add the result (default 0)

-- shift = amount to add to the stat value before computation (default 0)

function _M:combatStatScale(stat, low, high, power, add, shift)

To use these, you specify two values you want to match, and the function computes a curve passing through those points using the power you specified. The power is either a number, usually less than 1 (default 0.5), or "log," which sets the kind of curve to use. Then, the point on the curve corresponding to the first argument is found and returned as the result.

For combatTalentScale the first argument is either the talent definition table (from which the talent level is determined) or a number. The high and low arguments correspond to the values you want to match for effective talent levels 1.0 and 5.0. The add argument is added after the computation. The shift argument adjusts talent level up or down before computing the curve. This allows for better matching of desired values in between the points specified, and generally has the effect of straightening out the curve, like fitting the part of the curve to the right by the specified amount.

This function never returns negative values, but otherwise always returns low + add for talent level 1.0 and high + add for talent level 5.0.

The combatStatScale function is very similar, except that the first value is a stat abbreviation ("str", "dex", "mag", "wil", "cun", "con") or the stat value to use, and the high and low arguments correspond to stat values of 10 and 100 respectively.

Examples:

self:combatTalentScale(t, 1, 7)

This function computes a power curve (with default power 0.5) passing through the points (1, 1) and (5, 7). Using self as the actor with the talent, this takes the talent definition table, t, and returns 1 if the talent level is 1 and 7 if the talent level is 5. For (effective) talent levels {1, 2, 3, 4, 5, 10} it returns:

{1.00, 3.01, 4.55, 5.85, 7.00, 11.50}

self:combatTalentScale(t, 1, 7, 0.75)

As before, but uses power = 0.75 and returns:

{1.00, 2.75, 4.28, 5.68, 7.00, 12.84}

self:combatTalentScale(t, 1, 7, "log")

Uses a logarithmic scale, returning:

{1.00, 3.58, 5.10, 6.17, 7.00, 9.58}

self:combatTalentScale(t, 1, 7, 0.5, 2)

Adds 2 to the first result, returning:

{3.00, 5.01, 6.55, 7.85, 9.00, 13.50}

self:combatTalentScale(t, 1, 7, 0.5, 0, 10)

Uses the straighter part of the first curve, shifting the references "to the right" by 10, returning:

{1.00, 2.59, 4.12, 5.58, 7.00, 13.46}

The differences in these curves are obvious in the following plot:

Attachment:

ToMEScalingPlot1.jpg [ 80.02 KiB | Viewed 3974 times ]
Limit functions:

These functions are designed to allow for a gradual (smooth) progression from values you specify towards a limit that cannot be passed. There is one for talents and another for stats that use the same default base values as the scaling functions. The formula used is a variation of:

f(x) = (limit-b)*x/(x + h) + b

where b and h ("add" and "halfpoint" in the lua code) are computed to match the high and low values specified. Note that the function reaches the midpoint of its range when x = h.

**Code:**

-- Compute a diminishing returns value based on talent level that cannot go beyond a limit

-- t = talent def table or a numeric value

-- limit = value approached as talent levels increase

-- high = value at talent level 5

-- low = value at talent level 1 (optional)

-- raw if true specifies use of raw talent level

-- returns (limit - add)*TL/(TL + halfpoint) + add == add when TL = 0 and limit when TL = infinity

-- TL = talent level, halfpoint and add are internally computed to match the desired high/low values

-- note that the progression low->high->limit must be monotone, consistently increasing or decreasing

function _M:combatTalentLimit(t, limit, low, high, raw)

-- Compute a diminishing returns value based on a stat value that cannot go beyond a limit

-- stat == "str", "con",.... or a numeric value

-- limit = value approached as talent levels increase

-- high = value to match when stat = 100

-- low = value to match when stat = 10 (optional)

-- returns (limit - add)*stat/(stat + halfpoint) + add == add when STAT = 0 and limit when stat = infinity

-- halfpoint and add are internally computed to match the desired high/low values

-- note that the progression low->high->limit must be monotone, consistently increasing or decreasing

function _M:combatStatLimit(stat, limit, low, high)

For combatTalentLimit, the first argument is either the talent definition table (from which the talent level is determined) or a number. The limit argument is the value that is approached as talent levels increase, but that cannot be reached. The low and high arguments are the desired values corresponding to (effective) talent levels 1.0 and 5.0 respectively. To get meaningful results, if high > low, make sure limit > high and visa versa.

combatStatLimit is similar, except that the first argument is a stat abbreviation or a number, and the high and low values correspond to stat values of 100 and 10 respectively.

Examples:

Calling

self:combatStatLimit("dex", 100, 30, 85)

causes the function to compute an increasing curve passing through the points (10, 30) and (100, 85) that is always less than 100, look up the value of the Dexterity stat and then find the corresponding point on the curve (the return value). For dex values of {10, 25, 50, 75, 100, 250}, the following values are returned:

{30.00, 56.55, 73.38, 80.81, 85.00, 93.51}

Conversely, calling

self:combatStatLimit("wil", 0, 50, 15)

on the same values for Willpower computes a curve that is always more than 0, and returns the following values:

{50.00, 36.00, 24.55, 18.62, 15.00, 6.92}

The functions used by these calls are illustrated in the following graph

Attachment:

ToMEScalingPlot2.jpg [ 106.52 KiB | Viewed 3974 times ]
Generic functions:

**Code:**

-- Scale a value up or down by a power

-- x = a numeric value

-- y_low = value to match at x_low

-- y_high = value to match at x_high

-- power = scaling factor (default 0.5)

-- add = amount to add the result (default 0)

-- shift = amount to add to the input value before computation (default 0)

function _M:combatScale(x, y_low, x_low, y_high, x_high, power, add, shift)

-- Scale a value up or down subject to a limit

-- x = a numeric value

-- limit = value approached as x increases

-- y_high = value to match at when x = x_high

-- y_low (optional) = value to match when x = x_low

-- returns (limit - add)*x/(x + halfpoint) + add (= add when x = 0 and limit when x = infinity), halfpoint, add

-- halfpoint and add are internally computed to match the desired high/low values

-- note that the progression low->high->limit must be monotone, consistently increasing or decreasing

function _M:combatLimit(x, limit, y_low, x_low, y_high, x_high)

These functions work in the same way as the stat and talent scale and limit functions above, but make no assumptions about the points to match. Both x and y values at two points are required arguments to specify the curve to be used, which passes through (x_low, y_low) and (x_high, y_high).

Negative values are valid results for combatScale and the power, if specified, must be a numeric argument ("log" cannot be specified).

Integrated Example: Converting a talent to use infinite scaling

To illustrate the use of the new scaling methods, here is a step-by-step example of how the Scoundrel Strategies talent was modified. This talent has a number of effects when being attacked by or when attacking bleeding enemies. The starting talent definition is (for ToME 1.0.4):

**Code:**

newTalent{

name = "Scoundrel's Strategies", short_name = "SCOUNDREL",

type = {"cunning/scoundrel", 2},

require = cuns_req2,

mode = "passive",

points = 5,

getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)/2) end,

getMovePenalty = function(self, t) return (5 + self:combatTalentStatDamage(t, "cun", 10, 30)) / 100 end,

getAttackPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

getWillPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

getCunPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

do_scoundrel = function(self, t, target)

if not rng.percent(5+(self:getTalentLevel(t)*3)) then return end

if rng.percent(50) then

if target:hasEffect(target.EFF_DISABLE) then return end

target:setEffect(target.EFF_DISABLE, t.getDuration(self, t), {speed=t.getMovePenalty(self, t), atk=t.getAttackPenalty(self, t), apply_power=self:combatAttack()})

else

if target:hasEffect(target.EFF_ANGUISH) then return end

target:setEffect(target.EFF_ANGUISH, t.getDuration(self, t), {will=t.getWillPenalty(self, t), cun=t.getCunPenalty(self, t), apply_power=self:combatAttack()})

end

end,

info = function(self, t)

local duration = t.getDuration(self, t)

local move = t.getMovePenalty(self, t)

local attack = t.getAttackPenalty(self, t)

local will = t.getWillPenalty(self, t)

local cun = t.getCunPenalty(self, t)

return ([[Learn to take advantage of your enemy's pain.

If your enemy is bleeding and attempts to attack you, their critical hit rate is reduced by %d%%, as their wounds make them more predictable.

If you attack a bleeding enemy, there is a %d%% chance that, for %d turns, they are disabled as you take advantage of openings (reducing their movement speed by %d%% and Accuracy by %d) or anguished as you strike their painful wounds (reducing their Willpower by %d and their Cunning by %d).

The statistical reductions will increase with your Cunning.

]]):format(5+(self:getTalentLevel(t)*5),5+(self:getTalentLevel(t)*3),duration,move * 100,attack,will,cun)

end,

}

and one of the talent's effects is computed in mod.class.interface.Combat.lua (part of the _M:physicalCrit function):

**Code:**

...

-- Scoundrel's Strategies

if self:attr("cut") and target:knowTalent(self.T_SCOUNDREL) then

chance = chance - (5 + (target:getTalentLevel(self.T_SCOUNDREL)*5))

end

...

(The do_scoundrel function is also called by the _M:attackTargetWith function in mod.class.interface.Combat.lua, but the calling code does not need to be changed in this example.)

Looking at this code, consider what happens when a character of arbitrarily high level and corresponding stats invests fully in this talent. What will be the effects for a level 100 character? 200? 500+? (These levels can occur for NPCs in the High Peak or deep in the Infinite Dungeon.)

The duration (of the disabling effect) increases linearly with talent level (and thus character level) and could get excessively long - 10's of turns, quite possibly much longer than the fight itself. The duration can be brought in line with more typical game time scales by replacing the getDuration function with:

**Code:**

getDuration = function(self, t) return math.ceil(self:combatTalentScale(t, 3.3, 5.3)) end,

which scales as the 0.5 power. Here, the rounding and parameters are chosen to match the same duration for the first 5 talent investments (assumed to correspond to talent levels 1.0, 2.0, 3.0, 4.0, 5.0 for the reference characters).

The movement penalty, though it's based on the combatTalentStatDamage function, which has diminishing returns built in, can increase beyond 100%, which would correspond to a negative movement speed. The call to self:combatTalentStatDamage(t, "cun", 10, 30) has a minimum value of 0 and returns 22.4 for the high level reference character. To limit this to less than a 1.0 move factor (100% move speed reduction), replace the getMovePenalty function with:

**Code:**

getMovePenalty = function(self, t) return self:combatLimit(self:combatTalentStatDamage(t, "cun", 10, 30), 1, 0.05, 0, 0.274, 22.4) end, -- Limit <100%

which returns 0.274 and 0.05 when self:combatTalentStatDamage(t, "cun", 10, 30) returns 22.4 and 0 respectively, matching 2 points for the existing function.

The chance to apply the Disable or Anguish effects, computed with rng.percent(5+(self:getTalentLevel(t)*3)), can also increase to more than 100%. To limit these to 100%, introduce a new function to the talent definition:

**Code:**

disableChance = function(self,t) return self:combatTalentLimit(t, 100, 8, 20) end, -- Limit <100%

This limits the chance to < 100%, while matching the 8% chance at talent level 1.0 and the 20% chance at talent level 5.0, for the low and high level reference characters respectively, with the existing formula. The previous computuations in the do_scoundrel and info functions are then replaced with a call to the new function.

The crit rate reduction for a bleeding enemy attacking a character with this talent, computed as 5 + (target:getTalentLevel(self.T_SCOUNDREL)*5) in the _M:physicalCrit and the talent info functions, scales linearly with talent level (1.0 power). This is faster than the normal crit rate (0.5-0.75 power, see the scaling factors above). This means that a high level character with this talent can become completely immune to critical strikes, even against opponents with a bonus crit chance, since normal crit rates cannot keep up. As this is not a widely available talent, the lower tier scaling (0.5 power) is appropriate. The scaling can be made more consistent by adding a another new function:

**Code:**

getCritPenalty = function(self,t) return self:combatTalentScale(t, 10, 30) end,

which matches the existing effects (10% at talent level 1.0, 30% at talent level 5.0), but scales as the default 0.5 power with talent level. The computations in the talent info function and in the _M:physicalCrit function in mod.class.interface.Combat.lua are then updated to call this new function.

Here is the revised talent definition (for ToME 1.0.5):

**Code:**

newTalent{

name = "Scoundrel's Strategies", short_name = "SCOUNDREL",

type = {"cunning/scoundrel", 2},

require = cuns_req2,

mode = "passive",

points = 5,

getDuration = function(self, t) return math.ceil(self:combatTalentScale(t, 3.3, 5.3)) end,

-- _M:physicalCrit function in mod\class\interface\Combat.lua handles crit penalty

getCritPenalty = function(self,t) return self:combatTalentScale(t, 10, 30) end,

disableChance = function(self,t) return self:combatTalentLimit(t, 100, 8, 20) end, -- Limit <100%

getMovePenalty = function(self, t) return self:combatLimit(self:combatTalentStatDamage(t, "cun", 10, 30), 1, 0.05, 0, 0.274, 22.4) end, -- Limit <100%

getAttackPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

getWillPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

getCunPenalty = function(self, t) return 5 + self:combatTalentStatDamage(t, "cun", 5, 20) end,

do_scoundrel = function(self, t, target)

if not rng.percent(t.disableChance(self, t)) then return end

if rng.percent(50) then

if target:hasEffect(target.EFF_DISABLE) then return end

target:setEffect(target.EFF_DISABLE, t.getDuration(self, t), {speed=t.getMovePenalty(self, t), atk=t.getAttackPenalty(self, t), apply_power=self:combatAttack()})

else

if target:hasEffect(target.EFF_ANGUISH) then return end

target:setEffect(target.EFF_ANGUISH, t.getDuration(self, t), {will=t.getWillPenalty(self, t), cun=t.getCunPenalty(self, t), apply_power=self:combatAttack()})

end

end,

info = function(self, t)

local duration = t.getDuration(self, t)

local move = t.getMovePenalty(self, t)

local attack = t.getAttackPenalty(self, t)

local will = t.getWillPenalty(self, t)

local cun = t.getCunPenalty(self, t)

return ([[Learn to take advantage of your enemy's pain.

If your enemy is bleeding and attempts to attack you, their critical hit rate is reduced by %d%%, as their wounds make them more predictable.

If you attack a bleeding enemy, there is a %d%% chance that, for %d turns, they are disabled as you take advantage of openings (reducing their movement speed by %d%% and Accuracy by %d) or anguished as you strike their painful wounds (reducing their Willpower by %d and their Cunning by %d).

The statistical reductions will increase with your Cunning.

]]):format(t.getCritPenalty(self,t), t.disableChance(self, t), duration, move * 100, attack, will, cun)

end,

}

and the call to the new function in the _M:physicalCrit in mod.class.interface.Combat.lua:

**Code:**

...

-- Scoundrel's Strategies

if self:attr("cut") and target:knowTalent(self.T_SCOUNDREL) then

chance = chance - target:callTalent(target.T_SCOUNDREL,"getCritPenalty")

end

...