SHARE
TWEET

stats.lua

a guest Apr 3rd, 2015 1,523 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.  
  3. ---------------------------------------------------------------------
  4.                                 ultimate item stat system by zbizu
  5. ---------------------------------------------------------------------
  6. Made for OtLand.net. Do not post on other forums unless you link to a
  7. thread where you got it from. If you are looking for more 1.1 scripts,
  8. visit a thread where we are working on a list with important stuff:
  9. ---------------------------------------------------------------------
  10. http://otland.net/threads/list-of-useful-tfs-1-0-1-1-scripts.228391/
  11. ---------------------------------------------------------------------
  12.                     Version: 1.6.1, 3 Apr 2015
  13. ---------------------------------------------------------------------
  14.  
  15. ]]
  16.  
  17. STATS_SYSTEM_CONFIG = {
  18.         -- BASIC CONFIG STARTS HERE
  19.         -- enable/disable features so script will execute only what you want
  20.         monsterLoot = true,
  21.         addSlotAction = true,
  22.         addLevelAction = true,
  23.         PVEStat = true,
  24.         xpStat = true,
  25.         lootStat = true,
  26.         combatStats = true,
  27.         conditionStats = true,
  28.         reqLvlBasedOnUpgrade = true, -- requires TFS compiled after 8 Mar 2015
  29.         reqLvlFormula = function(thing) return math.max(thing:getType():getRequiredLevel(), thing:getType():getRequiredLevel() + (thing:getLevel() * 10) + (thing:getStatSlotCount() * 10)) end,
  30.        
  31.         -- don't forget to register them in actions or they will not work
  32.         GEM_BASIC_LEVEL = 8301,
  33.         GEM_ADD_SLOT = 8300,
  34.         GEM_RANDOM = 8305,
  35.         GEM_RARE = 8298,
  36.         GEM_EPIC = 8310,
  37.         GEM_LEGENDARY = 8299,
  38.         gems_power = {
  39.                 [8298] = {min_wl = 0, max_wl = 4, min_el = 0.3, max_el = 0.6, sl = function() return 2 end}, -- rare
  40.                 [8310] = {min_wl = 3, max_wl = 6, min_el = 0.6, max_el = 0.7, sl = function() return 3 end}, -- epic
  41.                 [8299] = {min_wl = 5, max_wl = 9, min_el = 0.8, max_el = 1, sl = function() return 4 end}, -- legendary
  42.                 [8305] = {min_wl = 0, max_wl = 9, min_el = 0.3, max_el = 1, sl = function() return math.random(2, 4) end} -- random
  43.         },
  44.        
  45.         maxSlotCount = 4,
  46.         slotChances = {
  47.                 [1] = 1000,
  48.                 [2] = 5000,
  49.                 [3] = 15000,
  50.                 [4] = 25000
  51.         },
  52.         tiers = { -- item name based on slots looted (if more than 1)
  53.                 [2] = 'rare',
  54.                 [3] = 'epic',
  55.                 [4] = 'legendary'
  56.         },
  57.         weapon_levels = {
  58.                 -- weapon name if no slots were assigned, chance(1000 = 1%)
  59.                 [-9] = {'useless', 300},
  60.                 [-8] = {'broken', 500},
  61.                 [-7] = {'trash', 1000},
  62.                 [-6] = {'ruined', 1500},
  63.                 [-5] = {'damaged', 2000},
  64.                 [-4] = {'worthless', 2500},
  65.                 [-3] = {'blunt', 4000},
  66.                 [-2] = {'cheap', 7000},
  67.                 [-1] = {'common', 9000},
  68.                 [1] = {'uncommon', 25000},
  69.                 [2] = {'strengthened', 20000},
  70.                 [3] = {'fine', 15000},
  71.                 [4] = {'superior', 10000},
  72.                 [5] = {'rare', 7500},
  73.                 [6] = {'unique', 3500},
  74.                 [7] = {'flawless', 2500},
  75.                 [8] = {'epic', 1000},
  76.                 [9] = {'legendary', 500}
  77.         },
  78.         ignoredIds = {}, -- items with these ids will be banned from upgrading
  79.         upgradeMagicItems = true, -- items with xml-sided bonuses, examples: magma coat, fire axe, boots of haste
  80.         upgradeItemsWithNoArmor = true, -- allow upgrading clothes without arm value
  81.         lootUpgradedItems = true,
  82.         rare_popup = true,
  83.         rare_text = "*rare*",
  84.         rare_effect = true,
  85.         rare_effect_id = CONST_ME_MAGIC_GREEN,
  86.         rare_loot_level = true, -- set to false if you want to disable levels on looted weapons
  87.         rare_negative_level = true, -- set to false if you want to disable it
  88.         rare_min_level =  -9,
  89.        
  90.         useSkill = true, -- enchanting power based on player's skill, set to false if you want it random
  91.         skillTriesStorage = 3866,
  92.        
  93.         simple = { -- upgrade by jewels
  94.                 enabled = true,
  95.                 usePerks = false, -- unused
  96.                 randomSpells = true, -- todo: modal with selecting attr if false
  97.                 downgradeOnFail = true, -- item level only
  98.         },
  99.        
  100.         -- BASIC CONFIG ENDS HERE
  101.         -- do not touch things below unless you are a advanced scripter
  102.         skillFormula = function(lv) return math.ceil(((1 * lv^3) - (2 * lv^2) + (4 * lv)) / (90 + lv) + lv) end,
  103.         maxLevel = 30,
  104.        
  105.         levelUpgradeFormula = function(lv, minl)
  106.                 if STATS_SYSTEM_CONFIG.rare_negative_level then
  107.                         return math.ceil((lv/minl) * 25) + math.min(math.ceil(lv/minl * 5) +70, 75)
  108.                 else
  109.                         return 65 - math.ceil((lv/minl) * 3)
  110.                 end
  111.         end,
  112.        
  113.         -- spells and values for certain types of item
  114.         UPGRADE_STATS_VALUES_PER_LVL = {
  115.                 -- value per level
  116.                         atk = 2,
  117.                         def = 2,
  118.                         extradef = 1,
  119.                         arm = 2,
  120.                         hitchance = 3,
  121.                         shootrange = 1
  122.         },
  123.        
  124.         UPGRADE_SPELLS = {
  125.                 necklace = {
  126.                         {'hp', 100, 10}, -- normal, percent
  127.                         {'mp', 200, 10},
  128.                         {'ml', 3, 10},
  129.                         {'melee', 3, 10},
  130.                         {'shield', 3, 10},
  131.                         {'dist', 3, 10},
  132.                         {'physical', 10, 5},
  133.                         {'energy', 10, 10},
  134.                         {'earth', 10, 10},
  135.                         {'fire', 10, 10},
  136.                         -- {'undefined', 10, 10},
  137.                         {'lifedrain', 10, 10},
  138.                         {'manadrain', 10, 10},
  139.                         {'healing', -10, -10},
  140.                         {'water', 20, 100},
  141.                         {'ice', 10, 10},
  142.                         {'holy', 10, 10},
  143.                         {'death', 10, 10},
  144.                         {'regHP', 5, 1}, -- normalhp, normalmp, percenthp, percentmp
  145.                         {'regMP', 10, 2}, -- normalhp, normalmp, percenthp, percentmp
  146.                         {'PVE death', 1, 100}
  147.                 },
  148.                 helmet = {
  149.                         {'ml', 3, 10},
  150.                         {'melee', 3, 10},
  151.                         {'dist', 3, 10},
  152.                         {'physical', 10, 3},
  153.                         {'energy', 10, 10},
  154.                         {'earth', 10, 10},
  155.                         {'fire', 10, 10},
  156.                         -- {'undefined', 10, 10},
  157.                         {'lifedrain', 10, 10},
  158.                         {'manadrain', 10, 10},
  159.                         {'healing', -10, -10},
  160.                         {'water', 20, 100},
  161.                         {'ice', 10, 10},
  162.                         {'holy', 10, 10},
  163.                         {'death', 10, 10},
  164.                         {'arm', 12, 70},
  165.                 },
  166.                 weapon = {
  167.                         {'melee', 5, 15},
  168.                         {'physical', 50, 10},
  169.                         {'energy', 50, 10},
  170.                         {'earth', 50, 10},
  171.                         {'fire', 50, 10},
  172.                         -- {'undefined', 50, 10},
  173.                         {'ice', 50, 10},
  174.                         {'holy', 50, 10},
  175.                         {'death', 50, 10},
  176.                         {'drainHP', 50, 3},
  177.                         {'drainMP', 50, 3},
  178.                         {'water', 50, 10},
  179.                         {'animals', 50, 10},
  180.                         {'humans', 50, 3},
  181.                         {'undeads', 50, 10},
  182.                         {'insects', 50, 10},
  183.                         {'atk', 12, 70},
  184.                         {'def', 12, 70},
  185.                         {'extra def', 12, 70},
  186.                 },
  187.                 distance = {
  188.                         {'dist', 5, 15},
  189.                         {'physical', 50, 10},
  190.                         {'energy', 50, 10},
  191.                         {'earth', 50, 10},
  192.                         {'fire', 50, 10},
  193.                         -- {'undefined', 50, 10},
  194.                         {'ice', 50, 10},
  195.                         {'holy', 50, 10},
  196.                         {'death', 50, 10},
  197.                         {'drainHP', 50, 3},
  198.                         {'drainMP', 50, 3},
  199.                         {'water', 50, 10},
  200.                         {'animals', 50, 10},
  201.                         {'humans', 50, 3},
  202.                         {'undeads', 50, 10},
  203.                         {'insects', 50, 10},
  204.                         {'atk', 12, 70},
  205.                         {'accuracy', 12, 70},
  206.                         {'range', 3, 50},
  207.                 },
  208.                 wand = {
  209.                         {'ml', 5, 15},
  210.                         {'physical', 50, 10},
  211.                         {'energy', 50, 10},
  212.                         {'earth', 50, 10},
  213.                         {'fire', 50, 10},
  214.                         -- {'undefined', 50, 10},
  215.                         {'healing', 50, 10},
  216.                         {'ice', 50, 10},
  217.                         {'holy', 50, 10},
  218.                         {'death', 50, 10},
  219.                         {'drainHP', 50, 3},
  220.                         {'drainMP', 50, 3},
  221.                         {'water', 50, 10},
  222.                         {'animals', 50, 10},
  223.                         {'humans', 50, 3},
  224.                         {'undeads', 50, 10},
  225.                         {'insects', 50, 10},
  226.                         {'range', 3, 50},
  227.                 },
  228.                 armor = {
  229.                         {'hp', 300, 15},
  230.                         {'mp', 500, 20},
  231.                         {'ml', 5, 15},
  232.                         {'melee', 5, 15},
  233.                         {'shield', 5, 15},
  234.                         {'dist', 5, 15},
  235.                         {'physical', 50, 5},
  236.                         {'energy', 10, 15},
  237.                         {'earth', 10, 15},
  238.                         {'fire', 10, 15},
  239.                         -- {'undefined', 10, 15},
  240.                         {'lifedrain', 10, 15},
  241.                         {'manadrain', 10, 15},
  242.                         {'healing', -10, -15},
  243.                         {'water', 20, 100},
  244.                         {'ice', 10, 15},
  245.                         {'holy', 10, 15},
  246.                         {'death', 10, 15},
  247.                         {'regHP', 5, 1},
  248.                         {'regMP', 10, 2},
  249.                         {'arm', 12, 70},
  250.                 },
  251.                 shield = {
  252.                         {'ml', 3, 10},
  253.                         {'shield', 5, 15},
  254.                         {'physical', 30, 5},
  255.                         {'energy', 10, 15},
  256.                         {'earth', 10, 15},
  257.                         {'fire', 10, 15},
  258.                         -- {'undefined', 10, 15},
  259.                         {'lifedrain', 10, 15},
  260.                         {'manadrain', 10, 15},
  261.                         {'ice', 10, 15},
  262.                         {'holy', 10, 15},
  263.                         {'death', 10, 15},
  264.                         {'regHP', 5, 1},
  265.                         {'regMP', 10, 2},
  266.                         {'def', 12, 70},
  267.                 },
  268.                 ring = {
  269.                         {'hp', 100, 10},
  270.                         {'mp', 200, 10},
  271.                         {'ml', 3, 10},
  272.                         {'melee', 3, 10},
  273.                         {'shield', 3, 10},
  274.                         {'dist', 3, 10},
  275.                         {'physical', 10, 5},
  276.                         {'energy', 10, 10},
  277.                         {'earth', 10, 10},
  278.                         {'fire', 10, 10},
  279.                         -- {'undefined', 10, 10},
  280.                         {'lifedrain', 10, 10},
  281.                         {'manadrain', 10, 10},
  282.                         {'healing', -10, -10},
  283.                         {'water', 20, 100},
  284.                         {'ice', 10, 10},
  285.                         {'holy', 10, 10},
  286.                         {'death', 10, 10},
  287.                         {'regHP', 5, 1},
  288.                         {'regMP', 10, 2},
  289.                         {'exp', 50, 50},
  290.                         {'loot', 1, 30},
  291.                 },
  292.                 legs = {
  293.                         {'ml', 3, 10},
  294.                         {'melee', 3, 10},
  295.                         {'shield', 3, 10},
  296.                         {'dist', 3, 10},
  297.                         {'physical', 10, 4},
  298.                         {'energy', 10, 10},
  299.                         {'earth', 10, 10},
  300.                         {'fire', 10, 10},
  301.                         -- {'undefined', 10, 10},
  302.                         {'lifedrain', 10, 10},
  303.                         {'manadrain', 10, 10},
  304.                         {'healing', -10, -10},
  305.                         {'ice', 10, 10},
  306.                         {'holy', 10, 10},
  307.                         {'death', 10, 10},
  308.                         {'arm', 12, 70},
  309.                 },
  310.                 boots = {
  311.                         {'physical', 10, 3},
  312.                         {'energy', 10, 10},
  313.                         {'earth', 10, 10},
  314.                         {'fire', 10, 10},
  315.                         -- {'undefined', 10, 10},
  316.                         {'lifedrain', 10, 10},
  317.                         {'manadrain', 10, 10},
  318.                         {'healing', -10, -10},
  319.                         {'ice', 10, 10},
  320.                         {'holy', 10, 10},
  321.                         {'death', 10, 10},
  322.                         {'regHP', 5, 1},
  323.                         {'regMP', 10, 2},
  324.                         {'arm', 12, 70},
  325.                 },
  326.                 charges = {
  327.                         {'charges', 500, 45},
  328.                 },
  329.                 decay = {
  330.                         {'time', 1200000, 50},
  331.                 },
  332.         },
  333.        
  334.         STATS = {
  335.                 {
  336.                         name = 'hp',
  337.                        
  338.                         weaponLootName = {'',''},
  339.                         armorLootName = {'','of improved health'},
  340.                         otherLootName = {'','of improved health'},
  341.                        
  342.                         spellName = 'Health',
  343.                         enabledValues = true,
  344.                         enabledPercent = true
  345.                         },
  346.                
  347.                 {
  348.                         name = 'mp',
  349.  
  350.                         spellName = 'Mana',
  351.                         enabledValues = true,
  352.                        
  353.                         weaponLootName = {'',''},
  354.                         armorLootName = {'','of improved mana'},
  355.                         otherLootName = {'','of improved mana'},
  356.                         enabledPercent = true
  357.                 },
  358.                
  359.                 {
  360.                         name = 'ml',
  361.  
  362.                         weaponLootName = {'magic',''},
  363.                         armorLootName = {'enchanted',''},
  364.                         otherLootName = {'magic',''},
  365.  
  366.                         spellName = 'Magic Level',
  367.                         enabledValues = true,  
  368.                         enabledPercent = true  
  369.                 },
  370.                
  371.                 {
  372.                         name = 'melee',
  373.  
  374.                         weaponLootName = {'','of power'},
  375.                         armorLootName = {'warrior',''},
  376.                         otherLootName = {'','of power'},
  377.  
  378.                         spellName = 'Melee Skill',
  379.                         enabledValues = true,
  380.                         enabledPercent = true          
  381.                 },
  382.                
  383.                 {
  384.                         name = 'shield',
  385.  
  386.                         weaponLootName = {'','of defense'},
  387.                         armorLootName = {'fortified',''},
  388.                         otherLootName = {'','of defense'},
  389.                        
  390.                         spellName = 'Shielding',
  391.                         enabledValues = true,
  392.                         enabledPercent = true                  
  393.                 },
  394.                
  395.                 {
  396.                         name = 'dist',
  397.  
  398.                         weaponLootName = {'','of hunting'},
  399.                         armorLootName = {'hunter',''},
  400.                         otherLootName = {'','of hunting'},
  401.                                                
  402.                         spellName = 'Distance Skill',
  403.                         enabledValues = true,
  404.                         enabledPercent = true
  405.                 },
  406.  
  407.                 -- element types
  408.                 -- on weapon: value = more or less element damage
  409.                 -- on armor: value = when something hits you, hit value may increase or decrease depending on value
  410.                 {
  411.                         name = 'physical',
  412.                         combatType = COMBAT_PHYSICALDAMAGE,
  413.  
  414.                         weaponLootName = {'','of bleeding'},
  415.                         armorLootName = {'strong',''},
  416.                         otherLootName = {'stone',''},
  417.                        
  418.                         spellName = 'Physical',
  419.                         enabledValues = true,
  420.                         enabledPercent = true,
  421.                        
  422.                         effect = CONST_ME_BLOCKHIT
  423.                 },
  424.                
  425.                
  426.                 {
  427.                         name = 'energy',
  428.                         combatType = COMBAT_ENERGYDAMAGE,
  429.                        
  430.                         weaponLootName = {'','of thunders'},
  431.                         armorLootName = {'','of sparks'},
  432.                         otherLootName = {'','of lightning'},
  433.                        
  434.                         oppositeSpell = 'earth', -- unused values
  435.                         spellName = 'Energy',
  436.                         enabledValues = true,
  437.                         enabledPercent = true,
  438.                        
  439.                         effect = CONST_ME_ENERGYHIT
  440.                 },
  441.                
  442.                 {
  443.                         name = 'earth',
  444.                         combatType = COMBAT_EARTHDAMAGE,
  445.  
  446.                         weaponLootName = {'poison',''},
  447.                         armorLootName = {'earthproof',''},
  448.                         otherLootName = {'','of antidote'},
  449.                        
  450.                         oppositeSpell = 'energy',
  451.                         spellName = 'Earth',
  452.                         enabledValues = true,
  453.                         enabledPercent = true,
  454.                         effect = CONST_ME_SMALLPLANTS
  455.                 },
  456.                
  457.                 {
  458.                         name = 'fire',
  459.                         combatType = COMBAT_FIREDAMAGE,
  460.  
  461.                         weaponLootName = {'burning',''},
  462.                         armorLootName = {'fireproof',''},
  463.                         otherLootName = {'','of fire protection'},
  464.                        
  465.                         oppositeSpell = 'ice',
  466.                         spellName = 'Fire',
  467.                         enabledValues = true,
  468.                         enabledPercent = true,
  469.                         effect = CONST_ME_FIREATTACK
  470.                 },
  471.                
  472.                 {
  473.                         -- exist in tfs, not in use by default
  474.                         name = 'undefined',
  475.                         combatType = COMBAT_UNDEFINEDDAMAGE,
  476.  
  477.                         weaponLootName = {'ghost',''},
  478.                         armorLootName = {'',''},
  479.                         otherLootName = {'',''},
  480.                        
  481.                         spellName = 'None',
  482.                         enabledValues = false,
  483.                         enabledPercent = false,
  484.                         effect = CONST_ME_GROUNDSHAKER
  485.                 },
  486.                
  487.                 {
  488.                         name = 'lifedrain',
  489.                         combatType = COMBAT_LIFEDRAIN,
  490.                        
  491.                         weaponLootName = {'cursed',''},
  492.                         armorLootName = {'enchanted',''},
  493.                         otherLootName = {'blessed',''},
  494.                        
  495.                         oppositeSpell = 'healing',
  496.                         spellName = 'Lifedrain',
  497.                         enabledValues = true,
  498.                         enabledPercent = true,
  499.                         effect = CONST_ME_MAGIC_RED
  500.                 },
  501.                
  502.                 {
  503.                         name = 'manadrain',
  504.                         combatType = COMBAT_MANADRAIN,
  505.                        
  506.                         weaponLootName = {'','of dark magic'},
  507.                         armorLootName = {'sealed',''},
  508.                         otherLootName = {'','of mana protection'},
  509.                        
  510.                         spellName = 'Manadrain',
  511.                         enabledValues = true,
  512.                         enabledPercent = true,
  513.                         effect = CONST_ME_LOSEENERGY
  514.                 },
  515.                
  516.                 {
  517.                         -- should not be used by weapons
  518.                         name = 'healing',
  519.                         combatType = COMBAT_HEALING,
  520.                        
  521.                         weaponLootName = {'healer',''},
  522.                         armorLootName = {'','of healing'},
  523.                         otherLootName = {'','of healing'},
  524.                        
  525.                         oppositeSpell = 'lifedrain',
  526.                         spellName = 'Healing',
  527.                         enabledValues = true,
  528.                         enabledPercent = true,
  529.                         effect = CONST_ME_MAGIC_BLUE
  530.                 },
  531.                
  532.                 {
  533.                         name = 'water',
  534.                         combatType = COMBAT_DROWNDAMAGE,
  535.                        
  536.                         weaponLootName = {'','of fear'},
  537.                         armorLootName = {'','of the deep'},
  538.                         otherLootName = {'','of the deep'},
  539.                        
  540.                         spellName = 'Water',
  541.                         enabledValues = true,
  542.                         enabledPercent = true,
  543.                         effect = CONST_ME_LOSEENERGY
  544.                 },
  545.                
  546.                 {
  547.                         name = 'ice',
  548.                         combatType = COMBAT_ICEDAMAGE,
  549.                        
  550.                         weaponLootName = {'icy',''},
  551.                         armorLootName = {'frozen',''},
  552.                         otherLootName = {'','of cold'},
  553.                        
  554.                         oppositeSpell = 'fire',
  555.                         spellName = 'Ice',
  556.                         enabledValues = true,
  557.                         enabledPercent = true,
  558.                         effect = CONST_ME_ICEATTACK
  559.                 },
  560.                
  561.                 {
  562.                         name = 'holy',
  563.                         combatType = COMBAT_HOLYDAMAGE,
  564.                        
  565.                         weaponLootName = {'divine',''},
  566.                         armorLootName = {'','of darkness'},
  567.                         otherLootName = {'dark',''},
  568.                        
  569.                         oppositeSpell = 'death',
  570.                         spellName = 'Holy',
  571.                         enabledValues = true,
  572.                         enabledPercent = true,
  573.                         effect = CONST_ME_HOLYDAMAGE
  574.                 },
  575.                
  576.                 {
  577.                         name = 'death',
  578.                         combatType = COMBAT_DEATHDAMAGE,
  579.  
  580.                         weaponLootName = {'','of darkness'},
  581.                         armorLootName = {'','of inquisition'},
  582.                         otherLootName = {'holy',''},
  583.                        
  584.                         oppositeSpell = 'holy',
  585.                         spellName = 'Death',
  586.                         enabledValues = true,
  587.                         enabledPercent = true,
  588.                         effect = CONST_ME_MORTAREA
  589.                 },
  590.                
  591.                 -- weapon only
  592.                 {
  593.                         name = 'drainHP',
  594.                         drain = COMBAT_LIFEDRAIN,
  595.  
  596.                         weaponLootName = {'vampire',''},
  597.                         armorLootName = {'',''},
  598.                         otherLootName = {'',''},
  599.                        
  600.                         spellName = 'Drain Health',
  601.                         enabledValues = true,
  602.                         enabledPercent = true
  603.                 },
  604.                
  605.                 {
  606.                         name = 'drainMP',
  607.                         drain = COMBAT_MANADRAIN,
  608.  
  609.                         weaponLootName = {'','of weakness'},
  610.                         armorLootName = {'',''},
  611.                         otherLootName = {'',''},
  612.                        
  613.                         spellName = 'Drain Mana',
  614.                         enabledValues = true,
  615.                         enabledPercent = true
  616.                 },
  617.                
  618.                 {
  619.                         name = 'animals',
  620.                         weaponLootName = {'hunting',''},
  621.                         armorLootName = {'',''},
  622.                         otherLootName = {'',''},
  623.                         spellName = 'Animals',
  624.                         enabledValues = true,
  625.                         enabledPercent = true
  626.                 },
  627.                
  628.                 {
  629.                         name = 'humans',
  630.  
  631.                         weaponLootName = {'',''},
  632.                         armorLootName = {'',''},
  633.                         otherLootName = {'',''},
  634.                        
  635.                         spellName = 'Humans',
  636.                         enabledValues = true,
  637.                         enabledPercent = true
  638.                 },
  639.                
  640.                 {
  641.                         name = 'undeads',
  642.  
  643.                         weaponLootName = {'','of inquisition'},
  644.                         armorLootName = {'',''},
  645.                         otherLootName = {'',''},
  646.                        
  647.                         spellName = 'Undeads',
  648.                         enabledValues = true,
  649.                         enabledPercent = true
  650.                 },
  651.                
  652.                 {
  653.                         name = 'insects',
  654.                        
  655.                         weaponLootName = {'','of insect hunting'},
  656.                         armorLootName = {'',''},
  657.                         otherLootName = {'',''},
  658.                        
  659.                         spellName = 'Insects',
  660.                         enabledValues = true,
  661.                         enabledPercent = true
  662.                 },
  663.  
  664.                 -- buff
  665.                 {
  666.                         name = 'regHP',
  667.                        
  668.                         weaponLootName = {'',''},
  669.                         armorLootName = {'','of vitality'},
  670.                         otherLootName = {'','of vitality'},
  671.                        
  672.                         spellName = 'HP Regeneration',
  673.                         enabledValues = true,
  674.                         enabledPercent = true
  675.                 },
  676.  
  677.                 {
  678.                         name = 'regMP',
  679.                        
  680.                         weaponLootName = {'',''},
  681.                         armorLootName = {'','of magic'},
  682.                         otherLootName = {'','of magic'},
  683.                        
  684.                         spellName = 'MP Regeneration',
  685.                         enabledValues = true,
  686.                         enabledPercent = true
  687.                 },
  688.                
  689.                 -- attr based stats
  690.                 {
  691.                         name = 'charges',
  692.                        
  693.                         weaponLootName = {'',''},
  694.                         armorLootName = {'',''},
  695.                         otherLootName = {'charged',''},
  696.                        
  697.                         spellName = 'Charges',
  698.                         enabledValues = true,
  699.                         enabledPercent = true
  700.                 },
  701.                
  702.                 {
  703.                         name = 'time',
  704.                        
  705.                         weaponLootName = {'',''},
  706.                         armorLootName = {'',''},
  707.                         otherLootName = {'fine',''},
  708.                        
  709.                         spellName = 'Duration',
  710.                         enabledValues = true,
  711.                         enabledPercent = true
  712.                 },
  713.                
  714.                 {
  715.                         name = 'atk',
  716.                        
  717.                         weaponLootName = {'sharpened',''},
  718.                         armorLootName = {'',''},
  719.                         otherLootName = {'',''},
  720.                        
  721.                         spellName = 'Attack',
  722.                         enabledValues = true,
  723.                         enabledPercent = true
  724.                 },
  725.                
  726.                 {
  727.                         name = 'def',
  728.                        
  729.                         weaponLootName = {'strong',''},
  730.                         armorLootName = {'fortified',''},
  731.                         otherLootName = {'',''},
  732.                        
  733.                         spellName = 'Defense',
  734.                         enabledValues = true,
  735.                         enabledPercent = true
  736.                 },
  737.                
  738.                 {
  739.                         name = 'extra def',
  740.                        
  741.                         weaponLootName = {'','of balance'},
  742.                         armorLootName = {'',''},
  743.                         otherLootName = {'',''},
  744.                        
  745.                         spellName = 'Extra Defense',
  746.                         enabledValues = true,
  747.                         enabledPercent = true
  748.                 },
  749.                
  750.                 {
  751.                         name = 'arm',
  752.                        
  753.                         weaponLootName = {'',''},
  754.                         armorLootName = {'masterpiece of',''},
  755.                         otherLootName = {'',''},
  756.                        
  757.                         spellName = 'Armor',
  758.                         enabledValues = true,
  759.                         enabledPercent = true
  760.                 },
  761.                
  762.                 {
  763.                         name = 'accuracy',
  764.                        
  765.                         weaponLootName = {'accurate',''},
  766.                         armorLootName = {'',''},
  767.                         otherLootName = {'',''},
  768.                        
  769.                         spellName = 'Hit Chance',
  770.                         enabledValues = true, -- hit% + x%
  771.                         enabledPercent = true -- hit% + hit%*x%
  772.                 },
  773.                
  774.                 {
  775.                         name = 'range',
  776.                        
  777.                         weaponLootName = {'sniper',''},
  778.                         armorLootName = {'',''},
  779.                         otherLootName = {'',''},
  780.                        
  781.                         spellName = 'Range',
  782.                         enabledValues = true,
  783.                         enabledPercent = true
  784.                 },
  785.                
  786.                 {
  787.                         name = 'PVE death',
  788.                        
  789.                         weaponLootName = {'',''},
  790.                         armorLootName = {'',''},
  791.                         otherLootName = {'','of good fate'},
  792.                        
  793.                         spellName = 'PVE Death',
  794.                         enabledValues = true,
  795.                         enabledPercent = true
  796.                 },
  797.                 -- xp, loot
  798.                 {
  799.                         name = 'exp',
  800.                        
  801.                         weaponLootName = {'',''},
  802.                         armorLootName = {'',''},
  803.                         otherLootName = {'','of experience'},
  804.                        
  805.                         spellName = 'Extra Exp',
  806.                         enabledValues = true,
  807.                         enabledPercent = true
  808.                 },
  809.                
  810.                 {
  811.                         name = 'loot',
  812.                        
  813.                         weaponLootName = {'',''},
  814.                         armorLootName = {'',''},
  815.                         otherLootName = {'','of luck'},
  816.                        
  817.                         spellName = 'Luck',
  818.                         enabledValues = true,
  819.                         enabledPercent = true
  820.                 },
  821.         },
  822. }
  823.  
  824. function getItemAttribute(uid, key, force)
  825.         local i = ItemType(Item(uid):getId())
  826.         local string_attributes = {
  827.                 [ITEM_ATTRIBUTE_NAME] = i:getName(),
  828.                 [ITEM_ATTRIBUTE_ARTICLE] = i:getArticle(),
  829.                 [ITEM_ATTRIBUTE_PLURALNAME] = i:getPluralName(),
  830.                 ["name"] = i:getName(),
  831.                 ["article"] = i:getArticle(),
  832.                 ["pluralname"] = i:getPluralName()
  833.         }
  834.  
  835.         local numeric_attributes = {
  836.                 [ITEM_ATTRIBUTE_WEIGHT] = i:getWeight(),
  837.                 [ITEM_ATTRIBUTE_ATTACK] = i:getAttack(),
  838.                 [ITEM_ATTRIBUTE_DEFENSE] = i:getDefense(),
  839.                 [ITEM_ATTRIBUTE_EXTRADEFENSE] = i:getExtraDefense(),
  840.                 [ITEM_ATTRIBUTE_ARMOR] = i:getArmor(),
  841.                 [ITEM_ATTRIBUTE_HITCHANCE] = i:getHitChance(),
  842.                 [ITEM_ATTRIBUTE_SHOOTRANGE] = i:getShootRange(),
  843.                 ["weight"] = i:getWeight(),
  844.                 ["attack"] = i:getAttack(),
  845.                 ["defense"] = i:getDefense(),
  846.                 ["extradefense"] = i:getExtraDefense(),
  847.                 ["armor"] = i:getArmor(),
  848.                 ["hitchance"] = i:getHitChance(),
  849.                 ["shootrange"] = i:getShootRange()
  850.         }
  851.  
  852.         local item = Item(uid)
  853.         local attr = item:getAttribute(key)
  854.         if tonumber(attr) then
  855.                 if numeric_attributes[key] then
  856.                         if force and item:getActionId() == 101 then
  857.                                 return attr
  858.                         else
  859.                                 return attr ~= 0 and attr or numeric_attributes[key]
  860.                         end
  861.                 end
  862.         else
  863.                 if string_attributes[key] then
  864.                         if attr == "" then
  865.                                 return string_attributes[key]
  866.                         end
  867.                 end
  868.         end
  869.         return attr
  870. end
  871.  
  872. function doItemSetAttribute(uid, key, value)
  873.         return Item(uid):setAttribute(key, value)
  874. end
  875.  
  876. function doItemEraseAttribute(uid, key)
  877.         return Item(uid):removeAttribute(key)
  878. end
  879.  
  880. local element_stats = {}
  881. local drain_stats = {}
  882.  
  883. for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  884.         local stat = STATS_SYSTEM_CONFIG.STATS[i]
  885.         if stat.drain then
  886.                 drain_stats[stat.name] = stat.drain
  887.         end
  888.        
  889.         if stat.combatType then
  890.                 element_stats[stat.name] = {combat = stat.combatType, effect = stat.effect}
  891.         end
  892. end
  893.  
  894. local stat_conditions = {
  895. [1] = {['hp'] = {}, ['mp'] = {}, ['ml'] = {}, ['melee'] = {}, ['shield'] = {}, ['dist'] = {}}, -- normal
  896. [2] = {['hp'] = {}, ['mp'] = {}, ['ml'] = {}, ['melee'] = {}, ['shield'] = {}, ['dist'] = {}} -- percent
  897. }
  898.  
  899. for i = -95, 300 do
  900. -- % stats and skills
  901.         stat_conditions[2]['hp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  902.         setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_SUBID, 50)
  903.         setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  904.         setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_TICKS, -1)
  905.         setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_STAT_MAXHITPOINTSPERCENT, 100+i)
  906.  
  907.         stat_conditions[2]['mp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  908.         setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_SUBID, 51)
  909.         setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  910.         setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_TICKS, -1)
  911.         setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_STAT_MAXMANAPOINTSPERCENT, 100+i)
  912.  
  913.         stat_conditions[2]['ml'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  914.         setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_SUBID, 52)
  915.         setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  916.         setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_TICKS, -1)
  917.         setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_STAT_MAGICPOINTSPERCENT, 100+i)
  918.  
  919.         stat_conditions[2]['melee'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  920.         setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_SUBID, 53)
  921.         setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  922.         setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_TICKS, -1)
  923.         setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_SKILL_MELEEPERCENT, 100+i)
  924.  
  925.         stat_conditions[2]['shield'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  926.         setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_SUBID, 54)
  927.         setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  928.         setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_TICKS, -1)
  929.         setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_SKILL_SHIELDPERCENT, 100+i)
  930.  
  931.         stat_conditions[2]['dist'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  932.         setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_SUBID, 55)
  933.         setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  934.         setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_TICKS, -1)
  935.         setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_SKILL_DISTANCEPERCENT, 100+i)
  936. end
  937.  
  938. for i = -1500, 1500 do
  939.         -- hp mp normal
  940.         stat_conditions[1]['hp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  941.         setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_SUBID, 56)
  942.         setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  943.         setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_TICKS, -1)
  944.         setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_STAT_MAXHITPOINTS, i)
  945.  
  946.         stat_conditions[1]['mp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  947.         setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_SUBID, 57)
  948.         setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  949.         setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_TICKS, -1)
  950.         setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_STAT_MAXMANAPOINTS, i)
  951. end
  952.  
  953. for i = -100, 100 do
  954.         -- skills
  955.         stat_conditions[1]['ml'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  956.         setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_SUBID, 58)
  957.         setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  958.         setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_TICKS, -1)
  959.         setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_STAT_MAGICPOINTS, i)
  960.  
  961.         stat_conditions[1]['melee'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  962.         setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_SUBID, 59)
  963.         setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  964.         setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_TICKS, -1)
  965.         setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_SKILL_MELEE, i)
  966.  
  967.         stat_conditions[1]['shield'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  968.         setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_SUBID, 60)
  969.         setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  970.         setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_TICKS, -1)
  971.         setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_SKILL_SHIELD, i)
  972.  
  973.         stat_conditions[1]['dist'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  974.         setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_SUBID, 61)
  975.         setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  976.         setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_TICKS, -1)
  977.         setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_SKILL_DISTANCE, i)
  978. end
  979.  
  980. local magic_words = { -- see upgradeMagicItems in config
  981.         'physical',
  982.         'fire',
  983.         'ice',
  984.         'earth',
  985.         'energy',
  986.         'poison',
  987.         'drown',
  988.         'holy',
  989.         'death',
  990.         'lifedrain',
  991.         'manadrain',
  992.         'protection',
  993.         'magic',
  994.         'fighting',
  995.         'shielding',
  996.         'speed',
  997.         'invisibility',
  998.         'drinking',
  999.         'regeneration',
  1000. }
  1001.        
  1002. local upgrade_types = {
  1003.         none = false,
  1004.         necklace = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.necklace,
  1005.         helmet = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.helmet,
  1006.         weapon = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.weapon,
  1007.         distance = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.distance,
  1008.         wand = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.wand,
  1009.         armor = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.armor,
  1010.         shield = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.shield,
  1011.         ring = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.ring,
  1012.         legs = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.legs,
  1013.         boots = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.boots,
  1014.         charges = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.charges,
  1015.         decay = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.decay,
  1016. }
  1017.  
  1018. function Item:getUpgradeType()
  1019.         local it_id = self:getType()
  1020.         if it_id:isStackable() or it_id:isContainer() then
  1021.                 return upgrade_types.none
  1022.         end
  1023.  
  1024.         local wp = it_id:getWeaponType()
  1025.         if self:getAttribute(ITEM_ATTRIBUTE_CHARGES) > 0 then
  1026.                 if wp > 0 then
  1027.                         return upgrade_types.none
  1028.                 end
  1029.                 return upgrade_types.charges
  1030.         end
  1031.  
  1032.         if self:getAttribute(ITEM_ATTRIBUTE_DURATION) > 0 then
  1033.                 if wp > 0 then
  1034.                         return upgrade_types.none
  1035.                 end
  1036.                 return upgrade_types.decay
  1037.         else
  1038.                 if self:getBaseDuration() > 0 then
  1039.                         if wp > 0 then
  1040.                                 return upgrade_types.none
  1041.                         end
  1042.                         return upgrade_types.decay
  1043.                 end
  1044.         end
  1045.        
  1046.         if wp > 0 then
  1047.                 if wp == WEAPON_SHIELD then
  1048.                         return upgrade_types.shield
  1049.                 elseif wp == WEAPON_DISTANCE then
  1050.                         return upgrade_types.distance
  1051.                 elseif wp == WEAPON_WAND then
  1052.                         return upgrade_types.wand
  1053.                 elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, wp) then
  1054.                         return upgrade_types.weapon
  1055.                 end
  1056.         else
  1057.                 local slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  1058.                 if it_id:getArmor() > 0 or STATS_SYSTEM_CONFIG.upgradeItemsWithNoArmor then
  1059.                         if slot == SLOTP_HEAD then
  1060.                                 return upgrade_types.helmet
  1061.                         elseif slot == SLOTP_ARMOR then
  1062.                                 return upgrade_types.armor
  1063.                         elseif slot == SLOTP_LEGS then
  1064.                                 return upgrade_types.legs
  1065.                         elseif slot == SLOTP_FEET then
  1066.                                 return upgrade_types.boots
  1067.                         end
  1068.                 end
  1069.                
  1070.                 if slot == SLOTP_NECKLACE then
  1071.                         return upgrade_types.necklace
  1072.                 end
  1073.                
  1074.                 if slot == SLOTP_RING then
  1075.                         return upgrade_types.ring
  1076.                 end
  1077.         end
  1078.        
  1079.         return upgrade_types.none
  1080. end
  1081.  
  1082. function Item:getStatSlotCount()
  1083.         local c = 0
  1084.         for _ in self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION):gmatch('%[(.-)%]') do
  1085.                 c = c+1
  1086.         end
  1087.         return c
  1088. end
  1089.  
  1090. function Item:getStatSlots()
  1091.         local t = {}
  1092.         for _ in self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION):gmatch('(%[.-%])') do
  1093.                 if _ then
  1094.                         if _:match('%[(.+)%]') then
  1095.                                 local n = _:match('%[(.+)%]')
  1096.                                 if n ~= '?' then
  1097.                                         local n1 = n:split(".")
  1098.                                         local i = #t + 1
  1099.                                         t[i] = {n1[1], n1[2]}
  1100.                                 end
  1101.                         end
  1102.                 end
  1103.         end
  1104.         return t
  1105. end
  1106.  
  1107. function Item:addStatSlot(spell, val, suffix)
  1108.         if spell and val then
  1109.                 if not suffix then suffix = "" end
  1110.                 self:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION) .. "[" .. spell .. "." .. (val >= 0 and "+" .. val or val) .. suffix .. "]")
  1111.         else
  1112.                 return false
  1113.         end
  1114. return true
  1115. end
  1116.  
  1117. function Item:addSlot(name, val, percent)
  1118.         val = tonumber(val)
  1119.         if name and val then
  1120.                 if self:addStat(name, val, (percent and "%" or "")) then
  1121.                         return true
  1122.                 end
  1123.         end
  1124.         return false
  1125. end
  1126.  
  1127. function Item:getBaseDuration()
  1128.         local it_id = self:getId()
  1129.         local tid = ItemType(it_id):getTransformEquipId()
  1130.         local vx = self:getAttribute(ITEM_ATTRIBUTE_DURATION)
  1131.        
  1132.         if tid > 0 then
  1133.                 self:transform(tid)
  1134.                 vx = self:getAttribute(ITEM_ATTRIBUTE_DURATION)
  1135.                 self:transform(it_id)
  1136.                 self:removeAttribute(ITEM_ATTRIBUTE_DURATION)
  1137.         end
  1138.         return vx
  1139. end
  1140.  
  1141. function Item:getBaseStatsInfo()
  1142.         local it_id = self:getType()
  1143.         local t = {
  1144.                 attack = it_id:getAttack(),
  1145.                 defense = it_id:getDefense(),
  1146.                 extraDefense = it_id:getExtraDefense(),
  1147.                 armor = it_id:getArmor(),
  1148.                 hitChance = it_id:getHitChance(),
  1149.                 shootRange = it_id:getShootRange(),
  1150.                 charges = it_id:getCharges(),
  1151.                 duration = self:getBaseDuration()
  1152.         }
  1153.         return t
  1154. end
  1155.  
  1156. function getEnchantingSkill(tries)
  1157. local xp = 0
  1158. local level = 0
  1159.         for lv = 1, STATS_SYSTEM_CONFIG.maxLevel do
  1160.                 xp = STATS_SYSTEM_CONFIG.skillFormula(lv) -- alternative: xp = xp + STATS_SYSTEM_CONFIG.skillFormula(lv)
  1161.                 if tries < xp then
  1162.                         level = lv
  1163.                         break
  1164.                 end
  1165.                 level = lv
  1166.         end
  1167.         return level
  1168. end
  1169.  
  1170. local SPELL_TYPE_VALUE = 1
  1171. local SPELL_TYPE_PERCENT = 2
  1172. local attrkeys = {
  1173.         ['charges'] = ITEM_ATTRIBUTE_CHARGES,
  1174.         ['time'] = ITEM_ATTRIBUTE_DURATION,
  1175.         ['atk'] = ITEM_ATTRIBUTE_ATTACK,
  1176.         ['def'] = ITEM_ATTRIBUTE_DEFENSE,
  1177.         ['extra def'] = ITEM_ATTRIBUTE_EXTRADEFENSE,
  1178.         ['arm'] = ITEM_ATTRIBUTE_ARMOR,
  1179.         ['accuracy'] = ITEM_ATTRIBUTE_HITCHANCE,
  1180.         ['range'] = ITEM_ATTRIBUTE_SHOOTRANGE
  1181. }
  1182.  
  1183. function Item.addStat(item, spellname, spellvalue, suffix, cid)
  1184.         if isInArray({'charges', 'time', 'atk', 'def', 'extra def', 'arm', 'accuracy', 'range'}, spellname) then
  1185.                 local basestats = item:getBaseStatsInfo()
  1186.                 local basestats2 = {
  1187.                         ['charges'] = basestats.charges,
  1188.                         ['time'] = basestats.duration,
  1189.                         ['atk'] = basestats.attack,
  1190.                         ['def'] = basestats.defense,
  1191.                         ['extra def'] = basestats.extraDefense,
  1192.                         ['arm'] = basestats.armor,
  1193.                         ['accuracy'] = basestats.hitChance,
  1194.                         ['range'] = basestats.shootRange
  1195.                 }
  1196.                
  1197.                 local uid = item:getUniqueId()
  1198.                 local fullstats = {
  1199.                         ['charges'] = getItemAttribute(uid, ITEM_ATTRIBUTE_CHARGES),
  1200.                         ['time'] = item:getBaseDuration(),
  1201.                         ['atk'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ATTACK),
  1202.                         ['def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_DEFENSE),
  1203.                         ['extra def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_EXTRADEFENSE),
  1204.                         ['arm'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ARMOR),
  1205.                         ['accuracy'] = getItemAttribute(uid, ITEM_ATTRIBUTE_HITCHANCE),
  1206.                         ['range'] = getItemAttribute(uid, ITEM_ATTRIBUTE_SHOOTRANGE)
  1207.                 }
  1208.                
  1209.                
  1210.                 if suffix == "%" then
  1211.                         if basestats2[spellname] == 0 then
  1212.                                 if cid then
  1213.                                         Player(cid):sendTextMessage(MESSAGE_INFO_DESCR, "Spell " .. spellname .. "% is not available for this item.")
  1214.                                 end
  1215.                                 return false
  1216.                         end
  1217.                         item:setAttribute(attrkeys[spellname], fullstats[spellname] + math.abs(math.floor((basestats2[spellname] * spellvalue/100)))) -- basestat intended to prevent too high values when combined with upgrade system
  1218.                 else
  1219.                         item:setAttribute(attrkeys[spellname], fullstats[spellname] + math.abs(spellvalue))
  1220.                 end
  1221.         end
  1222.         item:addStatSlot(spellname, spellvalue, suffix)
  1223.         return true
  1224. end
  1225.  
  1226. local upgradable_stats = {
  1227.         [1] = {ITEM_ATTRIBUTE_ATTACK, function(id) return id:getAttack() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.atk},
  1228.         [2] = {ITEM_ATTRIBUTE_DEFENSE, function(id) return id:getDefense() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.def},
  1229.         [3] = {ITEM_ATTRIBUTE_EXTRADEFENSE, function(id) return id:getExtraDefense() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.extradef},
  1230.         [4] = {ITEM_ATTRIBUTE_ARMOR, function(id) return id:getArmor() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.arm},
  1231.         [5] = {ITEM_ATTRIBUTE_HITCHANCE, function(id) return id:getHitChance() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.hitchance},
  1232.         [6] = {ITEM_ATTRIBUTE_SHOOTRANGE, function(id) return id:getShootRange() > 1 and id:getShootRange() or 0 end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.shootrange}
  1233. }
  1234.  
  1235. function stat_onUse(player, item, fromPosition, target, toPosition, attempt)
  1236. if not(Item(target) or Creature(target)) then return false end
  1237.  
  1238. local itemEx = {
  1239.         uid = target:isItem() and target:getUniqueId() or target:getId(),
  1240.         itemid = target:isItem() and target:getId() or 0
  1241. }
  1242.         if item.itemid == STATS_SYSTEM_CONFIG.GEM_BASIC_LEVEL then
  1243.                 if STATS_SYSTEM_CONFIG.addLevelAction then
  1244.                         local it_id = ItemType(itemEx.itemid)
  1245.                         if it_id then
  1246.                                 if not it_id:isStackable() then                        
  1247.                                         if it_id:getTransformEquipId() < 1 then
  1248.                                                 if it_id:getCharges() < 1 then
  1249.                                                         local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  1250.                                                         if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING and (item_sp_slot > 0 or it_id:getWeaponType() > 0) then
  1251.                                                                 local stat_min = 1
  1252.                                                                 if STATS_SYSTEM_CONFIG.rare_negative_level then
  1253.                                                                         stat_min = STATS_SYSTEM_CONFIG.rare_min_level
  1254.                                                                 end
  1255.                                                                
  1256.                                                                 local stat_max = #STATS_SYSTEM_CONFIG.weapon_levels
  1257.                                                                 local stat_lvl = tonumber(getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):match("%s%+%d+") or getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):match("%s%-%d+"))
  1258.                                                                 if stat_lvl == stat_max then
  1259.                                                                         player:sendTextMessage(MESSAGE_INFO_DESCR, "This item is on max level already.")
  1260.                                                                         return true
  1261.                                                                 end
  1262.                                                                
  1263.                                                                 local n_lvl = stat_lvl
  1264.                                                                 if not stat_lvl then
  1265.                                                                         stat_lvl = 0
  1266.                                                                 end
  1267.                                                                
  1268.                                                                 local chance = STATS_SYSTEM_CONFIG.levelUpgradeFormula(stat_lvl, stat_min)
  1269.                                                                 local it_u = Item(itemEx.uid)
  1270.                                                                 local it_name = it_u:getName()
  1271.                                                                 if stat_lvl > 0 then
  1272.                                                                         it_name = getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):split("+")[1]
  1273.                                                                 elseif stat_lvl < 0 then
  1274.                                                                         it_name = getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):split("-")[1]
  1275.                                                                 end
  1276.                                                                
  1277.                                                                 it_name = it_name:gsub("^%s*(.-)%s*$", "%1")
  1278.                                                                
  1279.                                                                 if math.random(1, 100) <= chance then
  1280.                                                                         n_lvl = stat_lvl + 1
  1281.                                                                 else
  1282.                                                                         if STATS_SYSTEM_CONFIG.simple.downgradeOnFail then
  1283.                                                                                 n_lvl = stat_lvl - 1
  1284.                                                                         end
  1285.                                                                 end
  1286.                                                                
  1287.                                                                 for i = 1, #upgradable_stats do
  1288.                                                                         local n_item_stat = upgradable_stats[i][2](it_id)
  1289.                                                                         if upgradable_stats[i][1] ~= ITEM_ATTRIBUTE_ATTACK or it_id:getWeaponType() ~= WEAPON_SHIELD then
  1290.                                                                                 it_u:setAttribute(upgradable_stats[i][1], getItemAttribute(itemEx.uid, upgradable_stats[i][1], true) + (upgradable_stats[i][3] * (n_lvl - stat_lvl)))
  1291.                                                                         end
  1292.                                                                 end
  1293.                                                                
  1294.                                                                 it_u:setActionId(101)
  1295.                                                                 Item(item.uid):remove(1)
  1296.                                                                 if (n_lvl - stat_lvl) > 0 then
  1297.                                                                         player:sendTextMessage(MESSAGE_INFO_DESCR, it_name:gsub("^%l", string.upper) .. " upgraded to " .. (n_lvl > 0 and "+" or "") .. n_lvl .. ".")
  1298.                                                                         toPosition:sendMagicEffect(CONST_ME_MAGIC_GREEN)
  1299.                                                                 else
  1300.                                                                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Attempt to upgrade failed.")
  1301.                                                                         toPosition:sendMagicEffect(CONST_ME_HITAREA)
  1302.                                                                 end
  1303.                                                                
  1304.                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, it_name .. (n_lvl ~= 0 and (" " .. (n_lvl > 0 and "+" or "") .. n_lvl) or ""))
  1305.                                                                 return true
  1306.                                                         end
  1307.                                                 end
  1308.                                         end
  1309.                                 end
  1310.                         end
  1311.                 end
  1312.                 return false
  1313.         end
  1314.        
  1315.         if item.itemid == STATS_SYSTEM_CONFIG.GEM_ADD_SLOT then
  1316.                 if not STATS_SYSTEM_CONFIG.addSlotAction then
  1317.                         return false
  1318.                 end
  1319.                
  1320.                 if not attempt then
  1321.                         attempt = 1
  1322.                 end
  1323.                
  1324.                 if attempt == 10 then
  1325.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Unable to add slot.")
  1326.                         return true
  1327.                 end
  1328.                
  1329.                 local it_u = Item(itemEx.uid)
  1330.                 if not it_u then
  1331.                         return false
  1332.                 end
  1333.                
  1334.                 if not STATS_SYSTEM_CONFIG.simple.enabled then
  1335.                         return false
  1336.                 end
  1337.                
  1338.                 if not STATS_SYSTEM_CONFIG.simple.randomSpells then
  1339.                         -- popup modal
  1340.                         -- popUpStatModal_index(player, item.uid)
  1341.                         print("todo: modal window")
  1342.                         return true
  1343.                 end
  1344.                
  1345.                 if isInArray(STATS_SYSTEM_CONFIG.ignoredIds, itemEx.itemid) then
  1346.                         -- player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade this item.")
  1347.                         return false
  1348.                 end
  1349.                
  1350.                 local it_id = ItemType(itemEx.itemid)
  1351.                 local u = it_u:getUpgradeType()
  1352.                
  1353.                 if not u then
  1354.                         -- player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade this item.")
  1355.                         return false
  1356.                 end
  1357.                
  1358.                 if not STATS_SYSTEM_CONFIG.upgradeMagicItems then
  1359.                         local atr = it_u:getDescription():match('%((.+)%)')
  1360.                         if atr and magic_words then
  1361.                                 if #magic_words > 0 then
  1362.                                         for i = 1, #magic_words do
  1363.                                                 if atr:match(magic_words[i]) then
  1364.                                                         player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade magic items.")
  1365.                                                         return true
  1366.                                                 end
  1367.                                         end
  1368.                                 end
  1369.                         end
  1370.                 end
  1371.                
  1372.                 local stat = math.random(1, #u)
  1373.                
  1374.                 local tries = player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage)
  1375.                 if tries < 0 then
  1376.                         player:setStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage, 0)
  1377.                 end
  1378.                
  1379.                 local level = STATS_SYSTEM_CONFIG.useSkill and getEnchantingSkill(tries) or math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  1380.                
  1381.                 local spellname = u[stat][1]   
  1382.                 local spelltype = 0
  1383.                 local available_spell_types = {}
  1384.                
  1385.                 for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  1386.                         if STATS_SYSTEM_CONFIG.STATS[i].name == spellname then
  1387.                                 if STATS_SYSTEM_CONFIG.STATS[i].enabledValues then
  1388.                                         table.insert(available_spell_types, SPELL_TYPE_VALUE)
  1389.                                 end
  1390.                                
  1391.                                 if STATS_SYSTEM_CONFIG.STATS[i].enabledPercent then
  1392.                                         table.insert(available_spell_types, SPELL_TYPE_PERCENT)
  1393.                                 end
  1394.                                
  1395.                                 if #available_spell_types > 0 then
  1396.                                         spelltype = available_spell_types[math.random(1, #available_spell_types)]
  1397.                                 end
  1398.                                 break
  1399.                         end
  1400.                 end
  1401.                
  1402.                 if spelltype == 0 then
  1403.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1404.                         return true
  1405.                 end
  1406.                
  1407.                 local spellattr = nil
  1408.                 for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  1409.                         if STATS_SYSTEM_CONFIG.STATS[i].name == spellname then
  1410.                                 spellattr = STATS_SYSTEM_CONFIG.STATS[i]
  1411.                                 break
  1412.                         end
  1413.                 end
  1414.                
  1415.                 if not spellattr then
  1416.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1417.                         return true
  1418.                 end
  1419.                        
  1420.                 local prc = (level * 100/STATS_SYSTEM_CONFIG.maxLevel)/100
  1421.                 local attrval = 0
  1422.                 local attrstr = ""
  1423.                
  1424.                 if spelltype == SPELL_TYPE_VALUE then
  1425.                         attrval = math.floor(prc * u[stat][2])
  1426.                 elseif spelltype == SPELL_TYPE_PERCENT then
  1427.                         attrval = math.floor(prc * u[stat][3])
  1428.                         attrstr = "%"
  1429.                 end
  1430.  
  1431.                 if attrval == 0 then
  1432.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1433.                         return true
  1434.                 end
  1435.                
  1436.                 local slotc = it_u:getStatSlotCount()
  1437.                 if slotc == STATS_SYSTEM_CONFIG.maxSlotCount then
  1438.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Slot limit reached.")
  1439.                         return true
  1440.                 end
  1441.                
  1442.                 local cur_slots = it_u:getStatSlots()
  1443.                 for i = 1, slotc do
  1444.                         if spellname == cur_slots[i][1] then
  1445.                                 -- player:sendTextMessage(MESSAGE_INFO_DESCR, "Duplicate stat, try again.")
  1446.                                 stat_onUse(player, item, fromPosition, itemEx, toPosition, attempt + 1)
  1447.                                 return true
  1448.                         end
  1449.                 end
  1450.  
  1451.                 if it_u:addStat(spellname, attrval, attrstr, player:getId()) then
  1452.                         toPosition:sendMagicEffect(CONST_ME_MAGIC_GREEN)
  1453.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Upgrade successful.\n" .. spellattr.spellName .. " " .. (attrval >= 0 and "+" .. attrval or attrval) .. attrstr)
  1454.                         doRemoveItem(item.uid, 1)
  1455.                         if STATS_SYSTEM_CONFIG.useSkill then
  1456.                                 player:setStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage, player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage) + 1)
  1457.                                 local nlevel = STATS_SYSTEM_CONFIG.useSkill and getEnchantingSkill(player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage)) or math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  1458.                                 if nlevel > level then
  1459.                                         player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You advanced to enchanting Level " .. (nlevel < STATS_SYSTEM_CONFIG.maxLevel and nlevel or nlevel .. " [max]") .. ".")
  1460.                                 end
  1461.                         end
  1462.                 end
  1463.                 return true
  1464.         end
  1465.        
  1466.         if isInArray({STATS_SYSTEM_CONFIG.GEM_RARE, STATS_SYSTEM_CONFIG.GEM_EPIC, STATS_SYSTEM_CONFIG.GEM_LEGENDARY, STATS_SYSTEM_CONFIG.GEM_RANDOM}, item.itemid) then
  1467.         local item2 = Item(itemEx.uid)
  1468.                 if item2 then
  1469.                         local u = item2:getUpgradeType()
  1470.                         if u then
  1471.                                 if item2:generateStats(u, STATS_SYSTEM_CONFIG.gems_power[item.itemid].sl(), math.random(STATS_SYSTEM_CONFIG.gems_power[item.itemid].min_wl, STATS_SYSTEM_CONFIG.gems_power[item.itemid].max_wl), math.floor(STATS_SYSTEM_CONFIG.maxLevel * STATS_SYSTEM_CONFIG.gems_power[item.itemid].min_el), math.ceil(STATS_SYSTEM_CONFIG.maxLevel * STATS_SYSTEM_CONFIG.gems_power[item.itemid].max_el)) then
  1472.                                         toPosition:sendMagicEffect(CONST_ME_MAGIC_GREEN)
  1473.                                         doRemoveItem(item.uid, 1)
  1474.                                         player:sendTextMessage(MESSAGE_INFO_DESCR, "Item modification successful.")
  1475.                                         return true
  1476.                                 end
  1477.                         end
  1478.                 end
  1479.                 return false
  1480.         end
  1481.         return false
  1482. end
  1483.        
  1484. local slots = {
  1485.         CONST_SLOT_HEAD,
  1486.         CONST_SLOT_NECKLACE,
  1487.         CONST_SLOT_BACKPACK,
  1488.         CONST_SLOT_ARMOR,
  1489.         CONST_SLOT_RIGHT,
  1490.         CONST_SLOT_LEFT,
  1491.         CONST_SLOT_LEGS,
  1492.         CONST_SLOT_FEET,
  1493.         CONST_SLOT_RING,
  1494.         CONST_SLOT_AMMO
  1495. }
  1496.  
  1497. local human_looktypes = {
  1498.         57, 58, 62, 63, 64, 66, 69, 70, 71, 72, 73, 75, 93, 96, 97,
  1499.         98, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137,
  1500.         138, 139, 140, 141, 142, 143, 144, 145, 145, 147, 148, 149,
  1501.         150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 193,
  1502.         194, 203, 251, 252, 253, 254, 255, 264, 266, 268, 269, 270,
  1503.         273, 278, 279, 288, 289, 302, 324, 325, 328, 329, 331, 332,
  1504.         366, 367, 386, 416, 423, 430, 431, 432, 433, 463, 464, 465,
  1505.         466, 471, 472, 493, 507, 512, 513, 513, 516, 537, 538, 539,
  1506.         541, 542, 574, 575, 577, 578, 610, 618, 619, 620
  1507. }
  1508.  
  1509. function stat_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  1510.         if origin == 2 then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1511.         if not creature then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1512.         if not attacker then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1513.         local cid = creature:getId()
  1514.         local aid = attacker:getId()
  1515.        
  1516.         -- weapon extra damage
  1517.         if attacker:isPlayer() then
  1518.                 for i = CONST_SLOT_RIGHT, CONST_SLOT_LEFT do
  1519.                         local item = attacker:getSlotItem(slots[i])
  1520.                         if item then
  1521.                                 if STATS_SYSTEM_CONFIG.reqLvlBasedOnUpgrade then
  1522.                                         if item then
  1523.                                                 if isWeapon(item:getUniqueId()) then
  1524.                                                         local lv = attacker:getLevel()
  1525.                                                         local rlv = item:getStatReqLevel()
  1526.                                                         if rlv > lv then
  1527.                                                                 local ndmg = lv/rlv
  1528.                                                                 primaryDamage = math.floor(primaryDamage * ndmg)
  1529.                                                                 secondaryDamage = math.floor(secondaryDamage * ndmg)
  1530.                                                         end
  1531.                                                 end
  1532.                                         end
  1533.                                 end
  1534.                        
  1535.                        
  1536.                                 local cur_slots = item:getStatSlots()
  1537.                                 local it_id = ItemType(item:getId())
  1538.                                 if it_id:getWeaponType() > 0 and it_id:getWeaponType() ~= WEAPON_SHIELD then
  1539.                                         local slotc = item:getStatSlotCount()
  1540.                                         if slotc > 0 then
  1541.                                                 for i = 1, slotc do
  1542.                                                         if element_stats[cur_slots[i][1]] then
  1543.                                                                 if cur_slots[i][2]:match("%%") then
  1544.                                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1545.                                                                         local dmg = math.floor((primaryDamage * (tonumber(a..b)/100)))
  1546.                                                                         if dmg > 0 then
  1547.                                                                                 doTargetCombatHealth(aid, cid, element_stats[cur_slots[i][1]].combat, 1, dmg, element_stats[cur_slots[i][1]].effect)
  1548.                                                                         end
  1549.                                                                 else
  1550.                                                                         local dmg = math.floor(math.random(0, tonumber(cur_slots[i][2])))
  1551.                                                                         if dmg > 0 then
  1552.                                                                                 doTargetCombatHealth(aid, cid, element_stats[cur_slots[i][1]].combat, 1, dmg, element_stats[cur_slots[i][1]].effect)
  1553.                                                                         end
  1554.                                                                 end
  1555.                                                         else
  1556.                                                                 if creature and attacker then
  1557.                                                                         if creature:getId() ~= attacker:getId() then
  1558.                                                                                 if cur_slots[i][1] == 'drainHP' then
  1559.                                                                                         if cur_slots[i][2]:match("%%") then
  1560.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1561.                                                                                                 local hp_d = math.floor((primaryDamage * (tonumber(a..b)/100)))
  1562.                                                                                                 if hp_d > 0 then
  1563.                                                                                                         doTargetCombatHealth(aid, cid, COMBAT_LIFEDRAIN, -hp_d, -hp_d, CONST_ME_MAGIC_RED)
  1564.                                                                                                         attacker:addHealth(hp_d)
  1565.                                                                                                 end
  1566.                                                                                         else
  1567.                                                                                                 local hp_d = math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1568.                                                                                                 if hp_d > 0 then
  1569.                                                                                                         doTargetCombatHealth(aid, cid, COMBAT_LIFEDRAIN, -hp_d, -hp_d, CONST_ME_MAGIC_RED)
  1570.                                                                                                         attacker:addHealth(hp_d)
  1571.                                                                                                 end
  1572.                                                                                         end
  1573.                                                                                 end
  1574.                                                                                
  1575.                                                                                 if cur_slots[i][1] == 'drainMP' then
  1576.                                                                                         if creature:getMana() > 0 then
  1577.                                                                                                 if cur_slots[i][2]:match("%%") then
  1578.                                                                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1579.                                                                                                         local mp_d = math.floor((primaryDamage * (tonumber(a..b)/100)))
  1580.                                                                                                         doTargetCombatMana(aid, cid, -mp_d, -mp_d)
  1581.                                                                                                         attacker:addMana(mp_d)
  1582.                                                                                                 else
  1583.                                                                                                         local mp_d = math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1584.                                                                                                         doTargetCombatMana(aid, cid, -mp_d, -mp_d)
  1585.                                                                                                         attacker:addMana(mp_d)
  1586.                                                                                                 end
  1587.                                                                                         end
  1588.                                                                                 end
  1589.                                                                         end
  1590.                                                                 end
  1591.                                                        
  1592.                                                                 if (creature:isPlayer() or isInArray(human_looktypes, creature:getOutfit().lookType)) and cur_slots[i][1] == 'humans' then
  1593.                                                                         if cur_slots[i][2]:match("%%") then
  1594.                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1595.                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1596.                                                                         else
  1597.                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1598.                                                                         end
  1599.                                                                 end
  1600.                                                                
  1601.                                                                 if creature:isMonster() then
  1602.                                                                         local race = MonsterType(creature:getName()):getRace()
  1603.                                                                         local name = creature:getName():lower()
  1604.                                                                         if cur_slots[i][1] == 'insects' then
  1605.                                                                                 if race == 1 then
  1606.                                                                                         if cur_slots[i][2]:match("%%") then
  1607.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1608.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1609.                                                                                         else
  1610.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1611.                                                                                         end
  1612.                                                                                 end
  1613.                                                                         elseif cur_slots[i][1] == 'animals' then
  1614.                                                                                 if race == 2 and not isInArray(human_looktypes, creature:getOutfit().lookType) then
  1615.                                                                                         if cur_slots[i][2]:match("%%") then
  1616.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1617.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1618.                                                                                         else
  1619.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1620.                                                                                         end
  1621.                                                                                 end
  1622.                                                                         elseif cur_slots[i][1] == 'undeads' then
  1623.                                                                                 if race == 3 then
  1624.                                                                                         if cur_slots[i][2]:match("%%") then
  1625.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1626.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1627.                                                                                         else
  1628.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1629.                                                                                         end
  1630.                                                                                 end
  1631.                                                                         elseif cur_slots[i][1] == 'elementals' then
  1632.                                                                                 if race == 4 or race == 5 or name:match("elemental") then
  1633.                                                                                         if cur_slots[i][2]:match("%%") then
  1634.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1635.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1636.                                                                                         else
  1637.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1638.                                                                                         end
  1639.                                                                                 end
  1640.                                                                         elseif cur_slots[i][1] == 'dragons' then
  1641.                                                                                 if name:match("dragon") then
  1642.                                                                                         if cur_slots[i][2]:match("%%") then
  1643.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1644.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1645.                                                                                         else
  1646.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1647.                                                                                         end
  1648.                                                                                 end
  1649.                                                                         elseif cur_slots[i][1] == 'lizards' then
  1650.                                                                                 if name:match("lizard") or name:match("draken") then
  1651.                                                                                         if cur_slots[i][2]:match("%%") then
  1652.                                                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1653.                                                                                                 primaryDamage = primaryDamage + math.floor((primaryDamage * (tonumber(a..b)/100)))
  1654.                                                                                         else
  1655.                                                                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1656.                                                                                         end
  1657.                                                                                 end
  1658.                                                                         end
  1659.                                                                 end
  1660.                                                         end
  1661.                                                 end
  1662.                                         end            
  1663.                                 end
  1664.                         end
  1665.                 end
  1666.         end
  1667.  
  1668.         -- armor elemental protection
  1669.         if creature:isPlayer() then
  1670.                 for i = 1, #slots do
  1671.                         local item = creature:getSlotItem(slots[i])
  1672.                         if item then
  1673.                                 local it_id = ItemType(item:getId())
  1674.                                
  1675.                                 if it_id:getWeaponType() == WEAPON_SHIELD or it_id:getWeaponType() == 0 then
  1676.                                 local slotc = item:getStatSlotCount()
  1677.                                         if slotc > 0 then
  1678.                                                 local cur_slots = item:getStatSlots()
  1679.                                                 for i = 1, slotc do
  1680.                                                         if element_stats[cur_slots[i][1]] then
  1681.                                                                 if cur_slots[i][2]:match("%%") then
  1682.                                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1683.                                                                         if primaryType == element_stats[cur_slots[i][1]] then
  1684.                                                                                 primaryDamage = math.floor(primaryDamage - (primaryDamage * (tonumber(a..b)/100)))
  1685.                                                                         end
  1686.  
  1687.                                                                         if secondaryType == element_stats[cur_slots[i][1]] then
  1688.                                                                                 secondaryDamage = math.floor(secondaryDamage - (secondaryDamage * (tonumber(a..b)/100)))
  1689.                                                                         end
  1690.                                                                 else
  1691.                                                                         if primaryType == element_stats[cur_slots[i][1]] then
  1692.                                                                                 primaryDamage = math.floor(primaryDamage - math.random(0, tonumber(cur_slots[i][2])))
  1693.                                                                         end
  1694.  
  1695.                                                                         if secondaryType == element_stats[cur_slots[i][1]] then
  1696.                                                                                 secondaryDamage = math.floor(secondaryDamage - math.random(0, tonumber(cur_slots[i][2])))
  1697.                                                                         end
  1698.                                                                 end
  1699.                                                         end
  1700.                                                 end            
  1701.                                         end
  1702.                                 end
  1703.                         end
  1704.                 end
  1705.         end
  1706.         return primaryDamage, primaryType, secondaryDamage, secondaryType
  1707. end
  1708.  
  1709. function stat_onManaChange(creature, attacker, manaChange, origin)
  1710.         if not creature:isPlayer() then
  1711.                 return manaChange
  1712.         end
  1713.         for i = 1, #slots do
  1714.                 local item = creature:getSlotItem(slots[i])
  1715.                 if item then
  1716.                         local it_id = ItemType(item:getId())
  1717.                        
  1718.                         if it_id:getWeaponType() == WEAPON_SHIELD or it_id:getWeaponType() == 0 then
  1719.                         local slotc = item:getStatSlotCount()
  1720.                                 if slotc > 0 then
  1721.                                         local cur_slots = item:getStatSlots()
  1722.                                         for i = 1, slotc do
  1723.                                                 if cur_slots[i][1] == 'manadrain' then
  1724.                                                         if cur_slots[i][2]:match("%%") then
  1725.                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1726.                                                                 manaChange = manaChange + (manaChange * (tonumber(a..b)/100))
  1727.                                                         else
  1728.                                                                 manaChange = manaChange + math.random(0, tonumber(cur_slots[i][2]))
  1729.                                                         end
  1730.                                                 end
  1731.                                         end            
  1732.                                 end
  1733.                         end
  1734.                 end
  1735.         end
  1736.         return manaChange
  1737. end
  1738.  
  1739. function getItemWeaponType(uid)
  1740.         local item = Item(uid)
  1741.         return item and item:getType():getWeaponType() or 0
  1742. end
  1743.  
  1744. function isWeapon(uid) return (getItemWeaponType(uid) > 0 and getItemWeaponType(uid) ~= 4) end
  1745. function isShield(uid) return getItemWeaponType(uid) == 4 end
  1746. function isBow(uid) return (getItemWeaponType(uid) == 5 and (not ItemType(getThing(uid).itemid):isStackable())) end
  1747.        
  1748. function check_slot(aab, i)
  1749.         if i == 5 or i == 6 then
  1750.                 if isWeapon(aab) or isShield(aab) or isBow(aab) then
  1751.                         return true
  1752.                 end
  1753.         else
  1754.                 return true
  1755.         end
  1756. return false
  1757. end
  1758.  
  1759. local player_regen = {
  1760.  
  1761. }
  1762.  
  1763. function stat_regen(cid, itemid, slot, checkid, sid)
  1764.  
  1765.         if not checkid then checkid = 1 end
  1766.         if not player_regen[cid] then return true end
  1767.         if not player_regen[cid][slot] then return true end
  1768.         local player = Player(cid)
  1769.         if not player then return true end
  1770.         local item = player:getSlotItem(slot)
  1771.         if not item then
  1772.                 player_regen[cid][slot] = nil
  1773.                 return true
  1774.         end
  1775.         if item:getId() ~= itemid then return true end
  1776.        
  1777.         local slotc = item:getStatSlotCount()
  1778.         if slotc == 0 then
  1779.                 player_regen[cid][slot] = nil
  1780.                 return true
  1781.         end
  1782.        
  1783.         player_regen[cid][slot] = player_regen[cid][slot] + 1
  1784.         if checkid == 60 then
  1785.                 local cur_slots = item:getStatSlots()
  1786.                 for i = 1, slotc do
  1787.                         if cur_slots[i][1] == 'regHP' or cur_slots[i][1] == 'regMP' then
  1788.                                 if cur_slots[i][2]:match("%%") then
  1789.                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1790.                                         if cur_slots[i][1] == 'regHP' then
  1791.                                                 player:addHealth(math.ceil(player:getVocation():getHealthGainAmount() * (tonumber(a..b))/100))
  1792.                                         end
  1793.                                        
  1794.                                         if cur_slots[i][1] == 'regMP' then
  1795.                                                 player:addMana(math.ceil(player:getVocation():getManaGainAmount() * (tonumber(a..b))/100))
  1796.                                         end
  1797.                                 else
  1798.                                         if cur_slots[i][1] == 'regHP' then
  1799.                                                 player:addHealth(tonumber(cur_slots[i][2]))
  1800.                                         end
  1801.                                        
  1802.                                         if cur_slots[i][1] == 'regMP' then
  1803.                                                 player:addMana(tonumber(cur_slots[i][2]))
  1804.                                         end
  1805.                                 end
  1806.                         end
  1807.                 end
  1808.                 checkid = 1
  1809.         end
  1810.         addEvent(stat_regen, 100, cid, itemid, slot, checkid + 1, sid + 1)
  1811.         return true
  1812. end
  1813.  
  1814. local eq_stat_conditions = {'hp', 'mp', 'ml', 'melee', 'shield', 'dist'}
  1815. function stat_load(cid)
  1816. local player = Player(cid)
  1817. local v_stat_percent = {}
  1818. local v_stat_normal = {}
  1819.         for j = 1, 9 do
  1820.                 local item = player:getSlotItem(j)
  1821.                 if item then
  1822.                         local slotc = item:getStatSlotCount()
  1823.                         if slotc > 0 then
  1824.                                 local cur_slots = item:getStatSlots()
  1825.                                 for i = 1, slotc do
  1826.                                         if isInArray(eq_stat_conditions, cur_slots[i][1]) then
  1827.                                                 if cur_slots[i][2]:match("%%") then
  1828.                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1829.                                                         if not v_stat_percent[cur_slots[i][1]] then
  1830.                                                                 v_stat_percent[cur_slots[i][1]] = 0
  1831.                                                         end
  1832.                                                         v_stat_percent[cur_slots[i][1]] = v_stat_percent[cur_slots[i][1]] + (tonumber(a..b)/100)
  1833.                                                 else
  1834.                                                         if not v_stat_normal[cur_slots[i][1]] then
  1835.                                                                 v_stat_normal[cur_slots[i][1]] = 0
  1836.                                                         end
  1837.                                                         v_stat_normal[cur_slots[i][1]] = v_stat_normal[cur_slots[i][1]] + tonumber(cur_slots[i][2])
  1838.                                                 end
  1839.                                         else
  1840.                                                 if cur_slots[i][1] == 'regHP' or cur_slots[i][1] == 'regMP' then
  1841.                                                         if not player_regen[cid] then player_regen[cid] = {} end
  1842.                                                         if not player_regen[cid][j] then player_regen[cid][j] = 1 end
  1843.                                                         local value = tonumber(cur_slots[i][2])
  1844.                                                         if not value then
  1845.                                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1846.                                                                 value = tonumber(a..b)/100
  1847.                                                         end
  1848.                                                         player_regen[cid][j] = 1
  1849.                                                         stat_regen(cid, item:getId(), j, 1, 1)
  1850.                                                 end
  1851.                                         end
  1852.                                 end
  1853.                         end
  1854.                 end
  1855.         end
  1856.        
  1857.         local fu = 0 -- functions used
  1858.         local ca = {} -- conditions assigned
  1859.         for i = 1, #eq_stat_conditions do
  1860.                 if eq_stat_conditions[i] == 'hp' then
  1861.                         if v_stat_normal[eq_stat_conditions[i]] then
  1862.                                 fu = fu+1
  1863.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(1500, v_stat_normal[eq_stat_conditions[i]]), -1500))])
  1864.                                 ca[56] = 1
  1865.                         end
  1866.                        
  1867.                         if v_stat_percent[eq_stat_conditions[i]] then
  1868.                                 fu = fu+1
  1869.                                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1870.                                 ca[50] = 1
  1871.                         end
  1872.                 elseif eq_stat_conditions[i] == 'mp' then
  1873.                         if v_stat_normal[eq_stat_conditions[i]] then
  1874.                                 fu = fu+1
  1875.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(1500, v_stat_normal[eq_stat_conditions[i]]), -1500))])
  1876.                                 ca[57] = 1
  1877.                         end
  1878.                        
  1879.                         if v_stat_percent[eq_stat_conditions[i]] then
  1880.                                 fu = fu+1
  1881.                                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1882.                                 ca[51] = 1
  1883.                         end
  1884.                 elseif eq_stat_conditions[i] == 'ml' then
  1885.                         if v_stat_normal[eq_stat_conditions[i]] then
  1886.                                 fu = fu+1
  1887.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100))])
  1888.                                 ca[58] = 1
  1889.                         end
  1890.                        
  1891.                         if v_stat_percent[eq_stat_conditions[i]] then
  1892.                                 fu = fu+1
  1893.                                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1894.                                 ca[52] = 1
  1895.                         end
  1896.                 elseif eq_stat_conditions[i] == 'melee' then
  1897.                         if v_stat_normal[eq_stat_conditions[i]] then
  1898.                                 fu = fu+1
  1899.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100))])
  1900.                                 ca[59] = 1
  1901.                         end
  1902.                        
  1903.                         if v_stat_percent[eq_stat_conditions[i]] then
  1904.                                 fu = fu+1
  1905.                                 doAddCondition(cid, stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1906.                                 ca[53] = 1
  1907.                         end
  1908.                 elseif eq_stat_conditions[i] == 'shield' then
  1909.                         if v_stat_normal[eq_stat_conditions[i]] then
  1910.                                 fu = fu+1
  1911.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100))])
  1912.                                 ca[60] = 1
  1913.                         end
  1914.                        
  1915.                         if v_stat_percent[eq_stat_conditions[i]] then
  1916.                                 fu = fu+1
  1917.                                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1918.                                 ca[54] = 1
  1919.                         end
  1920.                 elseif eq_stat_conditions[i] == 'dist' then
  1921.                         if v_stat_normal[eq_stat_conditions[i]] then
  1922.                                 fu = fu+1
  1923.                                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.floor(math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100))])
  1924.                                 ca[61] = 1
  1925.                         end
  1926.                        
  1927.                         if v_stat_percent[eq_stat_conditions[i]] then
  1928.                                 fu = fu+1
  1929.                                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.floor(math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95))])
  1930.                                 ca[55] = 1
  1931.                         end
  1932.                 end
  1933.         end
  1934.         if fu > 0 then
  1935.                 for i=50,61 do
  1936.                         if not ca[i] then
  1937.                                 doRemoveCondition(cid,CONDITION_ATTRIBUTES,i)
  1938.                         end
  1939.                 end
  1940.         else
  1941.                 for i=50,61 do
  1942.                         doRemoveCondition(cid,CONDITION_ATTRIBUTES,i)
  1943.                 end
  1944.         end
  1945.        
  1946.         return true
  1947. end
  1948.  
  1949. function loadSet(cid)
  1950. local player = Player(cid)
  1951. local t = {}
  1952.         if player then
  1953.                 for slot=1,9 do
  1954.                         t[slot] = ''
  1955.                         local s = player:getSlotItem(slot)
  1956.                         if s then
  1957.                                 t[slot] = s:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
  1958.                         end
  1959.                 end
  1960.         end
  1961.         return t
  1962. end
  1963.  
  1964. function chk(cid,f)
  1965.         if not isPlayer(cid) then return false end
  1966.         local t = loadSet(cid)
  1967.         for i=1,#f do
  1968.                 if f[i] ~= t[i] then
  1969.                         stat_load(cid)
  1970.                         break
  1971.                 end
  1972.         end
  1973.         addEvent(chk,2000,cid,t)
  1974. end
  1975.  
  1976. function stat_onLogin(player)
  1977.         if STATS_SYSTEM_CONFIG.combatStats then
  1978.                 player:registerEvent("statHP")
  1979.                 player:registerEvent("statMP")
  1980.         end
  1981.        
  1982.         if STATS_SYSTEM_CONFIG.PVEStat then
  1983.                 player:registerEvent("statPVE")
  1984.         end
  1985.        
  1986.         if STATS_SYSTEM_CONFIG.monsterLoot or STATS_SYSTEM_CONFIG.xpStat or STATS_SYSTEM_CONFIG.lootStat then
  1987.                 player:registerEvent("statLoot")
  1988.         end
  1989.        
  1990.         if STATS_SYSTEM_CONFIG.conditionStats then
  1991.                 local cid = player:getId()
  1992.                 stat_load(cid)
  1993.                 addEvent(chk,2000,cid,loadSet(cid))
  1994.         end
  1995. return true
  1996. end
  1997.  
  1998. function stat_onPrepareDeath(creature, lastHitKiller, mostDamageKiller)
  1999.         local necklace = creature:getSlotItem(CONST_SLOT_NECKLACE)
  2000.        
  2001.         if not Player(lastHitKiller) then
  2002.                 if necklace then
  2003.                         local slotc = necklace:getStatSlotCount()
  2004.                         if slotc > 0 then
  2005.                                 local cur_slots = necklace:getStatSlots()
  2006.                                 for i = 1, slotc do
  2007.                                         if cur_slots[i][1] == 'PVE death' then
  2008.                                                 if cur_slots[i][2]:match("%%") then
  2009.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  2010.                                                         if math.random(1, 100) > tonumber(a..b) then
  2011.                                                                 necklace:remove()
  2012.                                                                 return true
  2013.                                                         end
  2014.                                                 end
  2015.                                                 local maxhp = creature:getMaxHealth()
  2016.                                                 creature:addHealth(maxhp)
  2017.                                                 addEvent(doCreatureAddHealth, 100, creature:getId(), maxhp)
  2018.                                                 creature:teleportTo(creature:getTown():getTemplePosition())
  2019.                                                 necklace:remove()
  2020.                                                 return true
  2021.                                         end
  2022.                                 end
  2023.                         end
  2024.                 end
  2025.         end
  2026. return true
  2027. end
  2028.  
  2029. function stat_onTargetCombat(self, target)
  2030.         if Player(self) then
  2031.                 if STATS_SYSTEM_CONFIG.combatStats then
  2032.                         target:registerEvent("statHP")
  2033.                         target:registerEvent("statDeath")
  2034.                 end
  2035.         end
  2036.         return true
  2037. end
  2038.                                        
  2039. function assign_loot_Stat(c)
  2040.         local wp_string = {"", ""}
  2041.         local arm_string = {"", ""}
  2042.         local other_string = {"", ""}
  2043.         local rares = 0
  2044.         local h = c:getItemHoldingCount()
  2045.         if h > 0 then
  2046.                 for i = 1, h do
  2047.                         wp_string = {"", ""}
  2048.                         arm_string = {"", ""}
  2049.                         other_string = {"", ""}
  2050.                         local it_u = c:getItem(i - 1)
  2051.                         local u = it_u:getUpgradeType()
  2052.                         local upgrade = true
  2053.                         local it_id = ItemType(it_u:getId())
  2054.                         local slotc = 0
  2055.                        
  2056.                         if not isInArray(STATS_SYSTEM_CONFIG.ignoredIds, it_u:getId()) then
  2057.                                 if it_u:isContainer() then
  2058.                                         local crares = assign_loot_Stat(it_u)
  2059.                                         rares = rares + crares
  2060.                                         upgrade = false
  2061.                                 else
  2062.                                         if it_id:isStackable() then
  2063.                                                 upgrade = false
  2064.                                         end
  2065.                                        
  2066.                                         if u then
  2067.                                                 local atr = it_u:getDescription():match('%((.+)%)')
  2068.                                                 if atr and magic_words then
  2069.                                                         if #magic_words > 0 then
  2070.                                                                 for j = 1, #magic_words do
  2071.                                                                         if atr:match(magic_words[j]) then
  2072.                                                                                 if not STATS_SYSTEM_CONFIG.upgradeMagicItems then
  2073.                                                                                         upgrade = false
  2074.                                                                                 end
  2075.                                                                         end
  2076.                                                                 end
  2077.                                                         end
  2078.                                                 end
  2079.                                         end
  2080.                                 end
  2081.  
  2082.                                 if u and upgrade then
  2083.                                         for n = 1, #STATS_SYSTEM_CONFIG.slotChances do
  2084.                                                 if math.random(1, 100000) <= STATS_SYSTEM_CONFIG.slotChances[n] then
  2085.                                                         if slotc + 1 == n then
  2086.                                                                 local stat = math.random(1, #u)
  2087.                                                                 local level = math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  2088.                                                                 local spellname = u[stat][1]
  2089.                                                                 local spelltype = 0
  2090.                                                                 local available_spell_types = {}       
  2091.                                                                 local statdone = false
  2092.                                                                 for k = 1, #STATS_SYSTEM_CONFIG.STATS do
  2093.                                                                         if not statdone then
  2094.                                                                                 if STATS_SYSTEM_CONFIG.STATS[k].name == spellname then
  2095.                                                                                         if STATS_SYSTEM_CONFIG.STATS[k].enabledValues then
  2096.                                                                                                 table.insert(available_spell_types, SPELL_TYPE_VALUE)
  2097.                                                                                         end
  2098.                                                                                        
  2099.                                                                                         if STATS_SYSTEM_CONFIG.STATS[k].enabledPercent then
  2100.                                                                                                 table.insert(available_spell_types, SPELL_TYPE_PERCENT)
  2101.                                                                                         end
  2102.                                                                                        
  2103.                                                                                         if #available_spell_types > 0 then
  2104.                                                                                                 spelltype = available_spell_types[math.random(1, #available_spell_types)]
  2105.                                                                                         end
  2106.                                                                                        
  2107.                                                                                         wp_string = (STATS_SYSTEM_CONFIG.STATS[k].weaponLootName or wp_string)
  2108.                                                                                         arm_string = (STATS_SYSTEM_CONFIG.STATS[k].armorLootName or arm_string)
  2109.                                                                                         other_string = (STATS_SYSTEM_CONFIG.STATS[k].otherLootName or other_string)
  2110.                                                                                        
  2111.                                                                                         statdone = true
  2112.                                                                                 end
  2113.                                                                         end
  2114.                                                                 end
  2115.                                                                
  2116.                                                                 if spelltype == 0 then
  2117.                                                                         upgrade = false
  2118.                                                                 end
  2119.                                                                
  2120.                                                                 local spellattr = nil
  2121.                                                                 for l = 1, #STATS_SYSTEM_CONFIG.STATS do
  2122.                                                                         if not spellattr then
  2123.                                                                                 if STATS_SYSTEM_CONFIG.STATS[l].name == spellname then
  2124.                                                                                         spellattr = STATS_SYSTEM_CONFIG.STATS[l]
  2125.                                                                                 end
  2126.                                                                         end
  2127.                                                                 end
  2128.                                                                
  2129.                                                                 if not spellattr then
  2130.                                                                         upgrade = false
  2131.                                                                 end
  2132.                                                                
  2133.                                                                 if upgrade then
  2134.                                                                         local prc = (level * 100/STATS_SYSTEM_CONFIG.maxLevel)/100
  2135.                                                                         local attrval = 0
  2136.                                                                         local attrstr = ""
  2137.                                                                        
  2138.                                                                         if spelltype == SPELL_TYPE_VALUE then
  2139.                                                                                 attrval = math.floor(prc * u[stat][2])
  2140.                                                                         elseif spelltype == SPELL_TYPE_PERCENT then
  2141.                                                                                 attrval = math.floor(prc * u[stat][3])
  2142.                                                                                 attrstr = "%"
  2143.                                                                         end
  2144.                                                                        
  2145.                                                                         if attrval == 0 then
  2146.                                                                                 upgrade = false
  2147.                                                                         end
  2148.                                                                        
  2149.                                                                         local slotcx = it_u:getStatSlotCount()
  2150.                                                                         if slotcx == STATS_SYSTEM_CONFIG.maxSlotCount and upgrade then
  2151.                                                                                 upgrade = false
  2152.                                                                         end
  2153.                                                                        
  2154.                                                                         if upgrade then
  2155.                                                                                 local cur_slots = it_u:getStatSlots()
  2156.                                                                                 for m = 1, slotcx do
  2157.                                                                                         if spellname == cur_slots[m][1] then
  2158.                                                                                                 upgrade = false
  2159.                                                                                         end
  2160.                                                                                 end
  2161.                                                                         end
  2162.                                                                        
  2163.                                                                         if upgrade then
  2164.                                                                                 if it_u:addStat(spellname, attrval, attrstr) then
  2165.                                                                                         it_u:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
  2166.                                                                                         rares = rares + 1
  2167.                                                                                         slotc = slotc + 1
  2168.                                                                                 end
  2169.                                                                         end
  2170.                                                                 end
  2171.                                                         end
  2172.                                                 end
  2173.                                         end
  2174.                                         local uid = it_u:getUniqueId()
  2175.                                         if slotc > 1 then
  2176.                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, (STATS_SYSTEM_CONFIG.tiers[slotc] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME))
  2177.                                         elseif slotc == 1 then
  2178.                                                 local wp = it_id:getWeaponType()
  2179.                                                 if wp > 0 then
  2180.                                                         if wp == WEAPON_SHIELD then
  2181.                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, (arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or ""))
  2182.                                                         elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE, WEAPON_DISTANCE, WEAPON_WAND}, wp) then -- weapon
  2183.                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((wp_string[1] ~= "" and wp_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (wp_string[2] ~= "" and " " .. wp_string[2] or "")))
  2184.                                                         end
  2185.                                                 else
  2186.                                                         if it_id:getArmor() > 0 then -- armor
  2187.                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or "")))
  2188.                                                         else
  2189.                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((other_string[1] ~= "" and other_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (other_string[2] ~= "" and " " .. other_string[2] or "")))
  2190.                                                         end
  2191.                                                 end
  2192.                                         end
  2193.                                 end
  2194.                         end
  2195.                        
  2196.                         if STATS_SYSTEM_CONFIG.rare_loot_level then
  2197.                                 if not it_id:isStackable() then
  2198.                                         if it_id:getTransformEquipId() < 1 then
  2199.                                                 if it_id:getCharges() < 1 then
  2200.                                                         local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  2201.                                                         if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING then
  2202.                                                                 local stat_min = 1
  2203.                                                                 if STATS_SYSTEM_CONFIG.rare_negative_level then
  2204.                                                                         stat_min = STATS_SYSTEM_CONFIG.rare_min_level
  2205.                                                                 end
  2206.                                                                
  2207.                                                                 local stat_max = #STATS_SYSTEM_CONFIG.weapon_levels
  2208.                                                                 local it_lvl = math.random(stat_min, stat_max)
  2209.                                                                
  2210.                                                                 if STATS_SYSTEM_CONFIG.weapon_levels[it_lvl] then
  2211.                                                                         if math.random(1, 100000) <= STATS_SYSTEM_CONFIG.weapon_levels[it_lvl][2] then
  2212.                                                                                 for o = 1, #upgradable_stats do
  2213.                                                                                         local n_item_stat = upgradable_stats[o][2](it_id)
  2214.                                                                                         if n_item_stat ~= 0 then
  2215.                                                                                                 it_u:setAttribute(upgradable_stats[o][1], n_item_stat + (upgradable_stats[o][3] * it_lvl))
  2216.                                                                                         end
  2217.                                                                                 end
  2218.                                                                                
  2219.                                                                                 local uid = it_u:getUniqueId()
  2220.                                                                                 if slotc == 0 then
  2221.                                                                                         it_u:setAttribute(ITEM_ATTRIBUTE_NAME, STATS_SYSTEM_CONFIG.weapon_levels[it_lvl][1] .. " " .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME))
  2222.                                                                                 end
  2223.                                                                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. " " .. (it_lvl > 0 and "+" or "") .. it_lvl)
  2224.                                                                                
  2225.                                                                                 if it_lvl > 0 then
  2226.                                                                                         rares = rares + 1
  2227.                                                                                 end
  2228.                                                                         end
  2229.                                                                 end
  2230.                                                         end
  2231.                                                 end
  2232.                                         end
  2233.                                 end
  2234.                         end            
  2235.                 end
  2236.         end
  2237.         return rares
  2238. end
  2239.  
  2240. function improveChance(c, monsterName, extraPercent, killer)
  2241.         local m = MonsterType(monsterName):getLoot()
  2242.         if math.random(1, 100) <= extraPercent then
  2243.                 local t = {}
  2244.                 for i = 1, #m do
  2245.                         t[i] = {itemId = m[i].itemId, chance = m[i].chance}
  2246.                 end
  2247.                
  2248.                 local min = 1
  2249.                 local t_s = {}
  2250.                 local low5 = #t-5
  2251.                 while #t > low5 do
  2252.                         min = 1
  2253.                         for i = 1, #t do
  2254.                                 if math.min(t[i].chance, t[min].chance) == t[i].chance then
  2255.                                         min = i
  2256.                                 end
  2257.                         end
  2258.                         t_s[#t_s + 1] = {itemId = t[min].itemId, chance = t[min].chance}
  2259.                         table.remove(t, min)
  2260.                 end
  2261.                
  2262.                 local chosenId = math.random(1, #t_s)
  2263.                
  2264.                 local h = c:getItemHoldingCount()
  2265.                 if h > 0 then
  2266.                         local extra = true
  2267.                         for i = 1, h do
  2268.                                 if ItemType(c:getItem(i - 1):getId()) == t_s[chosenId].itemId then
  2269.                                         extra = false
  2270.                                         break
  2271.                                 end
  2272.                         end
  2273.                        
  2274.                         if extra then
  2275.                                 if math.random(1, 100000) <= (t_s[chosenId].chance + (t_s[chosenId].chance * extraPercent / 100)) * configManager.getNumber(configKeys.RATE_LOOT) then
  2276.                                         c:addItem(m[chosenId].itemId, 1)
  2277.                                         if killer then
  2278.                                                 local iid = ItemType(m[chosenId].itemId)
  2279.                                                 Player(killer):sendTextMessage(MESSAGE_EVENT_ADVANCE, "Extra loot: " .. (iid:getArticle() ~= "" and iid:getArticle() .. " " or "") .. iid:getName())
  2280.                                         end
  2281.                                 end
  2282.                         end
  2283.                 end
  2284.         end                                    
  2285.         return true
  2286. end
  2287.  
  2288. function improveStackables(c, v)
  2289.         local h = c:getItemHoldingCount()
  2290.         if h > 0 then
  2291.                 for i = 1, h do
  2292.                         local it_u = c:getItem(i - 1)
  2293.                         local it_id = ItemType(it_u)
  2294.                         if it_id:isStackable() then
  2295.                                 local amount = math.random(0, v)
  2296.                                 if amount > 0 then
  2297.                                         c:addItem(it_u:getId(), amount)
  2298.                                 end
  2299.                         elseif it_u:isContainer() then
  2300.                                 improveStackables(it_u, v)
  2301.                         end
  2302.                 end
  2303.         end
  2304. return true
  2305. end
  2306.  
  2307. function find_loot_Container(pos, extraPercent, monsterName, extraStackable, killer)
  2308.         local rares = 0
  2309.         local c = Tile(pos):getTopDownItem()
  2310.         if c ~= nil then
  2311.                 if c:isContainer() then
  2312.                         if STATS_SYSTEM_CONFIG.monsterLoot then
  2313.                                 rares = rares + assign_loot_Stat(c)
  2314.                         end
  2315.                        
  2316.                         if rares > 0 then
  2317.                                 if STATS_SYSTEM_CONFIG.rare_popup then
  2318.                                         local spectators = Game.getSpectators(pos, false, true, 7, 7, 5, 5)
  2319.                                         for i = 1, #spectators do
  2320.                                                 spectators[i]:say(STATS_SYSTEM_CONFIG.rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], pos)
  2321.                                         end
  2322.                                 end
  2323.  
  2324.                                 if STATS_SYSTEM_CONFIG.rare_effect then
  2325.                                         pos:sendMagicEffect(STATS_SYSTEM_CONFIG.rare_effect_id)
  2326.                                 end
  2327.                         end
  2328.                        
  2329.                         if extraPercent then
  2330.                                 if extraPercent > 0 then
  2331.                                         if monsterName then
  2332.                                                 improveChance(c, monsterName, extraPercent, killer)
  2333.                                         end
  2334.                                 end
  2335.                         end
  2336.                        
  2337.                         if extraStackable then
  2338.                                 if extraStackable > 0 then
  2339.                                         improveStackables(c, extraStackable)
  2340.                                 end
  2341.                         end
  2342.                 end
  2343.         end
  2344. end
  2345.  
  2346. function Creature:isSummon()
  2347.         return self:getMaster()
  2348. end
  2349.  
  2350. function stat_onKill(player, target, lastHit)
  2351.         local extraPercent = 0
  2352.         local extraStackable = 0
  2353.  
  2354.         if target:isMonster() then
  2355.                 local ring = player:getSlotItem(CONST_SLOT_RING)
  2356.                 local monster = MonsterType(target:getName())
  2357.                 if ring then
  2358.                         local slotc = ring:getStatSlotCount()
  2359.                         local cur_slots = ring:getStatSlots()
  2360.                         if slotc > 0 then
  2361.                                 for i = 1, slotc do
  2362.                                         if cur_slots[i][1] == 'exp' and STATS_SYSTEM_CONFIG.xpStat then
  2363.                                                 local nexp = monster:getExperience()
  2364.                                                 local k = Game.getExperienceStage(player:getLevel())
  2365.                                                 local st = player:getStamina()
  2366.                                                 if st > 2400 then
  2367.                                                         nexp = nexp * k*1.5
  2368.                                                 elseif st < 1 then
  2369.                                                         nexp =  0
  2370.                                                 elseif st < 841 then
  2371.                                                         nexp = math.floor(nexp/2)
  2372.                                                 else
  2373.                                                         nexp = nexp
  2374.                                                 end
  2375.                                                
  2376.                                                 if cur_slots[i][2]:match("%%") then
  2377.                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  2378.                                                         player:addExperience(math.ceil((nexp * tonumber(a..b)) / 100), true)
  2379.                                                 else
  2380.                                                         player:addExperience(math.random(1, tonumber(cur_slots[i][2])), true)
  2381.                                                 end
  2382.                                         elseif cur_slots[i][1] == 'loot' and STATS_SYSTEM_CONFIG.lootStat then
  2383.                                                 if cur_slots[i][2]:match("%%") then
  2384.                                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  2385.                                                         extraPercent = extraPercent + tonumber(a..b)
  2386.                                                 else
  2387.                                                         extraStackable = extraStackable + tonumber(cur_slots[i][2])
  2388.                                                 end
  2389.                                         end
  2390.                                 end
  2391.                         end
  2392.                 end
  2393.         end
  2394.  
  2395.         if not STATS_SYSTEM_CONFIG.lootUpgradedItems then
  2396.                 return true
  2397.         end
  2398.        
  2399.         if target:isPlayer() or target:isSummon() then
  2400.                 return true
  2401.         end
  2402.        
  2403.         addEvent(find_loot_Container, 2, target:getPosition(), extraPercent, target:getName(), extraStackable, player:getId())
  2404.         return true
  2405. end
  2406.  
  2407. function Item:removeSlot(slotid)
  2408.         if not tonumber(slotid) then slotid = 0 end
  2409.         local slots = self:getStatSlotCount()
  2410.         if slotid == 0 then
  2411.                 slotid = slots
  2412.         end
  2413.         local first_desc = self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
  2414.         local slot_t = self:getStatSlots()
  2415.         self:removeAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
  2416.         for i = 1, slots do
  2417.                 if i == slotid then
  2418.                         local spellname = slot_t[i][1]
  2419.                         if isInArray({'charges', 'time', 'atk', 'def', 'extra def', 'arm', 'accuracy', 'range'}, spellname) then
  2420.                                 local basestats = self:getBaseStatsInfo()
  2421.                                 local basestats2 = {
  2422.                                         ['charges'] = basestats.charges,
  2423.                                         ['time'] = basestats.duration,
  2424.                                         ['atk'] = basestats.attack,
  2425.                                         ['def'] = basestats.defense,
  2426.                                         ['extra def'] = basestats.extraDefense,
  2427.                                         ['arm'] = basestats.armor,
  2428.                                         ['accuracy'] = basestats.hitChance,
  2429.                                         ['range'] = basestats.shootRange
  2430.                                 }
  2431.                                
  2432.                                 local uid = self:getUniqueId()
  2433.                                 local fullstats = {
  2434.                                         ['charges'] = getItemAttribute(uid, ITEM_ATTRIBUTE_CHARGES),
  2435.                                         ['time'] = self:getBaseDuration(),
  2436.                                         ['atk'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ATTACK),
  2437.                                         ['def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_DEFENSE),
  2438.                                         ['extra def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_EXTRADEFENSE),
  2439.                                         ['arm'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ARMOR),
  2440.                                         ['accuracy'] = getItemAttribute(uid, ITEM_ATTRIBUTE_HITCHANCE),
  2441.                                         ['range'] = getItemAttribute(uid, ITEM_ATTRIBUTE_SHOOTRANGE)
  2442.                                 }
  2443.                                
  2444.                                 if slot_t[i][2]:match("%%") then
  2445.                                         local a, b = slot_t[i][2]:match('([+-])(%d+)%%')
  2446.                                         self:setAttribute(attrkeys[spellname], fullstats[spellname] - math.abs(math.floor((basestats2[spellname] * tonumber(a..b)/100))))
  2447.                                 else
  2448.                                         self:setAttribute(attrkeys[spellname], fullstats[spellname] - tonumber(slot_t[i][2]))
  2449.                                 end
  2450.                         end
  2451.                 else
  2452.                         if slot_t[i][2]:match("%%") then
  2453.                                 local a, b = slot_t[i][2]:match('([+-])(%d+)%%')
  2454.                                 self:addSlot(slot_t[i][1], tonumber(a..b), true)
  2455.                         else
  2456.                                 self:addSlot(slot_t[i][1], tonumber(slot_t[i][2]), false)
  2457.                         end
  2458.                 end
  2459.         end    
  2460.         return true
  2461. end
  2462.  
  2463. function Item:clearUpgrades()
  2464.         local slots = self:getStatSlotCount()
  2465.         if slots > 0 then
  2466.                 for i = 1, slots do
  2467.                         self:removeSlot(i)
  2468.                 end
  2469.         end
  2470.        
  2471.         self:removeAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
  2472.         self:removeAttribute(ITEM_ATTRIBUTE_NAME)
  2473.         self:removeAttribute(ITEM_ATTRIBUTE_ARTICLE)
  2474.         self:removeAttribute(ITEM_ATTRIBUTE_PLURALNAME)
  2475.         self:removeAttribute(ITEM_ATTRIBUTE_ATTACK)
  2476.         self:removeAttribute(ITEM_ATTRIBUTE_DEFENSE)
  2477.         self:removeAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE)
  2478.         self:removeAttribute(ITEM_ATTRIBUTE_ARMOR)
  2479.         self:removeAttribute(ITEM_ATTRIBUTE_HITCHANCE)
  2480.         self:removeAttribute(ITEM_ATTRIBUTE_SHOOTRANGE)
  2481.         self:removeAttribute(ITEM_ATTRIBUTE_DURATION)
  2482.         self:removeAttribute(ITEM_ATTRIBUTE_CHARGES)
  2483. return true
  2484. end
  2485.  
  2486. function Item:addLevel(change)
  2487.         if not self then return false end
  2488.         if not change then return false end
  2489.        
  2490.         local it_id = self:getType()
  2491.        
  2492.         if not it_id then return false end
  2493.         if it_id:isStackable()then return false end
  2494.  
  2495.         if it_id:getTransformEquipId() < 1 then
  2496.                 if it_id:getCharges() < 1 then
  2497.                         local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  2498.                         if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING then
  2499.                                 local exu = self:getUniqueId()
  2500.                                 local stat_lvl = self:getLevel()
  2501.                                 if not stat_lvl then stat_lvl = 0 end
  2502.                                
  2503.                                 local it_name = self:getName()
  2504.                                 if stat_lvl > 0 then
  2505.                                         it_name = getItemAttribute(exu, ITEM_ATTRIBUTE_NAME):split("+")[1]
  2506.                                 elseif stat_lvl < 0 then
  2507.                                         it_name = getItemAttribute(exu, ITEM_ATTRIBUTE_NAME):split("-")[1]
  2508.                                 end
  2509.  
  2510.                                 it_name = it_name:gsub("^%s*(.-)%s*$", "%1")
  2511.                                 for i = 1, #upgradable_stats do
  2512.                                         local n_item_stat = upgradable_stats[i][2](it_id)
  2513.                                         self:setAttribute(upgradable_stats[i][1], getItemAttribute(exu, upgradable_stats[i][1], true) + (upgradable_stats[i][3] * change))
  2514.                                 end
  2515.                                
  2516.                                 self:setActionId(101)
  2517.                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, it_name .. (change + stat_lvl ~= 0 and (" " .. (change + stat_lvl > 0 and "+" or "") .. change + stat_lvl) or ""))
  2518.                                 return true
  2519.                         end
  2520.                 end
  2521.         end
  2522. return false
  2523. end
  2524.  
  2525. function Item:getLevel()
  2526.         if not self then return nil end
  2527.         local uid = self:getUniqueId()
  2528.         return tonumber(getItemAttribute(uid, ITEM_ATTRIBUTE_NAME):match("%s%+%d+") or getItemAttribute(uid, ITEM_ATTRIBUTE_NAME):match("%s%-%d+")) or 0
  2529. end
  2530.  
  2531. function Item:setLevel(level)
  2532.         self:addLevel(level - self:getLevel())
  2533.         return true
  2534. end
  2535.  
  2536. STATSLOT_TYPE_NORMAL = 1
  2537. STATSLOT_TYPE_PERCENT = 2
  2538.  
  2539. function Item:generateTier(slots)
  2540. --[[
  2541.         example slots: {
  2542.                 {'fire', '5', STATSLOT_TYPE_PERCENT},
  2543.                 {'ice', '20', STATSLOT_TYPE_NORMAL}
  2544.         }
  2545. ]]
  2546.         if not self then return false end
  2547.         if not slots then return false end
  2548.         local fslotc = 0
  2549.  
  2550.         self:clearUpgrades()
  2551.         local slotc = #slots
  2552.         if slotc > 0 then
  2553.                 local upgrade = true
  2554.                 for i = 1, slotc do
  2555.                         local spellname = slots[i][1]
  2556.                         local spelltype = 0
  2557.                         local available_spell_types = {}
  2558.                         upgrade = true
  2559.                        
  2560.                         for k = 1, #STATS_SYSTEM_CONFIG.STATS do
  2561.                                 if STATS_SYSTEM_CONFIG.STATS[k].name == spellname then
  2562.                                         if STATS_SYSTEM_CONFIG.STATS[k].enabledValues and slots[i][3] == STATSLOT_TYPE_NORMAL then
  2563.                                                 spelltype = SPELL_TYPE_VALUE
  2564.                                         elseif STATS_SYSTEM_CONFIG.STATS[k].enabledPercent and slots[i][3] == STATSLOT_TYPE_PERCENT then
  2565.                                                 spelltype = SPELL_TYPE_PERCENT
  2566.                                         end
  2567.                                         wp_string = (STATS_SYSTEM_CONFIG.STATS[k].weaponLootName or "")
  2568.                                         arm_string = (STATS_SYSTEM_CONFIG.STATS[k].armorLootName or "")
  2569.                                         other_string = (STATS_SYSTEM_CONFIG.STATS[k].otherLootName or "")
  2570.                                 end
  2571.                         end
  2572.                        
  2573.                         if spelltype == 0 then
  2574.                                 upgrade = false
  2575.                         end
  2576.                        
  2577.                         local spellattr = nil
  2578.                         for l = 1, #STATS_SYSTEM_CONFIG.STATS do
  2579.                                 if not spellattr then
  2580.                                         if STATS_SYSTEM_CONFIG.STATS[l].name == spellname then
  2581.                                                 spellattr = STATS_SYSTEM_CONFIG.STATS[l]
  2582.                                         end
  2583.                                 end
  2584.                         end
  2585.                        
  2586.                         if not spellattr then
  2587.                                 upgrade = false
  2588.                         end
  2589.                        
  2590.                         if upgrade then
  2591.                                 local attrval = 0
  2592.                                 local attrstr = ""
  2593.                                
  2594.                                 attrval = math.floor(slots[i][2])
  2595.                                 if spelltype == SPELL_TYPE_PERCENT then
  2596.                                         attrstr = "%"
  2597.                                 end
  2598.  
  2599.                                 if attrval == 0 then
  2600.                                         upgrade = false
  2601.                                 end
  2602.  
  2603.                                 local slotcx = self:getStatSlotCount()
  2604.                                 if slotcx == STATS_SYSTEM_CONFIG.maxSlotCount and upgrade then
  2605.                                         upgrade = false
  2606.                                 end
  2607.  
  2608.                                 if upgrade then
  2609.                                         local cur_slots = self:getStatSlots()
  2610.                                         for m = 1, slotcx do
  2611.                                                 if spellname == cur_slots[m][1] then
  2612.                                                         upgrade = false
  2613.                                                 end
  2614.                                         end
  2615.                                 end
  2616.  
  2617.                                 if upgrade then
  2618.                                         if self:addStat(spellname, attrval, attrstr) then
  2619.                                                 fslotc = fslotc + 1
  2620.                                         end
  2621.                                 end
  2622.                         end
  2623.                 end
  2624.         end
  2625.  
  2626.         if fslotc == 0 then
  2627.                 return false
  2628.         end
  2629.        
  2630.         local uid = self:getUniqueId()
  2631.         if fslotc > 1 then
  2632.                 self:setAttribute(ITEM_ATTRIBUTE_NAME, (STATS_SYSTEM_CONFIG.tiers[fslotc] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME))
  2633.         elseif fslotc == 1 then
  2634.                 local it_id = self:getType()
  2635.                 local wp = it_id:getWeaponType()
  2636.                 if wp > 0 then
  2637.                         if wp == WEAPON_SHIELD then
  2638.                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, (arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or ""))
  2639.                         elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE, WEAPON_DISTANCE, WEAPON_WAND}, wp) then -- weapon
  2640.                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, ((wp_string[1] ~= "" and wp_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (wp_string[2] ~= "" and " " .. wp_string[2] or "")))
  2641.                         end
  2642.                 else
  2643.                         if it_id:getArmor() > 0 then -- armor
  2644.                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, ((arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or "")))
  2645.                         else
  2646.                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, ((other_string[1] ~= "" and other_string[1] .. " " or "") .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. (other_string[2] ~= "" and " " .. other_string[2] or "")))
  2647.                         end
  2648.                 end
  2649.         end
  2650.        
  2651.         return true
  2652. end
  2653.  
  2654. function Item:generateLooted(it_lvl, slots)
  2655.         if not self then return false end
  2656.         if not tonumber(it_lvl) then it_lvl = 0 end
  2657.  
  2658.         local it_id = self:getType()   
  2659.         if it_id:isStackable() then return false end
  2660.        
  2661.         self:clearUpgrades()
  2662.         local ntier = false
  2663.         if slots then
  2664.                 ntier = self:generateTier(slots)
  2665.         end
  2666.        
  2667.         if it_id:getTransformEquipId() < 1 then
  2668.                 if it_id:getCharges() < 1 then
  2669.                         local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  2670.                         if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING then  
  2671.                                 if STATS_SYSTEM_CONFIG.weapon_levels[it_lvl] then
  2672.                                         local uid = self:getUniqueId()
  2673.                                         for o = 1, #upgradable_stats do
  2674.                                                 local n_item_stat = upgradable_stats[o][2](it_id)
  2675.                                                 if n_item_stat ~= 0 then
  2676.                                                         self:setAttribute(upgradable_stats[o][1], getItemAttribute(uid, upgradable_stats[o][1], true) + (upgradable_stats[o][3] * it_lvl))
  2677.                                                 end
  2678.                                         end
  2679.                                        
  2680.                                         if not ntier then
  2681.                                                 self:setAttribute(ITEM_ATTRIBUTE_NAME, STATS_SYSTEM_CONFIG.weapon_levels[it_lvl][1] .. " " .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME))
  2682.                                         end
  2683.                                         self:setAttribute(ITEM_ATTRIBUTE_NAME, getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. " " .. (it_lvl > 0 and "+" or "") .. it_lvl)
  2684.                                 end
  2685.                         end
  2686.                 end
  2687.         end    
  2688.         return true
  2689. end
  2690.  
  2691. function Item:generateStats(slots, slotc, wp_lvl, min_sl, max_sl)
  2692.         local t_s = {}
  2693.         local level = 0
  2694.  
  2695.         if slots and slotc then
  2696.         local t = {}
  2697.                 for i = 1, #slots do
  2698.                         t[i] = slots[i]
  2699.                 end
  2700.                
  2701.                 if slotc > 0 then                      
  2702.                         local low5 = #t-5
  2703.                         while #t_s < slotc do
  2704.                                 local sel = math.random(1, #t)
  2705.                                 t_s[#t_s + 1] = t[sel]
  2706.                                 table.remove(t, sel)
  2707.                         end
  2708.                 end
  2709.                
  2710.                 for i = 1, #t_s do
  2711.                         if min_sl then
  2712.                                 if max_sl then
  2713.                                         level = math.random(min_sl, max_sl)
  2714.                                 else
  2715.                                         level = min_sl
  2716.                                 end
  2717.                         end
  2718.                         local tmp = 1
  2719.                         if math.random(1, 2) == 2 then tmp = 2 end
  2720.                         t_s[i] = {t_s[i][1], t_s[i][tmp + 1] * (level /STATS_SYSTEM_CONFIG.maxLevel), tmp}
  2721.                 end
  2722.         end
  2723.        
  2724.         self:generateLooted(wp_lvl, t_s)
  2725.         return true
  2726. end
  2727.  
  2728. function stat_onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified)
  2729. --[[
  2730.  
  2731. -- generateStats example of looting specific item
  2732.         if creature:isMonster() then
  2733.                 if corpse and corpse:isContainer() then
  2734.                         local item = corpse:addItem("sword")
  2735.                         item:generateStats(item:getUpgradeType(), math.random(0, STATS_SYSTEM_CONFIG.maxSlotCount), math.random(0, 4), 1, STATS_SYSTEM_CONFIG.maxLevel)
  2736.                         local item2 = corpse:addItem("plate shield")
  2737.                         item2:generateStats({
  2738.                                 {'lifedrain', 10, 15},
  2739.                                 {'manadrain', 10, 15},
  2740.                                 {'ice', 10, 15},
  2741.                                 {'holy', 10, 15},
  2742.                                 {'death', 10, 15},
  2743.                         }, 3, 6, 24)
  2744.                 end
  2745.         end
  2746.        
  2747. ]]
  2748. return true
  2749. end
  2750.  
  2751. function Item:getStatReqLevel()
  2752.         if STATS_SYSTEM_CONFIG.reqLvlBasedOnUpgrade then
  2753.                 return STATS_SYSTEM_CONFIG.reqLvlFormula(self)
  2754.         else
  2755.                 return self:getType():getRequiredLevel()
  2756.         end
  2757. end
  2758.  
  2759. function stat_onLook(thing, description)
  2760.         if not STATS_SYSTEM_CONFIG.reqLvlBasedOnUpgrade then
  2761.                 return description
  2762.         end
  2763.        
  2764.         local v, d = description:match('%It can only be wielded properly by (.-)% of level (.-)% or higher')
  2765.         if v then
  2766.                 local lv = d:match('%d+')
  2767.                 local nlv = thing:getStatReqLevel()
  2768.                 return description:gsub(description:match(v .. " of level " .. d), v .. " of level " .. nlv)
  2769.         end
  2770.         return description
  2771. end
  2772.  
  2773. --[[ workaround for older tfs
  2774. function ItemType:getRequiredLevel()
  2775.         local i = Item(doCreateItemEx(self:getId()))
  2776.         local d, v = i:getDescription():match('%It can only be wielded properly by (.-)% of level (.-)% or higher')
  2777.         return v:match('%d+') or 0
  2778. end
  2779. -- ]]
  2780.  
  2781. --[[ list of functions:
  2782.         doItemSetAttribute(uid, key, value) -- 0.4 version of item:setAttribute(key, value)
  2783.         doItemEraseAttribute(uid, key) -- 0.4 version of item:removeAttribute(key)
  2784.         getItemAttribute(uid, key, force) -- known function from 0.4, force parameter works for items upgraded before
  2785.        
  2786.         isWeapon(uid) -- is item a weapon
  2787.         isShield(uid) -- is item a shield
  2788.         isBow(uid) -- is item a bow
  2789.        
  2790.         STATS_SYSTEM_CONFIG.skillFormula(level) -- shows exp for enchanting level
  2791.         STATS_SYSTEM_CONFIG.levelUpgradeFormula(level, maxlevel) -- chance to upgrade item level on certain level
  2792.        
  2793.         assign_loot_Stat(container) -- applies random stats on items inside this container
  2794.         find_loot_Container(pos, extraPercent, monsterName, extraStackable, killer) -- applies random stats event functions on monster corpse
  2795.         getEnchantingSkill(tries) -- returns enchanting skill based on amount of tries
  2796.         improveChance(container, monsterName, extraPercent, killer) -- increases a chance to loot rare item from monster
  2797.         improveStackables(container, value) -- stackables in container will be increased by random amount between 0 and value
  2798.        
  2799.         creature:isSummon() -- is creature a summon
  2800.        
  2801.         item:getBaseDuration() -- returns current duration or duration of brand-new item
  2802.         item:getBaseStatsInfo() -- reads non-modified item stats
  2803.         item:getStatSlotCount() -- returns amount of slots assigned to an item
  2804.         item:getStatSlots() -- returns slots from item this way:
  2805.         {
  2806.                 [1] = {'fire', '+25%'},
  2807.                 [2] = {'atk', '-2'},
  2808.         }
  2809.         item:getUpgradeType() -- returns spells available for item(STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.type)
  2810.         item:getStatReqLevel() -- works as itemType:getRequiredLevel(), but for itemid and considers changes made by stat system
  2811.        
  2812.         item:addLevel(levelchange) -- adds levels to item, works with negative values also
  2813.         item:getLevel() -- get item level(+x or -x)
  2814.         item:setLevel(level) -- set item level
  2815.         item:addSlot(name, value, percent) -- adds slot and applying item attributes where name = spellname, value = spell value, percent = if true it will add % to number value
  2816.         item:removeSlot(slotid) -- removes certain slot from item
  2817.         item:clearUpgrades() -- removes all upgrades from item
  2818.         item:generateTier(slots) -- generates item like it was looted from a monster, example slots:
  2819.         {
  2820.                 {'fire', '5', STATSLOT_TYPE_PERCENT},
  2821.                 {'ice', '20', STATSLOT_TYPE_NORMAL}
  2822.         }
  2823.         item:generateLooted(it_lvl, slots) -- calls function above, plus allows you to set a level on item
  2824.         item:generateStats(slots, slotc, wp_lvl, min_sl, max_sl) -- more random version of function above, go to stat_onDeath for example of use
  2825.                
  2826. -- functions used by the lib(not intended to be used by other scripts)
  2827. item:addStat(item, spellname, spellvalue, suffix, cid) -- upgrades attributes, doesn't add stat
  2828. item:addStatSlot(spell, value, suffix) -- adds slot one to description, doesn't upgrade attributes
  2829. check_slot(weapon, slot) -- returns value for skill conditions system
  2830. loadSet(cid) -- used by skill conditions system
  2831. chk(cid,slots) -- used by skill conditions system
  2832. stat_regen(cid, itemid, slot, checkid, sid) -- does regeneration, auto-used
  2833. stat_load(cid) -- executed to load player's stats and run other functions
  2834.  
  2835. SPELL_TYPE_VALUE
  2836. SPELL_TYPE_PERCENT
  2837.  
  2838. -- default events (advanced scripters may find calling it in unusual cases useful)
  2839. stat_onUse(player, item, fromPosition, itemEx, toPosition, attempt)
  2840. stat_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  2841. stat_onManaChange(creature, attacker, manaChange, origin)
  2842. stat_onLogin(player)
  2843. stat_onPrepareDeath(creature, lastHitKiller, mostDamageKiller)
  2844. stat_onTargetCombat(self, target)
  2845. stat_onKill(player, target, lastHit)
  2846. stat_onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified)
  2847. stat_onLook(thing, description)
  2848. ]]
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top