Guest User

stats.lua

a guest
Mar 6th, 2015
438
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 67.48 KB | None | 0 0
  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 Beta, 7 Mar 2015
  13. ---------------------------------------------------------------------
  14.  
  15. ]]
  16.  
  17. STATS_SYSTEM_CONFIG = {
  18.     -- BASIC CONFIG STARTS HERE
  19.     maxSlotCount = 4,
  20.     slotChances = {
  21.         [1] = 500,
  22.         [2] = 5000,
  23.         [3] = 15000,
  24.         [4] = 25000
  25.     },
  26.     tiers = { -- item name based on slots looted (if more than 1)
  27.         [2] = 'rare',
  28.         [3] = 'epic',
  29.         [4] = 'legendary'
  30.     },
  31.     weapon_levels = {
  32.         -- weapon name if no slots were assigned, chance(1000 = 1%)
  33.         [-9] = {'useless', 300},
  34.         [-8] = {'broken', 500},
  35.         [-7] = {'trash', 1000},
  36.         [-6] = {'ruined', 1500},
  37.         [-5] = {'damaged', 2000},
  38.         [-4] = {'worthless', 2500},
  39.         [-3] = {'blunt', 4000},
  40.         [-2] = {'cheap', 7000},
  41.         [-1] = {'common', 9000},
  42.         [1] = {'uncommon', 25000},
  43.         [2] = {'strengthened', 20000},
  44.         [3] = {'fine', 15000},
  45.         [4] = {'superior', 10000},
  46.         [5] = {'rare', 7500},
  47.         [6] = {'unique', 3500},
  48.         [7] = {'flawless', 2500},
  49.         [8] = {'epic', 1000},
  50.         [9] = {'legendary', 500}
  51.     },
  52.     ignoredIds = {}, -- items with these ids will be banned from upgrading
  53.     upgradeMagicItems = true, -- items with xml-sided bonuses, examples: magma coat, fire axe, boots of haste
  54.     upgradeItemsWithNoArmor = true, -- allow upgrading clothes without arm value
  55.     lootUpgradedItems = true,
  56.     rare_popup = true,
  57.     rare_text = "*rare*",
  58.     rare_effect = true,
  59.     rare_effect_id = CONST_ME_MAGIC_GREEN,
  60.     rare_loot_level = true, -- set to false if you want to disable levels on looted weapons
  61.     rare_negative_level = true, -- not in use yet, set to false if you want to disable it
  62.     rare_min_level =  -9,
  63.    
  64.     useSkill = true, -- enchanting power based on player's skill, set to false if you want it random
  65.     skillTriesStorage = 3866,
  66.    
  67.     simple = { -- upgrade by jewels
  68.         enabled = true,
  69.         usePerks = false, -- unused
  70.         randomSpells = true, -- todo: modal with selecting attr if false
  71.         downgradeOnFail = true, -- item level only
  72.     },
  73.    
  74.     -- BASIC CONFIG ENDS HERE
  75.     -- do not touch things below unless you are a advanced scripter
  76.     skillFormula = function(lv) return math.ceil(((1 * lv^3) - (2 * lv^2) + (4 * lv)) / (90 + lv) + lv) end,
  77.     maxLevel = 30,
  78.    
  79.     levelUpgradeFormula = function(lv, minl)
  80.         if STATS_SYSTEM_CONFIG.rare_negative_level then
  81.             return math.ceil((lv/minl) * 25) + math.min(math.ceil(lv/minl * 5) +70, 75)
  82.         else
  83.             return 65 - math.ceil((lv/minl) * 3)
  84.         end
  85.     end,
  86.    
  87.     -- spells and values for certain types of item
  88.     UPGRADE_STATS_VALUES_PER_LVL = {
  89.         -- value per level
  90.             atk = 2,
  91.             def = 2,
  92.             extradef = 1,
  93.             arm = 2,
  94.             hitchance = 3,
  95.             shootrange = 1
  96.     },
  97.    
  98.     UPGRADE_SPELLS = {
  99.         necklace = {
  100.             {'hp', 100, 10}, -- normal, percent
  101.             {'mp', 200, 10},
  102.             {'ml', 3, 10},
  103.             {'melee', 3, 10},
  104.             {'shield', 3, 10},
  105.             {'dist', 3, 10},
  106.             {'physical', 10, 5},
  107.             {'energy', 10, 10},
  108.             {'earth', 10, 10},
  109.             {'fire', 10, 10},
  110.             -- {'undefined', 10, 10},
  111.             {'lifedrain', 10, 10},
  112.             {'manadrain', 10, 10},
  113.             {'healing', -10, -10},
  114.             {'water', 20, 100},
  115.             {'ice', 10, 10},
  116.             {'holy', 10, 10},
  117.             {'death', 10, 10},
  118.             {'regHP', 5, 1}, -- normalhp, normalmp, percenthp, percentmp
  119.             {'regMP', 10, 2}, -- normalhp, normalmp, percenthp, percentmp
  120.             {'PVE death', 1, 100}
  121.         },
  122.         helmet = {
  123.             {'ml', 3, 10},
  124.             {'melee', 3, 10},
  125.             {'dist', 3, 10},
  126.             {'physical', 10, 3},
  127.             {'energy', 10, 10},
  128.             {'earth', 10, 10},
  129.             {'fire', 10, 10},
  130.             -- {'undefined', 10, 10},
  131.             {'lifedrain', 10, 10},
  132.             {'manadrain', 10, 10},
  133.             {'healing', -10, -10},
  134.             {'water', 20, 100},
  135.             {'ice', 10, 10},
  136.             {'holy', 10, 10},
  137.             {'death', 10, 10},
  138.             {'arm', 12, 70},
  139.         },
  140.         weapon = {
  141.             {'melee', 5, 15},
  142.             {'physical', 50, 10},
  143.             {'energy', 50, 10},
  144.             {'earth', 50, 10},
  145.             {'fire', 50, 10},
  146.             -- {'undefined', 50, 10},
  147.             {'ice', 50, 10},
  148.             {'holy', 50, 10},
  149.             {'death', 50, 10},
  150.             {'drainHP', 50, 3},
  151.             {'drainMP', 50, 3},
  152.             {'water', 50, 10},
  153.             {'animals', 50, 10},
  154.             {'humans', 50, 3},
  155.             {'undeads', 50, 10},
  156.             {'insects', 50, 10},
  157.             {'atk', 12, 70},
  158.             {'def', 12, 70},
  159.             {'extra def', 12, 70},
  160.         },
  161.         distance = {
  162.             {'dist', 5, 15},
  163.             {'physical', 50, 10},
  164.             {'energy', 50, 10},
  165.             {'earth', 50, 10},
  166.             {'fire', 50, 10},
  167.             -- {'undefined', 50, 10},
  168.             {'ice', 50, 10},
  169.             {'holy', 50, 10},
  170.             {'death', 50, 10},
  171.             {'drainHP', 50, 3},
  172.             {'drainMP', 50, 3},
  173.             {'water', 50, 10},
  174.             {'animals', 50, 10},
  175.             {'humans', 50, 3},
  176.             {'undeads', 50, 10},
  177.             {'insects', 50, 10},
  178.             {'atk', 12, 70},
  179.             {'accuracy', 12, 70},
  180.             {'range', 3, 50},
  181.         },
  182.         wand = {
  183.             {'ml', 5, 15},
  184.             {'physical', 50, 10},
  185.             {'energy', 50, 10},
  186.             {'earth', 50, 10},
  187.             {'fire', 50, 10},
  188.             -- {'undefined', 50, 10},
  189.             {'healing', 50, 10},
  190.             {'ice', 50, 10},
  191.             {'holy', 50, 10},
  192.             {'death', 50, 10},
  193.             {'drainHP', 50, 3},
  194.             {'drainMP', 50, 3},
  195.             {'water', 50, 10},
  196.             {'animals', 50, 10},
  197.             {'humans', 50, 3},
  198.             {'undeads', 50, 10},
  199.             {'insects', 50, 10},
  200.             {'range', 3, 50},
  201.         },
  202.         armor = {
  203.             {'hp', 300, 15},
  204.             {'mp', 500, 20},
  205.             {'ml', 5, 15},
  206.             {'melee', 5, 15},
  207.             {'shield', 5, 15},
  208.             {'dist', 5, 15},
  209.             {'physical', 50, 5},
  210.             {'energy', 10, 15},
  211.             {'earth', 10, 15},
  212.             {'fire', 10, 15},
  213.             -- {'undefined', 10, 15},
  214.             {'lifedrain', 10, 15},
  215.             {'manadrain', 10, 15},
  216.             {'healing', -10, -15},
  217.             {'water', 20, 100},
  218.             {'ice', 10, 15},
  219.             {'holy', 10, 15},
  220.             {'death', 10, 15},
  221.             {'regHP', 5, 1},
  222.             {'regMP', 10, 2},
  223.             {'arm', 12, 70},
  224.         },
  225.         shield = {
  226.             {'ml', 3, 10},
  227.             {'shield', 5, 15},
  228.             {'physical', 30, 5},
  229.             {'energy', 10, 15},
  230.             {'earth', 10, 15},
  231.             {'fire', 10, 15},
  232.             -- {'undefined', 10, 15},
  233.             {'lifedrain', 10, 15},
  234.             {'manadrain', 10, 15},
  235.             {'ice', 10, 15},
  236.             {'holy', 10, 15},
  237.             {'death', 10, 15},
  238.             {'regHP', 5, 1},
  239.             {'regMP', 10, 2},
  240.             {'def', 12, 70},
  241.         },
  242.         ring = {
  243.             {'hp', 100, 10},
  244.             {'mp', 200, 10},
  245.             {'ml', 3, 10},
  246.             {'melee', 3, 10},
  247.             {'shield', 3, 10},
  248.             {'dist', 3, 10},
  249.             {'physical', 10, 5},
  250.             {'energy', 10, 10},
  251.             {'earth', 10, 10},
  252.             {'fire', 10, 10},
  253.             -- {'undefined', 10, 10},
  254.             {'lifedrain', 10, 10},
  255.             {'manadrain', 10, 10},
  256.             {'healing', -10, -10},
  257.             {'water', 20, 100},
  258.             {'ice', 10, 10},
  259.             {'holy', 10, 10},
  260.             {'death', 10, 10},
  261.             {'regHP', 5, 1},
  262.             {'regMP', 10, 2},
  263.             {'exp', 50, 50},
  264.             {'loot', 1, 30},
  265.         },
  266.         legs = {
  267.             {'ml', 3, 10},
  268.             {'melee', 3, 10},
  269.             {'shield', 3, 10},
  270.             {'dist', 3, 10},
  271.             {'physical', 10, 4},
  272.             {'energy', 10, 10},
  273.             {'earth', 10, 10},
  274.             {'fire', 10, 10},
  275.             -- {'undefined', 10, 10},
  276.             {'lifedrain', 10, 10},
  277.             {'manadrain', 10, 10},
  278.             {'healing', -10, -10},
  279.             {'ice', 10, 10},
  280.             {'holy', 10, 10},
  281.             {'death', 10, 10},
  282.             {'arm', 12, 70},
  283.         },
  284.         boots = {
  285.             {'physical', 10, 3},
  286.             {'energy', 10, 10},
  287.             {'earth', 10, 10},
  288.             {'fire', 10, 10},
  289.             -- {'undefined', 10, 10},
  290.             {'lifedrain', 10, 10},
  291.             {'manadrain', 10, 10},
  292.             {'healing', -10, -10},
  293.             {'ice', 10, 10},
  294.             {'holy', 10, 10},
  295.             {'death', 10, 10},
  296.             {'regHP', 5, 1},
  297.             {'regMP', 10, 2},
  298.             {'arm', 12, 70},
  299.         },
  300.         charges = {
  301.             {'charges', 500, 45},
  302.         },
  303.         decay = {
  304.             {'time', 1200000, 50},
  305.         },
  306.     },
  307.    
  308.     STATS = {
  309.         {
  310.             name = 'hp',
  311.            
  312.             weaponLootName = {'',''},
  313.             armorLootName = {'','of improved health'},
  314.             otherLootName = {'','of improved health'},
  315.            
  316.             spellName = 'Health',
  317.             enabledValues = true,
  318.             enabledPercent = true
  319.             },
  320.        
  321.         {
  322.             name = 'mp',
  323.  
  324.             spellName = 'Mana',
  325.             enabledValues = true,
  326.            
  327.             weaponLootName = {'',''},
  328.             armorLootName = {'','of improved mana'},
  329.             otherLootName = {'','of improved mana'},
  330.             enabledPercent = true
  331.         },
  332.        
  333.         {
  334.             name = 'ml',
  335.  
  336.             weaponLootName = {'magic',''},
  337.             armorLootName = {'enchanted',''},
  338.             otherLootName = {'magic',''},
  339.  
  340.             spellName = 'Magic Level',
  341.             enabledValues = true,  
  342.             enabledPercent = true  
  343.         },
  344.        
  345.         {
  346.             name = 'melee',
  347.  
  348.             weaponLootName = {'','of power'},
  349.             armorLootName = {'warrior',''},
  350.             otherLootName = {'','of power'},
  351.  
  352.             spellName = 'Melee Skill',
  353.             enabledValues = true,
  354.             enabledPercent = true      
  355.         },
  356.        
  357.         {
  358.             name = 'shield',
  359.  
  360.             weaponLootName = {'','of defense'},
  361.             armorLootName = {'fortified',''},
  362.             otherLootName = {'','of defense'},
  363.            
  364.             spellName = 'Shielding',
  365.             enabledValues = true,
  366.             enabledPercent = true          
  367.         },
  368.        
  369.         {
  370.             name = 'dist',
  371.  
  372.             weaponLootName = {'','of hunting'},
  373.             armorLootName = {'hunter',''},
  374.             otherLootName = {'','of hunting'},
  375.                        
  376.             spellName = 'Distance Skill',
  377.             enabledValues = true,
  378.             enabledPercent = true
  379.         },
  380.  
  381.         -- element types
  382.         -- on weapon: value = more or less element damage
  383.         -- on armor: value = when something hits you, hit value may increase or decrease depending on value
  384.         {
  385.             name = 'physical',
  386.             combatType = COMBAT_PHYSICALDAMAGE,
  387.  
  388.             weaponLootName = {'','of bleeding'},
  389.             armorLootName = {'strong',''},
  390.             otherLootName = {'stone',''},
  391.            
  392.             spellName = 'Physical',
  393.             enabledValues = true,
  394.             enabledPercent = true
  395.         },
  396.        
  397.        
  398.         {
  399.             name = 'energy',
  400.             combatType = COMBAT_ENERGYDAMAGE,
  401.            
  402.             weaponLootName = {'','of thunders'},
  403.             armorLootName = {'','of sparks'},
  404.             otherLootName = {'','of lightning'},
  405.            
  406.             oppositeSpell = 'earth', -- unused values
  407.             spellName = 'Energy',
  408.             enabledValues = true,
  409.             enabledPercent = true      
  410.         },
  411.        
  412.         {
  413.             name = 'earth',
  414.             combatType = COMBAT_EARTHDAMAGE,
  415.  
  416.             weaponLootName = {'poison',''},
  417.             armorLootName = {'earthproof',''},
  418.             otherLootName = {'','of antidote'},
  419.            
  420.             oppositeSpell = 'energy',
  421.             spellName = 'Earth',
  422.             enabledValues = true,
  423.             enabledPercent = true
  424.         },
  425.        
  426.         {
  427.             name = 'fire',
  428.             combatType = COMBAT_FIREDAMAGE,
  429.  
  430.             weaponLootName = {'burning',''},
  431.             armorLootName = {'fireproof',''},
  432.             otherLootName = {'','of fire protection'},
  433.            
  434.             oppositeSpell = 'ice',
  435.             spellName = 'Fire',
  436.             enabledValues = true,
  437.             enabledPercent = true
  438.         },
  439.        
  440.         {
  441.             -- exist in tfs, not in use by default
  442.             name = 'undefined',
  443.             combatType = COMBAT_UNDEFINEDDAMAGE,
  444.  
  445.             weaponLootName = {'ghost',''},
  446.             armorLootName = {'',''},
  447.             otherLootName = {'',''},
  448.            
  449.             spellName = 'None',
  450.             enabledValues = false,
  451.             enabledPercent = false
  452.         },
  453.        
  454.         {
  455.             name = 'lifedrain',
  456.             combatType = COMBAT_LIFEDRAIN,
  457.            
  458.             weaponLootName = {'cursed',''},
  459.             armorLootName = {'enchanted',''},
  460.             otherLootName = {'blessed',''},
  461.            
  462.             oppositeSpell = 'healing',
  463.             spellName = 'Lifedrain',
  464.             enabledValues = true,
  465.             enabledPercent = true
  466.         },
  467.        
  468.         {
  469.             name = 'manadrain',
  470.             combatType = COMBAT_MANADRAIN,
  471.            
  472.             weaponLootName = {'','of dark magic'},
  473.             armorLootName = {'sealed',''},
  474.             otherLootName = {'','of mana protection'},
  475.            
  476.             spellName = 'Manadrain',
  477.             enabledValues = true,
  478.             enabledPercent = true
  479.         },
  480.        
  481.         {
  482.             -- should not be used by weapons
  483.             name = 'healing',
  484.             combatType = COMBAT_HEALING,
  485.            
  486.             weaponLootName = {'healer',''},
  487.             armorLootName = {'','of healing'},
  488.             otherLootName = {'','of healing'},
  489.            
  490.             oppositeSpell = 'lifedrain',
  491.             spellName = 'Healing',
  492.             enabledValues = true,
  493.             enabledPercent = true
  494.         },
  495.        
  496.         {
  497.             name = 'water',
  498.             combatType = COMBAT_DROWNDAMAGE,
  499.            
  500.             weaponLootName = {'','of fear'},
  501.             armorLootName = {'','of the deep'},
  502.             otherLootName = {'','of the deep'},
  503.            
  504.             spellName = 'Water',
  505.             enabledValues = true,
  506.             enabledPercent = true
  507.         },
  508.        
  509.         {
  510.             name = 'ice',
  511.             combatType = COMBAT_ICEDAMAGE,
  512.            
  513.             weaponLootName = {'icy',''},
  514.             armorLootName = {'frozen',''},
  515.             otherLootName = {'','of cold'},
  516.            
  517.             oppositeSpell = 'fire',
  518.             spellName = 'Ice',
  519.             enabledValues = true,
  520.             enabledPercent = true
  521.         },
  522.        
  523.         {
  524.             name = 'holy',
  525.             combatType = COMBAT_HOLYDAMAGE,
  526.            
  527.             weaponLootName = {'divine',''},
  528.             armorLootName = {'','of darkness'},
  529.             otherLootName = {'dark',''},
  530.            
  531.             oppositeSpell = 'death',
  532.             spellName = 'Holy',
  533.             enabledValues = true,
  534.             enabledPercent = true
  535.         },
  536.        
  537.         {
  538.             name = 'death',
  539.             combatType = COMBAT_DEATHDAMAGE,
  540.  
  541.             weaponLootName = {'','of darkness'},
  542.             armorLootName = {'','of inquisition'},
  543.             otherLootName = {'holy',''},
  544.            
  545.             oppositeSpell = 'holy',
  546.             spellName = 'Death',
  547.             enabledValues = true,
  548.             enabledPercent = true
  549.         },
  550.        
  551.         -- weapon only
  552.         {
  553.             name = 'drainHP',
  554.             drain = COMBAT_LIFEDRAIN,
  555.  
  556.             weaponLootName = {'vampire',''},
  557.             armorLootName = {'',''},
  558.             otherLootName = {'',''},
  559.            
  560.             spellName = 'Drain Health',
  561.             enabledValues = true,
  562.             enabledPercent = true
  563.         },
  564.        
  565.         {
  566.             name = 'drainMP',
  567.             drain = COMBAT_MANADRAIN,
  568.  
  569.             weaponLootName = {'','of weakness'},
  570.             armorLootName = {'',''},
  571.             otherLootName = {'',''},
  572.            
  573.             spellName = 'Drain Mana',
  574.             enabledValues = true,
  575.             enabledPercent = true
  576.         },
  577.        
  578.         {
  579.             name = 'animals',
  580.             weaponLootName = {'hunting',''},
  581.             armorLootName = {'',''},
  582.             otherLootName = {'',''},
  583.             spellName = 'Animals',
  584.             enabledValues = true,
  585.             enabledPercent = true
  586.         },
  587.        
  588.         {
  589.             name = 'humans',
  590.  
  591.             weaponLootName = {'',''},
  592.             armorLootName = {'',''},
  593.             otherLootName = {'',''},
  594.            
  595.             spellName = 'Humans',
  596.             enabledValues = true,
  597.             enabledPercent = true
  598.         },
  599.        
  600.         {
  601.             name = 'undeads',
  602.  
  603.             weaponLootName = {'','of inquisition'},
  604.             armorLootName = {'',''},
  605.             otherLootName = {'',''},
  606.            
  607.             spellName = 'Undeads',
  608.             enabledValues = true,
  609.             enabledPercent = true
  610.         },
  611.        
  612.         {
  613.             name = 'insects',
  614.            
  615.             weaponLootName = {'','of insect hunting'},
  616.             armorLootName = {'',''},
  617.             otherLootName = {'',''},
  618.            
  619.             spellName = 'Insects',
  620.             enabledValues = true,
  621.             enabledPercent = true
  622.         },
  623.  
  624.         -- buff
  625.         {
  626.             name = 'regHP',
  627.            
  628.             weaponLootName = {'',''},
  629.             armorLootName = {'','of vitality'},
  630.             otherLootName = {'','of vitality'},
  631.            
  632.             spellName = 'HP Regeneration',
  633.             enabledValues = true,
  634.             enabledPercent = true
  635.         },
  636.  
  637.         {
  638.             name = 'regMP',
  639.            
  640.             weaponLootName = {'',''},
  641.             armorLootName = {'','of magic'},
  642.             otherLootName = {'','of magic'},
  643.            
  644.             spellName = 'MP Regeneration',
  645.             enabledValues = true,
  646.             enabledPercent = true
  647.         },
  648.        
  649.         -- attr based stats
  650.         {
  651.             name = 'charges',
  652.            
  653.             weaponLootName = {'',''},
  654.             armorLootName = {'',''},
  655.             otherLootName = {'charged',''},
  656.            
  657.             spellName = 'Charges',
  658.             enabledValues = true,
  659.             enabledPercent = true
  660.         },
  661.        
  662.         {
  663.             name = 'time',
  664.            
  665.             weaponLootName = {'',''},
  666.             armorLootName = {'',''},
  667.             otherLootName = {'fine',''},
  668.            
  669.             spellName = 'Duration',
  670.             enabledValues = true,
  671.             enabledPercent = true
  672.         },
  673.        
  674.         {
  675.             name = 'atk',
  676.            
  677.             weaponLootName = {'sharpened',''},
  678.             armorLootName = {'',''},
  679.             otherLootName = {'',''},
  680.            
  681.             spellName = 'Attack',
  682.             enabledValues = true,
  683.             enabledPercent = true
  684.         },
  685.        
  686.         {
  687.             name = 'def',
  688.            
  689.             weaponLootName = {'strong',''},
  690.             armorLootName = {'fortified',''},
  691.             otherLootName = {'',''},
  692.            
  693.             spellName = 'Defense',
  694.             enabledValues = true,
  695.             enabledPercent = true
  696.         },
  697.        
  698.         {
  699.             name = 'extra def',
  700.            
  701.             weaponLootName = {'','of balance'},
  702.             armorLootName = {'',''},
  703.             otherLootName = {'',''},
  704.            
  705.             spellName = 'Extra Defense',
  706.             enabledValues = true,
  707.             enabledPercent = true
  708.         },
  709.        
  710.         {
  711.             name = 'arm',
  712.            
  713.             weaponLootName = {'',''},
  714.             armorLootName = {'masterpiece of',''},
  715.             otherLootName = {'',''},
  716.            
  717.             spellName = 'Armor',
  718.             enabledValues = true,
  719.             enabledPercent = true
  720.         },
  721.        
  722.         {
  723.             name = 'accuracy',
  724.            
  725.             weaponLootName = {'accurate',''},
  726.             armorLootName = {'',''},
  727.             otherLootName = {'',''},
  728.            
  729.             spellName = 'Hit Chance',
  730.             enabledValues = true, -- hit% + x%
  731.             enabledPercent = true -- hit% + hit%*x%
  732.         },
  733.        
  734.         {
  735.             name = 'range',
  736.            
  737.             weaponLootName = {'sniper',''},
  738.             armorLootName = {'',''},
  739.             otherLootName = {'',''},
  740.            
  741.             spellName = 'Range',
  742.             enabledValues = true,
  743.             enabledPercent = true
  744.         },
  745.        
  746.         {
  747.             name = 'PVE death',
  748.            
  749.             weaponLootName = {'',''},
  750.             armorLootName = {'',''},
  751.             otherLootName = {'','of good fate'},
  752.            
  753.             spellName = 'PVE Death',
  754.             enabledValues = true,
  755.             enabledPercent = true
  756.         },
  757.         -- xp, loot
  758.         {
  759.             name = 'exp',
  760.            
  761.             weaponLootName = {'',''},
  762.             armorLootName = {'',''},
  763.             otherLootName = {'','of experience'},
  764.            
  765.             spellName = 'Extra Exp',
  766.             enabledValues = true,
  767.             enabledPercent = true
  768.         },
  769.        
  770.         {
  771.             name = 'loot',
  772.            
  773.             weaponLootName = {'',''},
  774.             armorLootName = {'',''},
  775.             otherLootName = {'','of luck'},
  776.            
  777.             spellName = 'Luck',
  778.             enabledValues = true,
  779.             enabledPercent = true
  780.         },
  781.     },
  782. }
  783.  
  784. function getItemAttribute(uid, key)
  785.     local i = ItemType(Item(uid):getId())
  786.     local string_attributes = {
  787.         [ITEM_ATTRIBUTE_NAME] = i:getName(),
  788.         [ITEM_ATTRIBUTE_ARTICLE] = i:getArticle(),
  789.         [ITEM_ATTRIBUTE_PLURALNAME] = i:getPluralName(),
  790.         ["name"] = i:getName(),
  791.         ["article"] = i:getArticle(),
  792.         ["pluralname"] = i:getPluralName()
  793.     }
  794.  
  795.     local numeric_attributes = {
  796.         [ITEM_ATTRIBUTE_WEIGHT] = i:getWeight(),
  797.         [ITEM_ATTRIBUTE_ATTACK] = i:getAttack(),
  798.         [ITEM_ATTRIBUTE_DEFENSE] = i:getDefense(),
  799.         [ITEM_ATTRIBUTE_EXTRADEFENSE] = i:getExtraDefense(),
  800.         [ITEM_ATTRIBUTE_ARMOR] = i:getArmor(),
  801.         [ITEM_ATTRIBUTE_HITCHANCE] = i:getHitChance(),
  802.         [ITEM_ATTRIBUTE_SHOOTRANGE] = i:getShootRange(),
  803.         ["weight"] = i:getWeight(),
  804.         ["attack"] = i:getAttack(),
  805.         ["defense"] = i:getDefense(),
  806.         ["extradefense"] = i:getExtraDefense(),
  807.         ["armor"] = i:getArmor(),
  808.         ["hitchance"] = i:getHitChance(),
  809.         ["shootrange"] = i:getShootRange()
  810.     }
  811.  
  812.     local attr = Item(uid):getAttribute(key)
  813.     if tonumber(attr) then
  814.         if numeric_attributes[key] then
  815.             return attr ~= 0 and attr or numeric_attributes[key]
  816.         end
  817.     else
  818.         if string_attributes[key] then
  819.             if attr == "" then
  820.                 return string_attributes[key]
  821.             end
  822.         end
  823.     end
  824.     return attr
  825. end
  826.  
  827. function doItemSetAttribute(uid, key, value)
  828.     return Item(uid):setAttribute(key, value)
  829. end
  830.  
  831. function doItemEraseAttribute(uid, key)
  832.     return Item(uid):removeAttribute(key)
  833. end
  834.  
  835. local element_stats = {}
  836. local drain_stats = {}
  837.  
  838. for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  839.     local stat = STATS_SYSTEM_CONFIG.STATS[i]
  840.     if stat.drain then
  841.         drain_stats[stat.name] = stat.drain
  842.     end
  843.    
  844.     if stat.combatType then
  845.         element_stats[stat.name] = stat.combatType
  846.     end
  847. end
  848.  
  849. local stat_conditions = {
  850. [1] = {['hp'] = {}, ['mp'] = {}, ['ml'] = {}, ['melee'] = {}, ['shield'] = {}, ['dist'] = {}}, -- normal
  851. [2] = {['hp'] = {}, ['mp'] = {}, ['ml'] = {}, ['melee'] = {}, ['shield'] = {}, ['dist'] = {}} -- percent
  852. }
  853.  
  854. for i = -95, 300 do
  855. -- % stats and skills
  856.     stat_conditions[2]['hp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  857.     setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_SUBID, 50)
  858.     setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  859.     setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_TICKS, -1)
  860.     setConditionParam(stat_conditions[2]['hp'][i], CONDITION_PARAM_STAT_MAXHITPOINTSPERCENT, 100+i)
  861.  
  862.     stat_conditions[2]['mp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  863.     setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_SUBID, 51)
  864.     setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  865.     setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_TICKS, -1)
  866.     setConditionParam(stat_conditions[2]['mp'][i], CONDITION_PARAM_STAT_MAXMANAPOINTSPERCENT, 100+i)
  867.  
  868.     stat_conditions[2]['ml'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  869.     setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_SUBID, 52)
  870.     setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  871.     setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_TICKS, -1)
  872.     setConditionParam(stat_conditions[2]['ml'][i], CONDITION_PARAM_STAT_MAGICPOINTSPERCENT, 100+i)
  873.  
  874.     stat_conditions[2]['melee'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  875.     setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_SUBID, 53)
  876.     setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  877.     setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_TICKS, -1)
  878.     setConditionParam(stat_conditions[2]['melee'][i], CONDITION_PARAM_SKILL_MELEEPERCENT, 100+i)
  879.  
  880.     stat_conditions[2]['shield'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  881.     setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_SUBID, 54)
  882.     setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  883.     setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_TICKS, -1)
  884.     setConditionParam(stat_conditions[2]['shield'][i], CONDITION_PARAM_SKILL_SHIELDPERCENT, 100+i)
  885.  
  886.     stat_conditions[2]['dist'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  887.     setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_SUBID, 55)
  888.     setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  889.     setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_TICKS, -1)
  890.     setConditionParam(stat_conditions[2]['dist'][i], CONDITION_PARAM_SKILL_DISTANCEPERCENT, 100+i)
  891. end
  892.  
  893. for i = -1500, 1500 do
  894.     -- hp mp normal
  895.     stat_conditions[1]['hp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  896.     setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_SUBID, 56)
  897.     setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  898.     setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_TICKS, -1)
  899.     setConditionParam(stat_conditions[1]['hp'][i], CONDITION_PARAM_STAT_MAXHITPOINTS, i)
  900.  
  901.     stat_conditions[1]['mp'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  902.     setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_SUBID, 57)
  903.     setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  904.     setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_TICKS, -1)
  905.     setConditionParam(stat_conditions[1]['mp'][i], CONDITION_PARAM_STAT_MAXMANAPOINTS, i)
  906. end
  907.  
  908. for i = -100, 100 do
  909.     -- skills
  910.     stat_conditions[1]['ml'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  911.     setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_SUBID, 58)
  912.     setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  913.     setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_TICKS, -1)
  914.     setConditionParam(stat_conditions[1]['ml'][i], CONDITION_PARAM_STAT_MAGICPOINTS, i)
  915.  
  916.     stat_conditions[1]['melee'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  917.     setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_SUBID, 59)
  918.     setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  919.     setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_TICKS, -1)
  920.     setConditionParam(stat_conditions[1]['melee'][i], CONDITION_PARAM_SKILL_MELEE, i)
  921.  
  922.     stat_conditions[1]['shield'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  923.     setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_SUBID, 60)
  924.     setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  925.     setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_TICKS, -1)
  926.     setConditionParam(stat_conditions[1]['shield'][i], CONDITION_PARAM_SKILL_SHIELD, i)
  927.  
  928.     stat_conditions[1]['dist'][i] = createConditionObject(CONDITION_ATTRIBUTES)
  929.     setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_SUBID, 61)
  930.     setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_BUFF_SPELL, 1)
  931.     setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_TICKS, -1)
  932.     setConditionParam(stat_conditions[1]['dist'][i], CONDITION_PARAM_SKILL_DISTANCE, i)
  933. end
  934.  
  935. local magic_words = { -- see upgradeMagicItems in config
  936.     'physical',
  937.     'fire',
  938.     'ice',
  939.     'earth',
  940.     'energy',
  941.     'poison',
  942.     'drown',
  943.     'holy',
  944.     'death',
  945.     'lifedrain',
  946.     'manadrain',
  947.     'protection',
  948.     'magic',
  949.     'fighting',
  950.     'shielding',
  951.     'speed',
  952.     'invisibility',
  953.     'drinking',
  954.     'regeneration',
  955. }
  956.    
  957. local upgrade_types = {
  958.     none = false,
  959.     necklace = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.necklace,
  960.     helmet = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.helmet,
  961.     weapon = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.weapon,
  962.     distance = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.distance,
  963.     wand = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.wand,
  964.     armor = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.armor,
  965.     shield = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.shield,
  966.     ring = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.ring,
  967.     legs = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.legs,
  968.     boots = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.boots,
  969.     charges = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.charges,
  970.     decay = STATS_SYSTEM_CONFIG.UPGRADE_SPELLS.decay,
  971. }
  972.  
  973. function Item.getUpgradeType(self)
  974.     local it_id = ItemType(self:getId())
  975.     if it_id:isStackable() or it_id:isContainer() then
  976.         return upgrade_types.none
  977.     end
  978.  
  979.     local wp = it_id:getWeaponType()
  980.     if self:getAttribute(ITEM_ATTRIBUTE_CHARGES) > 0 then
  981.         if wp > 0 then
  982.             return upgrade_types.none
  983.         end
  984.         return upgrade_types.charges
  985.     end
  986.  
  987.     if self:getAttribute(ITEM_ATTRIBUTE_DURATION) > 0 then
  988.         if wp > 0 then
  989.             return upgrade_types.none
  990.         end
  991.         return upgrade_types.decay
  992.     end
  993.    
  994.     if wp > 0 then
  995.         if wp == WEAPON_SHIELD then
  996.             return upgrade_types.shield
  997.         elseif wp == WEAPON_DISTANCE then
  998.             return upgrade_types.distance
  999.         elseif wp == WEAPON_WAND then
  1000.             return upgrade_types.wand
  1001.         elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE}, wp) then
  1002.             return upgrade_types.weapon
  1003.         end
  1004.     else
  1005.         local slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  1006.         if it_id:getArmor() > 0 or STATS_SYSTEM_CONFIG.upgradeItemsWithNoArmor then
  1007.             if slot == SLOTP_HEAD then
  1008.                 return upgrade_types.helmet
  1009.             elseif slot == SLOTP_ARMOR then
  1010.                 return upgrade_types.armor
  1011.             elseif slot == SLOTP_LEGS then
  1012.                 return upgrade_types.legs
  1013.             elseif slot == SLOTP_FEET then
  1014.                 return upgrade_types.boots
  1015.             end
  1016.         end
  1017.        
  1018.         if slot == SLOTP_NECKLACE then
  1019.             return upgrade_types.necklace
  1020.         end
  1021.        
  1022.         if slot == SLOTP_RING then
  1023.             return upgrade_types.ring
  1024.         end
  1025.     end
  1026.    
  1027.     return upgrade_types.none
  1028. end
  1029.  
  1030. function Item.getStatSlotCount(self)
  1031.     local c = 0
  1032.     for _ in self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION):gmatch('%[(.-)%]') do
  1033.         c = c+1
  1034.     end
  1035.     return c
  1036. end
  1037.  
  1038. function Item.getStatSlots(self)
  1039.     local t = {}
  1040.     for _ in self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION):gmatch('(%[.-%])') do
  1041.         if _ then
  1042.             if _:match('%[(.+)%]') then
  1043.                 local n = _:match('%[(.+)%]')
  1044.                 if n ~= '?' then
  1045.                     local n1 = n:split(".")
  1046.                     local i = #t + 1
  1047.                     t[i] = {n1[1], n1[2]}
  1048.                 end
  1049.             end
  1050.         end
  1051.     end
  1052.     return t
  1053. end
  1054.  
  1055. function Item.addStatSlot(self, spell, val, suffix)
  1056.     if spell and val then
  1057.         if not suffix then suffix = "" end
  1058.         self:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, self:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION) .. "[" .. spell .. "." .. (val >= 0 and "+" .. val or val) .. suffix .. "]")
  1059.     else
  1060.         return false
  1061.     end
  1062. return true
  1063. end
  1064.  
  1065. function Item.getBaseDuration(self)
  1066.     local it_id = self:getId()
  1067.     local tid = ItemType(it_id):getTransformEquipId()
  1068.     if tid > 0 then
  1069.         self:transform(tid)
  1070.         local vx = self:getAttribute(ITEM_ATTRIBUTE_DURATION)
  1071.         self:transform(it_id)
  1072.         self:removeAttribute(ITEM_ATTRIBUTE_DURATION)
  1073.         return vx
  1074.     end
  1075.     return 0
  1076. end
  1077.  
  1078. function Item.getBaseStatsInfo(self)
  1079.     local it_id = ItemType(self:getId())
  1080.     local t = {
  1081.         attack = it_id:getAttack(),
  1082.         defense = it_id:getDefense(),
  1083.         extraDefense = it_id:getExtraDefense(),
  1084.         armor = it_id:getArmor(),
  1085.         hitChance = it_id:getHitChance(),
  1086.         shootRange = it_id:getShootRange(),
  1087.         charges = it_id:getCharges(),
  1088.         duration = self:getBaseDuration()
  1089.     }
  1090.     return t
  1091. end
  1092.  
  1093. function getEnchantingSkill(tries)
  1094. local xp = 0
  1095. local level = 0
  1096.     for lv = 1, STATS_SYSTEM_CONFIG.maxLevel do
  1097.         xp = STATS_SYSTEM_CONFIG.skillFormula(lv) -- alternative: xp = xp + STATS_SYSTEM_CONFIG.skillFormula(lv)
  1098.         if tries < xp then
  1099.             level = lv
  1100.             break
  1101.         end
  1102.         level = lv
  1103.     end
  1104.     return level
  1105. end
  1106.  
  1107. local SPELL_TYPE_VALUE = 1
  1108. local SPELL_TYPE_PERCENT = 2
  1109. local attrkeys = {
  1110.     ['charges'] = ITEM_ATTRIBUTE_CHARGES,
  1111.     ['time'] = ITEM_ATTRIBUTE_DURATION,
  1112.     ['atk'] = ITEM_ATTRIBUTE_ATTACK,
  1113.     ['def'] = ITEM_ATTRIBUTE_DEFENSE,
  1114.     ['extra def'] = ITEM_ATTRIBUTE_EXTRADEFENSE,
  1115.     ['arm'] = ITEM_ATTRIBUTE_ARMOR,
  1116.     ['accuracy'] = ITEM_ATTRIBUTE_HITCHANCE,
  1117.     ['range'] = ITEM_ATTRIBUTE_SHOOTRANGE
  1118. }
  1119.  
  1120. function Item.addStat(item, spellname, spellvalue, suffix, cid)
  1121.     if isInArray({'charges', 'time', 'atk', 'def', 'extra def', 'arm', 'accuracy', 'range'}, spellname) then
  1122.         local basestats = item:getBaseStatsInfo()
  1123.         local basestats2 = {
  1124.             ['charges'] = basestats.charges,
  1125.             ['time'] = basestats.duration,
  1126.             ['atk'] = basestats.attack,
  1127.             ['def'] = basestats.defense,
  1128.             ['extra def'] = basestats.extraDefense,
  1129.             ['arm'] = basestats.armor,
  1130.             ['accuracy'] = basestats.hitChance,
  1131.             ['range'] = basestats.shootRange
  1132.         }
  1133.        
  1134.         local uid = item:getUniqueId()
  1135.         local fullstats = {
  1136.             ['charges'] = getItemAttribute(uid, ITEM_ATTRIBUTE_CHARGES),
  1137.             ['time'] = basestats2['time'],
  1138.             ['atk'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ATTACK),
  1139.             ['def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_DEFENSE),
  1140.             ['extra def'] = getItemAttribute(uid, ITEM_ATTRIBUTE_EXTRADEFENSE),
  1141.             ['arm'] = getItemAttribute(uid, ITEM_ATTRIBUTE_ARMOR),
  1142.             ['accuracy'] = getItemAttribute(uid, ITEM_ATTRIBUTE_HITCHANCE),
  1143.             ['range'] = getItemAttribute(uid, ITEM_ATTRIBUTE_SHOOTRANGE)
  1144.         }
  1145.        
  1146.        
  1147.         if suffix == "%" then
  1148.             if basestats2[spellname] == 0 then
  1149.                 if cid then
  1150.                     Player(cid):sendTextMessage(MESSAGE_INFO_DESCR, "Spell " .. spellname .. "% is not available for this item.")
  1151.                 end
  1152.                 return false
  1153.             end
  1154.             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
  1155.         else
  1156.             item:setAttribute(attrkeys[spellname], fullstats[spellname] + math.abs(spellvalue))
  1157.         end
  1158.     end
  1159.     item:addStatSlot(spellname, spellvalue, suffix)
  1160.     return true
  1161. end
  1162.  
  1163. local upgradable_stats = {
  1164.     [1] = {ITEM_ATTRIBUTE_ATTACK, function(id) return id:getAttack() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.atk},
  1165.     [2] = {ITEM_ATTRIBUTE_DEFENSE, function(id) return id:getDefense() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.def},
  1166.     [3] = {ITEM_ATTRIBUTE_EXTRADEFENSE, function(id) return id:getExtraDefense() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.extradef},
  1167.     [4] = {ITEM_ATTRIBUTE_ARMOR, function(id) return id:getArmor() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.arm},
  1168.     [5] = {ITEM_ATTRIBUTE_HITCHANCE, function(id) return id:getHitChance() end, STATS_SYSTEM_CONFIG.UPGRADE_STATS_VALUES_PER_LVL.hitchance},
  1169.     [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}
  1170. }
  1171.  
  1172. function stat_onUse(player, item, fromPosition, itemEx, toPosition, attempt)
  1173.     if not (item.itemid == 8300) then
  1174.     -- upgrade level instead of slot
  1175.         if STATS_SYSTEM_CONFIG.rare_loot_level then
  1176.             local it_id = ItemType(itemEx.itemid)
  1177.             if not it_id:isStackable() then            
  1178.                 if it_id:getTransformEquipId() < 1 then
  1179.                     if it_id:getCharges() < 1 then
  1180.                         local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  1181.                         if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING then
  1182.                             local stat_min = 1
  1183.                             if STATS_SYSTEM_CONFIG.rare_negative_level then
  1184.                                 stat_min = STATS_SYSTEM_CONFIG.rare_min_level
  1185.                             end
  1186.                            
  1187.                             local stat_max = #STATS_SYSTEM_CONFIG.weapon_levels
  1188.                             local stat_lvl = tonumber(getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):match("%s%+%d+") or getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):match("%s%-%d+"))
  1189.                             if stat_lvl == stat_max then
  1190.                                 player:sendTextMessage(MESSAGE_INFO_DESCR, "This item is on max level already.")
  1191.                                 return true
  1192.                             end
  1193.                            
  1194.                             local n_lvl = stat_lvl
  1195.                             if not stat_lvl then
  1196.                                 stat_lvl = 0
  1197.                             end
  1198.                            
  1199.                             local chance = STATS_SYSTEM_CONFIG.levelUpgradeFormula(stat_lvl, stat_min)
  1200.                             local it_u = Item(itemEx.uid)
  1201.                             local it_name = it_u:getName()
  1202.                             if stat_lvl > 0 then
  1203.                                 it_name = getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):split("+")[1]
  1204.                             elseif stat_lvl < 0 then
  1205.                                 it_name = getItemAttribute(itemEx.uid, ITEM_ATTRIBUTE_NAME):split("-")[1]
  1206.                             end
  1207.                            
  1208.                             it_name = it_name:gsub("^%s*(.-)%s*$", "%1")
  1209.                            
  1210.                             if math.random(1, 100) <= chance then
  1211.                                 n_lvl = stat_lvl + 1
  1212.                             else
  1213.                                 if STATS_SYSTEM_CONFIG.simple.downgradeOnFail then
  1214.                                     n_lvl = stat_lvl - 1
  1215.                                 end
  1216.                             end
  1217.                            
  1218.                             for i = 1, #upgradable_stats do
  1219.                                 local n_item_stat = upgradable_stats[i][2](it_id)
  1220.                                 it_u:setAttribute(upgradable_stats[i][1], getItemAttribute(itemEx.uid, upgradable_stats[i][1]) + (upgradable_stats[i][3] * (n_lvl - stat_lvl)))
  1221.                             end
  1222.  
  1223.                             Item(item.uid):remove(1)
  1224.                             if (n_lvl - stat_lvl) > 0 then
  1225.                                 player:sendTextMessage(MESSAGE_INFO_DESCR, it_name:gsub("^%l", string.upper) .. " upgraded to " .. (n_lvl > 0 and "+" or "") .. n_lvl .. ".")
  1226.                                 toPosition:sendMagicEffect(CONST_ME_MAGIC_GREEN)
  1227.                             else
  1228.                                 player:sendTextMessage(MESSAGE_INFO_DESCR, "Attempt to upgrade failed.")
  1229.                                 toPosition:sendMagicEffect(CONST_ME_HITAREA)
  1230.                             end
  1231.                            
  1232.                             it_u:setAttribute(ITEM_ATTRIBUTE_NAME, it_name .. (n_lvl ~= 0 and (" " .. (n_lvl > 0 and "+" or "") .. n_lvl) or ""))
  1233.                             return true
  1234.                         end
  1235.                     end
  1236.                 end
  1237.             end
  1238.         end
  1239.         return false
  1240.     end
  1241.    
  1242.     if not attempt then
  1243.         attempt = 1
  1244.     end
  1245.    
  1246.     if attempt == 10 then
  1247.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Unable to add slot.")
  1248.         return true
  1249.     end
  1250.    
  1251.     local it_u = Item(itemEx.uid)
  1252.     if not it_u then
  1253.         return false
  1254.     end
  1255.    
  1256.     if not STATS_SYSTEM_CONFIG.simple.enabled then
  1257.         return false
  1258.     end
  1259.    
  1260.     if not STATS_SYSTEM_CONFIG.simple.randomSpells then
  1261.         -- popup modal
  1262.         -- popUpStatModal_index(player, item.uid)
  1263.         print("todo: modal window")
  1264.         return true
  1265.     end
  1266.    
  1267.     if isInArray(STATS_SYSTEM_CONFIG.ignoredIds, itemEx.itemid) then
  1268.         player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade this item.")
  1269.         return true
  1270.     end
  1271.    
  1272.     local it_id = ItemType(itemEx.itemid)
  1273.     local u = it_u:getUpgradeType()
  1274.    
  1275.     if not u then
  1276.         player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade this item.")
  1277.         return true
  1278.     end
  1279.    
  1280.     if not STATS_SYSTEM_CONFIG.upgradeMagicItems then
  1281.         local atr = it_u:getDescription():match('%((.+)%)')
  1282.         if atr and magic_words then
  1283.             if #magic_words > 0 then
  1284.                 for i = 1, #magic_words do
  1285.                     if atr:match(magic_words[i]) then
  1286.                         player:sendTextMessage(MESSAGE_INFO_DESCR, "You cannot upgrade magic items.")
  1287.                         return true
  1288.                     end
  1289.                 end
  1290.             end
  1291.         end
  1292.     end
  1293.    
  1294.     local stat = math.random(1, #u)
  1295.    
  1296.     local tries = player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage)
  1297.     if tries < 0 then
  1298.         player:setStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage, 0)
  1299.     end
  1300.    
  1301.     local level = STATS_SYSTEM_CONFIG.useSkill and getEnchantingSkill(tries) or math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  1302.    
  1303.     local spellname = u[stat][1]   
  1304.     local spelltype = 0
  1305.     local available_spell_types = {}
  1306.    
  1307.     for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  1308.         if STATS_SYSTEM_CONFIG.STATS[i].name == spellname then
  1309.             if STATS_SYSTEM_CONFIG.STATS[i].enabledValues then
  1310.                 table.insert(available_spell_types, SPELL_TYPE_VALUE)
  1311.             end
  1312.            
  1313.             if STATS_SYSTEM_CONFIG.STATS[i].enabledPercent then
  1314.                 table.insert(available_spell_types, SPELL_TYPE_PERCENT)
  1315.             end
  1316.            
  1317.             if #available_spell_types > 0 then
  1318.                 spelltype = available_spell_types[math.random(1, #available_spell_types)]
  1319.             end
  1320.             break
  1321.         end
  1322.     end
  1323.    
  1324.     if spelltype == 0 then
  1325.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1326.         return true
  1327.     end
  1328.    
  1329.     local spellattr = nil
  1330.     for i = 1, #STATS_SYSTEM_CONFIG.STATS do
  1331.         if STATS_SYSTEM_CONFIG.STATS[i].name == spellname then
  1332.             spellattr = STATS_SYSTEM_CONFIG.STATS[i]
  1333.             break
  1334.         end
  1335.     end
  1336.    
  1337.     if not spellattr then
  1338.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1339.         return true
  1340.     end
  1341.        
  1342.     local prc = (level * 100/STATS_SYSTEM_CONFIG.maxLevel)/100
  1343.     local attrval = 0
  1344.     local attrstr = ""
  1345.    
  1346.     if spelltype == SPELL_TYPE_VALUE then
  1347.         attrval = math.floor(prc * u[stat][2])
  1348.     elseif spelltype == SPELL_TYPE_PERCENT then
  1349.         attrval = math.floor(prc * u[stat][3])
  1350.         attrstr = "%"
  1351.     end
  1352.  
  1353.     if attrval == 0 then
  1354.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Error: spell is unavailable.")
  1355.         return true
  1356.     end
  1357.    
  1358.     local slotc = it_u:getStatSlotCount()
  1359.     if slotc == STATS_SYSTEM_CONFIG.maxSlotCount then
  1360.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Slot limit reached.")
  1361.         return true
  1362.     end
  1363.    
  1364.     local cur_slots = it_u:getStatSlots()
  1365.     for i = 1, slotc do
  1366.         if spellname == cur_slots[i][1] then
  1367.             player:sendTextMessage(MESSAGE_INFO_DESCR, "Duplicate stat, try again.")
  1368.             -- stat_onUse(player, item, fromPosition, itemEx, toPosition, attempt + 1)
  1369.             return true
  1370.         end
  1371.     end
  1372.  
  1373.     if it_u:addStat(spellname, attrval, attrstr, player:getId()) then
  1374.         toPosition:sendMagicEffect(CONST_ME_MAGIC_GREEN)
  1375.         player:sendTextMessage(MESSAGE_INFO_DESCR, "Upgrade successful.\n" .. spellattr.spellName .. " " .. (attrval >= 0 and "+" .. attrval or attrval) .. attrstr)
  1376.         doRemoveItem(item.uid)
  1377.         if STATS_SYSTEM_CONFIG.useSkill then
  1378.             player:setStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage, player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage) + 1)
  1379.             local nlevel = STATS_SYSTEM_CONFIG.useSkill and getEnchantingSkill(player:getStorageValue(STATS_SYSTEM_CONFIG.skillTriesStorage)) or math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  1380.             if nlevel > level then
  1381.                 player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You advanced to enchanting Level " .. (nlevel < STATS_SYSTEM_CONFIG.maxLevel and nlevel or nlevel .. " [max]") .. ".")
  1382.             end
  1383.         end
  1384.     end
  1385.     return true
  1386. end
  1387.    
  1388. local slots = {
  1389.     CONST_SLOT_HEAD,
  1390.     CONST_SLOT_NECKLACE,
  1391.     CONST_SLOT_BACKPACK,
  1392.     CONST_SLOT_ARMOR,
  1393.     CONST_SLOT_RIGHT,
  1394.     CONST_SLOT_LEFT,
  1395.     CONST_SLOT_LEGS,
  1396.     CONST_SLOT_FEET,
  1397.     CONST_SLOT_RING,
  1398.     CONST_SLOT_AMMO
  1399. }
  1400.  
  1401. local human_looktypes = {
  1402.     57, 58, 62, 63, 64, 66, 69, 70, 71, 72, 73, 75, 93, 96, 97,
  1403.     98, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137,
  1404.     138, 139, 140, 141, 142, 143, 144, 145, 145, 147, 148, 149,
  1405.     150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 193,
  1406.     194, 203, 251, 252, 253, 254, 255, 264, 266, 268, 269, 270,
  1407.     273, 278, 279, 288, 289, 302, 324, 325, 328, 329, 331, 332,
  1408.     366, 367, 386, 416, 423, 430, 431, 432, 433, 463, 464, 465,
  1409.     466, 471, 472, 493, 507, 512, 513, 513, 516, 537, 538, 539,
  1410.     541, 542, 574, 575, 577, 578, 610, 618, 619, 620
  1411. }
  1412.  
  1413. function stat_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
  1414.     if origin == 2 then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1415.     if not creature then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1416.     if not attacker then return primaryDamage, primaryType, secondaryDamage, secondaryType end
  1417.     local cid = creature:getId()
  1418.     local aid = attacker:getId()
  1419.    
  1420.     -- weapon extra damage
  1421.     if attacker:isPlayer() then
  1422.         for i = CONST_SLOT_RIGHT, CONST_SLOT_LEFT do
  1423.             local item = attacker:getSlotItem(slots[i])
  1424.             if item then
  1425.                 local cur_slots = item:getStatSlots()
  1426.                 local it_id = ItemType(item:getId())
  1427.                 if it_id:getWeaponType() > 0 and it_id:getWeaponType() ~= WEAPON_SHIELD then
  1428.                     local slotc = item:getStatSlotCount()
  1429.                     if slotc > 0 then
  1430.                         for i = 1, slotc do
  1431.                             if element_stats[cur_slots[i][1]] then
  1432.                                 if cur_slots[i][2]:match("%%") then
  1433.                                     local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1434.                                     doTargetCombatHealth(aid, cid, element_stats[cur_slots[i][1]], 1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1435.                                 else
  1436.                                     doTargetCombatHealth(aid, cid, element_stats[cur_slots[i][1]], 1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1437.                                 end
  1438.                             else
  1439.                                 if creature and attacker then
  1440.                                     if creature:getId() ~= attacker:getId() then
  1441.                                         if cur_slots[i][1] == 'drainHP' then
  1442.                                             if cur_slots[i][2]:match("%%") then
  1443.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1444.                                                 local hp_d = math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1445.                                                 creature:addHealth(-hp_d)
  1446.                                                 attacker:addHealth(hp_d)
  1447.                                             else
  1448.                                                 local hp_d = math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1449.                                                 creature:addHealth(-hp_d)
  1450.                                                 attacker:addHealth(hp_d)
  1451.                                             end
  1452.                                         end
  1453.                                        
  1454.                                         if cur_slots[i][1] == 'drainMP' then
  1455.                                             if creature:getMana() > 0 then
  1456.                                                 if cur_slots[i][2]:match("%%") then
  1457.                                                     local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1458.                                                     local mp_d = math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1459.                                                     creature:addMana(mp_d)
  1460.                                                     attacker:addMana(-mp_d)
  1461.                                                 else
  1462.                                                     local mp_d = math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1463.                                                     creature:addMana(mp_d)
  1464.                                                     attacker:addMana(-mp_d)
  1465.                                                 end
  1466.                                             end
  1467.                                         end
  1468.                                     end
  1469.                                 end
  1470.                            
  1471.                                 if (creature:isPlayer() or isInArray(human_looktypes, creature:getOutfit().lookType)) and cur_slots[i][1] == 'humans' then
  1472.                                     if cur_slots[i][2]:match("%%") then
  1473.                                         local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1474.                                         primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1475.                                     else
  1476.                                         primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1477.                                     end
  1478.                                 end
  1479.                                
  1480.                                 if creature:isMonster() then
  1481.                                     local race = MonsterType(creature:getName()):getRace()
  1482.                                     local name = creature:getName():lower()
  1483.                                     if cur_slots[i][1] == 'insects' then
  1484.                                         if race == 1 then
  1485.                                             if cur_slots[i][2]:match("%%") then
  1486.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1487.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1488.                                             else
  1489.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1490.                                             end
  1491.                                         end
  1492.                                     elseif cur_slots[i][1] == 'animals' then
  1493.                                         if race == 2 and not isInArray(human_looktypes, creature:getOutfit().lookType) then
  1494.                                             if cur_slots[i][2]:match("%%") then
  1495.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1496.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1497.                                             else
  1498.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1499.                                             end
  1500.                                         end
  1501.                                     elseif cur_slots[i][1] == 'undeads' then
  1502.                                         if race == 3 then
  1503.                                             if cur_slots[i][2]:match("%%") then
  1504.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1505.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1506.                                             else
  1507.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1508.                                             end
  1509.                                         end
  1510.                                     elseif cur_slots[i][1] == 'elementals' then
  1511.                                         if race == 4 or race == 5 or name:match("elemental") then
  1512.                                             if cur_slots[i][2]:match("%%") then
  1513.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1514.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1515.                                             else
  1516.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1517.                                             end
  1518.                                         end
  1519.                                     elseif cur_slots[i][1] == 'dragons' then
  1520.                                         if name:match("dragon") then
  1521.                                             if cur_slots[i][2]:match("%%") then
  1522.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1523.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1524.                                             else
  1525.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1526.                                             end
  1527.                                         end
  1528.                                     elseif cur_slots[i][1] == 'lizards' then
  1529.                                         if name:match("lizard") or name:match("draken") then
  1530.                                             if cur_slots[i][2]:match("%%") then
  1531.                                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1532.                                                 primaryDamage = primaryDamage + math.random(1, math.floor((primaryDamage * (tonumber(a..b)/100))))
  1533.                                             else
  1534.                                                 primaryDamage = primaryDamage + math.random(1, math.floor(math.random(0, tonumber(cur_slots[i][2]))))
  1535.                                             end
  1536.                                         end
  1537.                                     end
  1538.                                 end
  1539.                             end
  1540.                         end
  1541.                     end    
  1542.                 end
  1543.             end
  1544.         end
  1545.     end
  1546.  
  1547.     -- armor elemental protection
  1548.     if creature:isPlayer() then
  1549.         for i = 1, #slots do
  1550.             local item = creature:getSlotItem(slots[i])
  1551.             if item then
  1552.                 local it_id = ItemType(item:getId())
  1553.                
  1554.                 if it_id:getWeaponType() == WEAPON_SHIELD or it_id:getWeaponType() == 0 then
  1555.                 local slotc = item:getStatSlotCount()
  1556.                     if slotc > 0 then
  1557.                         local cur_slots = item:getStatSlots()
  1558.                         for i = 1, slotc do
  1559.                             if element_stats[cur_slots[i][1]] then
  1560.                                 if cur_slots[i][2]:match("%%") then
  1561.                                     local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1562.                                     if primaryType == element_stats[cur_slots[i][1]] then
  1563.                                         primaryDamage = math.floor(primaryDamage - (primaryDamage * (tonumber(a..b)/100)))
  1564.                                     end
  1565.  
  1566.                                     if secondaryType == element_stats[cur_slots[i][1]] then
  1567.                                         secondaryDamage = math.floor(secondaryDamage - (secondaryDamage * (tonumber(a..b)/100)))
  1568.                                     end
  1569.                                 else
  1570.                                     if primaryType == element_stats[cur_slots[i][1]] then
  1571.                                         primaryDamage = math.floor(primaryDamage - math.random(0, tonumber(cur_slots[i][2])))
  1572.                                     end
  1573.  
  1574.                                     if secondaryType == element_stats[cur_slots[i][1]] then
  1575.                                         secondaryDamage = math.floor(secondaryDamage - math.random(0, tonumber(cur_slots[i][2])))
  1576.                                     end
  1577.                                 end
  1578.                             end
  1579.                         end    
  1580.                     end
  1581.                 end
  1582.             end
  1583.         end
  1584.     end
  1585.     return primaryDamage, primaryType, secondaryDamage, secondaryType
  1586. end
  1587.  
  1588. function stat_onManaChange(creature, attacker, manaChange, origin)
  1589.     if not creature:isPlayer() then
  1590.         return manaChange
  1591.     end
  1592.     for i = 1, #slots do
  1593.         local item = creature:getSlotItem(slots[i])
  1594.         if item then
  1595.             local it_id = ItemType(item:getId())
  1596.            
  1597.             if it_id:getWeaponType() == WEAPON_SHIELD or it_id:getWeaponType() == 0 then
  1598.             local slotc = item:getStatSlotCount()
  1599.                 if slotc > 0 then
  1600.                     local cur_slots = item:getStatSlots()
  1601.                     for i = 1, slotc do
  1602.                         if cur_slots[i][1] == 'manadrain' then
  1603.                             if cur_slots[i][2]:match("%%") then
  1604.                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1605.                                 manaChange = manaChange + (manaChange * (tonumber(a..b)/100))
  1606.                             else
  1607.                                 manaChange = manaChange + math.random(0, tonumber(cur_slots[i][2]))
  1608.                             end
  1609.                         end
  1610.                     end    
  1611.                 end
  1612.             end
  1613.         end
  1614.     end
  1615.     return manaChange
  1616. end
  1617.  
  1618. function isWeapon(uid) return (getItemWeaponType(uid) > 0 and getItemWeaponType(uid) ~= 4) end
  1619. function isShield(uid) return getItemWeaponType(uid) == 4 end
  1620. function isBow(uid) return (getItemWeaponType(uid) == 5 and (not ItemType(getThing(uid).itemid):isStackable())) end
  1621.    
  1622. function check_slot(aab, i)
  1623.     if i == 5 or i == 6 then
  1624.         if isWeapon(aab) or isShield(aab) or isBow(aab) then
  1625.             return true
  1626.         end
  1627.     else
  1628.         return true
  1629.     end
  1630. return false
  1631. end
  1632.  
  1633. local player_regen = {
  1634.  
  1635. }
  1636.  
  1637. function stat_regen(cid, itemid, slot, checkid)
  1638.     if not checkid then checkid = 1 end
  1639.     if not player_regen[cid] then return true end
  1640.     if not player_regen[cid][slot] then return true end
  1641.     local player = Player(cid)
  1642.     if not player then return true end
  1643.     local item = player:getSlotItem(slot)
  1644.     if not item then
  1645.         player_regen[cid][slot] = {}
  1646.         return true
  1647.     end
  1648.     if item:getId() ~= itemid then return true end
  1649.    
  1650.     local slotc = item:getStatSlotCount()
  1651.     if slotc == 0 then
  1652.         player_regen[cid][slot] = {}
  1653.         return true
  1654.     end
  1655.    
  1656.     if checkid == 20 then
  1657.         local cur_slots = item:getStatSlots()
  1658.         for i = 1, slotc do
  1659.             if cur_slots[i][1] == 'regHP' or cur_slots[i][1] == 'regMP' then
  1660.                 if cur_slots[i][2]:match("%%") then
  1661.                     local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1662.                     if cur_slots[i][1] == 'regHP' then
  1663.                         player:addHealth(math.ceil(player:getMaxHealth() * (tonumber(a..b))/100))
  1664.                     end
  1665.                    
  1666.                     if cur_slots[i][1] == 'regMP' then
  1667.                         player:addMana(math.ceil(player:getMaxMana() * (tonumber(a..b))/100))
  1668.                     end
  1669.                 else
  1670.                     if cur_slots[i][1] == 'regHP' then
  1671.                         player:addHealth(tonumber(cur_slots[i][2]))
  1672.                     end
  1673.                    
  1674.                     if cur_slots[i][1] == 'regMP' then
  1675.                         player:addMana(tonumber(cur_slots[i][2]))
  1676.                     end
  1677.                 end
  1678.             end
  1679.         end
  1680.         addEvent(stat_regen, 100, cid, itemid, slot)
  1681.         return true
  1682.     end
  1683.     addEvent(stat_regen, 100, cid, itemid, slot, checkid + 1)
  1684.     return true
  1685. end
  1686.  
  1687. local eq_stat_conditions = {'hp', 'mp', 'ml', 'melee', 'shield', 'dist'}
  1688. function stat_load(cid)
  1689. local player = Player(cid)
  1690. local v_stat_percent = {}
  1691. local v_stat_normal = {}
  1692.     for j = 1, 9 do
  1693.         local item = player:getSlotItem(j)
  1694.         if item then
  1695.             if ItemType(item:getId()):getWeaponType() == WEAPON_SHIELD or ItemType(item:getId()):getWeaponType() == 0 then
  1696.                 local slotc = item:getStatSlotCount()
  1697.                 if slotc > 0 then
  1698.                     local cur_slots = item:getStatSlots()
  1699.                     for i = 1, slotc do
  1700.                         if isInArray(eq_stat_conditions, cur_slots[i][1]) then
  1701.                             if cur_slots[i][2]:match("%%") then
  1702.                                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1703.                                 if not v_stat_percent[cur_slots[i][1]] then
  1704.                                     v_stat_percent[cur_slots[i][1]] = 0
  1705.                                 end
  1706.                                 v_stat_percent[cur_slots[i][1]] = v_stat_percent[cur_slots[i][1]] + (tonumber(a..b)/100)
  1707.                             else
  1708.                                 if not v_stat_normal[cur_slots[i][1]] then
  1709.                                     v_stat_normal[cur_slots[i][1]] = 0
  1710.                                 end
  1711.                                 v_stat_normal[cur_slots[i][1]] = v_stat_normal[cur_slots[i][1]] + tonumber(cur_slots[i][2])
  1712.                             end
  1713.                         else
  1714.                             if cur_slots[i][1] == 'regHP' or cur_slots[i][1] == 'regMP' then
  1715.                                 if not player_regen[cid] then player_regen[cid] = {} end
  1716.                                 if not player_regen[cid][j] then player_regen[cid][j] = {} end
  1717.                                 local value = tonumber(cur_slots[i][2])
  1718.                                 if not value then
  1719.                                     local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1720.                                     value = tonumber(a..b)/100
  1721.                                 end
  1722.                                 player_regen[cid][j] = {value = value, percent = (cur_slots[i][2]:match("%%") and true)}
  1723.                                 stat_regen(cid, item:getId(), j)
  1724.                             end
  1725.                         end
  1726.                     end
  1727.                 end
  1728.             end
  1729.         end
  1730.     end
  1731.    
  1732.     local fu = 0 -- functions used
  1733.     local ca = {} -- conditions assigned
  1734.     for i = 1, #eq_stat_conditions do
  1735.         if eq_stat_conditions[i] == 'hp' then
  1736.             if v_stat_normal[eq_stat_conditions[i]] then
  1737.                 fu = fu+1
  1738.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(1500, v_stat_normal[eq_stat_conditions[i]]), -1500)])
  1739.                 ca[56] = 1
  1740.             end
  1741.            
  1742.             if v_stat_percent[eq_stat_conditions[i]] then
  1743.                 fu = fu+1
  1744.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1745.                 ca[50] = 1
  1746.             end
  1747.         elseif eq_stat_conditions[i] == 'mp' then
  1748.             if v_stat_normal[eq_stat_conditions[i]] then
  1749.                 fu = fu+1
  1750.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(1500, v_stat_normal[eq_stat_conditions[i]]), -1500)])
  1751.                 ca[57] = 1
  1752.             end
  1753.            
  1754.             if v_stat_percent[eq_stat_conditions[i]] then
  1755.                 fu = fu+1
  1756.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1757.                 ca[51] = 1
  1758.             end
  1759.         elseif eq_stat_conditions[i] == 'ml' then
  1760.             if v_stat_normal[eq_stat_conditions[i]] then
  1761.                 fu = fu+1
  1762.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100)])
  1763.                 ca[58] = 1
  1764.             end
  1765.            
  1766.             if v_stat_percent[eq_stat_conditions[i]] then
  1767.                 fu = fu+1
  1768.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1769.                 ca[52] = 1
  1770.             end
  1771.         elseif eq_stat_conditions[i] == 'melee' then
  1772.             if v_stat_normal[eq_stat_conditions[i]] then
  1773.                 fu = fu+1
  1774.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100)])
  1775.                 ca[59] = 1
  1776.             end
  1777.            
  1778.             if v_stat_percent[eq_stat_conditions[i]] then
  1779.                 fu = fu+1
  1780.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1781.                 ca[53] = 1
  1782.             end
  1783.         elseif eq_stat_conditions[i] == 'shield' then
  1784.             if v_stat_normal[eq_stat_conditions[i]] then
  1785.                 fu = fu+1
  1786.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100)])
  1787.                 ca[60] = 1
  1788.             end
  1789.            
  1790.             if v_stat_percent[eq_stat_conditions[i]] then
  1791.                 fu = fu+1
  1792.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1793.                 ca[54] = 1
  1794.             end
  1795.         elseif eq_stat_conditions[i] == 'dist' then
  1796.             if v_stat_normal[eq_stat_conditions[i]] then
  1797.                 fu = fu+1
  1798.                 doAddCondition(cid,stat_conditions[1][eq_stat_conditions[i]][math.max(math.min(100, v_stat_normal[eq_stat_conditions[i]]), -100)])
  1799.                 ca[61] = 1
  1800.             end
  1801.            
  1802.             if v_stat_percent[eq_stat_conditions[i]] then
  1803.                 fu = fu+1
  1804.                 doAddCondition(cid,stat_conditions[2][eq_stat_conditions[i]][math.max(math.min(300, v_stat_percent[eq_stat_conditions[i]] * 100), -95)])
  1805.                 ca[55] = 1
  1806.             end
  1807.         end
  1808.     end
  1809.     if fu > 0 then
  1810.         for i=50,61 do
  1811.             if not ca[i] then
  1812.                 doRemoveCondition(cid,CONDITION_ATTRIBUTES,i)
  1813.             end
  1814.         end
  1815.     else
  1816.         for i=50,61 do
  1817.             doRemoveCondition(cid,CONDITION_ATTRIBUTES,i)
  1818.         end
  1819.     end
  1820.    
  1821.     return true
  1822. end
  1823.  
  1824. function loadSet(cid)
  1825.     local t = {}
  1826.     for slot=1,9 do
  1827.         t[slot] = ''
  1828.         local s = getPlayerSlotItem(cid,slot).uid
  1829.         if s ~= 0 then
  1830.             t[slot] = Item(s):getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
  1831.         end
  1832.     end
  1833.     return t
  1834. end
  1835.  
  1836. function chk(cid,f)
  1837.     if not isPlayer(cid) then return false end
  1838.     local t = loadSet(cid)
  1839.     for i=1,#f do
  1840.         if f[i] ~= t[i] then
  1841.             stat_load(cid)
  1842.             break
  1843.         end
  1844.     end
  1845.     addEvent(chk,2000,cid,t)
  1846. end
  1847.  
  1848. function stat_onLogin(player)
  1849.     player:registerEvent("statHP")
  1850.     player:registerEvent("statMP")
  1851.     player:registerEvent("statPVE")
  1852.     player:registerEvent("statLoot")
  1853.    
  1854.     local cid = player:getId()
  1855.     stat_load(cid)
  1856.     addEvent(chk,2000,cid,loadSet(cid))
  1857. return true
  1858. end
  1859.  
  1860. function stat_onPrepareDeath(creature, lastHitKiller, mostDamageKiller)
  1861.     local necklace = creature:getSlotItem(CONST_SLOT_NECKLACE)
  1862.     local slotc = necklace:getStatSlotCount()
  1863.    
  1864.     if slotc > 0 then
  1865.         local cur_slots = necklace:getStatSlots()
  1866.         for i = 1, slotc do
  1867.             if cur_slots[i][1] == 'PVE death' then
  1868.                 if cur_slots[i][2]:match("%%") then
  1869.                 local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  1870.                     if math.random(1, 100) > tonumber(a..b) then
  1871.                         necklace:remove()
  1872.                         return true
  1873.                     end
  1874.                 end
  1875.                 local maxhp = creature:getMaxHealth()
  1876.                 creature:addHealth(maxhp)
  1877.                 addEvent(doCreatureAddHealth, 100, creature:getId(), maxhp)
  1878.                 creature:teleportTo(creature:getTown():getTemplePosition())
  1879.                 necklace:remove()
  1880.                 return true
  1881.             end
  1882.         end    
  1883.     end
  1884. return true
  1885. end
  1886.  
  1887. function stat_onTargetCombat(self, target)
  1888.     if Player(self) then
  1889.         target:registerEvent("statHP")
  1890.     end
  1891.     return true
  1892. end
  1893.                    
  1894. function assign_loot_Stat(c)
  1895.     local wp_string = {"", ""}
  1896.     local arm_string = {"", ""}
  1897.     local other_string = {"", ""}
  1898.     local rares = 0
  1899.     local h = c:getItemHoldingCount()
  1900.     if h > 0 then
  1901.         for i = 1, h do
  1902.             wp_string = {"", ""}
  1903.             arm_string = {"", ""}
  1904.             other_string = {"", ""}
  1905.             local it_u = c:getItem(i - 1)
  1906.             local u = it_u:getUpgradeType()
  1907.             local upgrade = true
  1908.             local it_id = ItemType(it_u:getId())
  1909.             local slotc = 0
  1910.            
  1911.             if not isInArray(STATS_SYSTEM_CONFIG.ignoredIds, it_u:getId()) then
  1912.                 if it_u:isContainer() then
  1913.                     local crares = assign_loot_Stat(it_u)
  1914.                     rares = rares + crares
  1915.                     upgrade = false
  1916.                 else
  1917.                     if it_id:isStackable() then
  1918.                         upgrade = false
  1919.                     end
  1920.                    
  1921.                     if u then
  1922.                         local atr = it_u:getDescription():match('%((.+)%)')
  1923.                         if atr and magic_words then
  1924.                             if #magic_words > 0 then
  1925.                                 for j = 1, #magic_words do
  1926.                                     if atr:match(magic_words[j]) then
  1927.                                         if STATS_SYSTEM_CONFIG.upgradeMagicItems then
  1928.                                             upgrade = false
  1929.                                         end
  1930.                                     end
  1931.                                 end
  1932.                             end
  1933.                         end
  1934.                     end
  1935.                 end
  1936.  
  1937.                 if u and upgrade then
  1938.                     for n = 1, #STATS_SYSTEM_CONFIG.slotChances do
  1939.                         if math.random(1, 100000) <= STATS_SYSTEM_CONFIG.slotChances[n] then
  1940.                             if slotc + 1 == n then
  1941.                                 local stat = math.random(1, #u)
  1942.                                 local level = math.random(1, STATS_SYSTEM_CONFIG.maxLevel)
  1943.                                 local spellname = u[stat][1]
  1944.                                 local spelltype = 0
  1945.                                 local available_spell_types = {}   
  1946.                                 local statdone = false
  1947.                                 for k = 1, #STATS_SYSTEM_CONFIG.STATS do
  1948.                                     if not statdone then
  1949.                                         if STATS_SYSTEM_CONFIG.STATS[k].name == spellname then
  1950.                                             if STATS_SYSTEM_CONFIG.STATS[k].enabledValues then
  1951.                                                 table.insert(available_spell_types, SPELL_TYPE_VALUE)
  1952.                                             end
  1953.                                            
  1954.                                             if STATS_SYSTEM_CONFIG.STATS[k].enabledPercent then
  1955.                                                 table.insert(available_spell_types, SPELL_TYPE_PERCENT)
  1956.                                             end
  1957.                                            
  1958.                                             if #available_spell_types > 0 then
  1959.                                                 spelltype = available_spell_types[math.random(1, #available_spell_types)]
  1960.                                             end
  1961.                                            
  1962.                                             wp_string = (STATS_SYSTEM_CONFIG.STATS[k].weaponLootName or wp_string)
  1963.                                             arm_string = (STATS_SYSTEM_CONFIG.STATS[k].armorLootName or arm_string)
  1964.                                             other_string = (STATS_SYSTEM_CONFIG.STATS[k].otherLootName or other_string)
  1965.                                            
  1966.                                             statdone = true
  1967.                                         end
  1968.                                     end
  1969.                                 end
  1970.                                
  1971.                                 if spelltype == 0 then
  1972.                                     upgrade = false
  1973.                                 end
  1974.                                
  1975.                                 local spellattr = nil
  1976.                                 for l = 1, #STATS_SYSTEM_CONFIG.STATS do
  1977.                                     if not spellattr then
  1978.                                         if STATS_SYSTEM_CONFIG.STATS[l].name == spellname then
  1979.                                             spellattr = STATS_SYSTEM_CONFIG.STATS[l]
  1980.                                         end
  1981.                                     end
  1982.                                 end
  1983.                                
  1984.                                 if not spellattr then
  1985.                                     upgrade = false
  1986.                                 end
  1987.                                
  1988.                                 if upgrade then
  1989.                                     local prc = (level * 100/STATS_SYSTEM_CONFIG.maxLevel)/100
  1990.                                     local attrval = 0
  1991.                                     local attrstr = ""
  1992.                                    
  1993.                                     if spelltype == SPELL_TYPE_VALUE then
  1994.                                         attrval = math.floor(prc * u[stat][2])
  1995.                                     elseif spelltype == SPELL_TYPE_PERCENT then
  1996.                                         attrval = math.floor(prc * u[stat][3])
  1997.                                         attrstr = "%"
  1998.                                     end
  1999.                                    
  2000.                                     if attrval == 0 then
  2001.                                         upgrade = false
  2002.                                     end
  2003.                                    
  2004.                                     local slotcx = it_u:getStatSlotCount()
  2005.                                     if slotcx == STATS_SYSTEM_CONFIG.maxSlotCount and upgrade then
  2006.                                         upgrade = false
  2007.                                     end
  2008.                                    
  2009.                                     if upgrade then
  2010.                                         local cur_slots = it_u:getStatSlots()
  2011.                                         for m = 1, slotcx do
  2012.                                             if spellname == cur_slots[m][1] then
  2013.                                                 upgrade = false
  2014.                                             end
  2015.                                         end
  2016.                                     end
  2017.                                    
  2018.                                     if upgrade then
  2019.                                         if it_u:addStat(spellname, attrval, attrstr) then
  2020.                                             it_u:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
  2021.                                             rares = rares + 1
  2022.                                             slotc = slotc + 1
  2023.                                         end
  2024.                                     end
  2025.                                 end
  2026.                             end
  2027.                         end
  2028.                     end
  2029.                     if slotc > 1 then
  2030.                         it_u:setAttribute(ITEM_ATTRIBUTE_NAME, (STATS_SYSTEM_CONFIG.tiers[slotc] .. " " or "") .. getItemAttribute(it_u:getUniqueId(), ITEM_ATTRIBUTE_NAME))
  2031.                     elseif slotc == 1 then
  2032.                         local wp = it_id:getWeaponType()
  2033.                         if wp > 0 then
  2034.                             if wp == WEAPON_SHIELD then
  2035.                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, (arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(it_u:getUniqueId(), ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or ""))
  2036.                             elseif isInArray({WEAPON_SWORD, WEAPON_CLUB, WEAPON_AXE, WEAPON_DISTANCE, WEAPON_WAND}, wp) then -- weapon
  2037.                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((wp_string[1] ~= "" and wp_string[1] .. " " or "") .. getItemAttribute(it_u:getUniqueId(), ITEM_ATTRIBUTE_NAME) .. (wp_string[2] ~= "" and " " .. wp_string[2] or "")))
  2038.                             end
  2039.                         else
  2040.                             if it_id:getArmor() > 0 then -- armor
  2041.                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((arm_string[1] ~= "" and arm_string[1] .. " " or "") .. getItemAttribute(it_u:getUniqueId(), ITEM_ATTRIBUTE_NAME) .. (arm_string[2] ~= "" and " " .. arm_string[2] or "")))
  2042.                             else
  2043.                                 it_u:setAttribute(ITEM_ATTRIBUTE_NAME, ((other_string[1] ~= "" and other_string[1] .. " " or "") .. getItemAttribute(it_u:getUniqueId(), ITEM_ATTRIBUTE_NAME) .. (other_string[2] ~= "" and " " .. other_string[2] or "")))
  2044.                             end
  2045.                         end
  2046.                     end
  2047.                 end
  2048.             end
  2049.            
  2050.             if STATS_SYSTEM_CONFIG.rare_loot_level then
  2051.                 if not it_id:isStackable() then
  2052.                     if it_id:getTransformEquipId() < 1 then
  2053.                         if it_id:getCharges() < 1 then
  2054.                             local item_sp_slot = it_id:getSlotPosition() - SLOTP_LEFT - SLOTP_RIGHT
  2055.                             if item_sp_slot ~= SLOTP_NECKLACE and item_sp_slot ~= SLOTP_RING then
  2056.                                 local stat_min = 1
  2057.                                 if STATS_SYSTEM_CONFIG.rare_negative_level then
  2058.                                     stat_min = STATS_SYSTEM_CONFIG.rare_min_level
  2059.                                 end
  2060.                                
  2061.                                 local stat_max = #STATS_SYSTEM_CONFIG.weapon_levels
  2062.                                 local it_lvl = math.random(stat_min, stat_max)
  2063.                                
  2064.                                 if STATS_SYSTEM_CONFIG.weapon_levels[it_lvl] then
  2065.                                     if math.random(1, 100000) <= STATS_SYSTEM_CONFIG.weapon_levels[it_lvl][2] then
  2066.                                         for o = 1, #upgradable_stats do
  2067.                                             local n_item_stat = upgradable_stats[o][2](it_id)
  2068.                                             if n_item_stat ~= 0 then
  2069.                                                 it_u:setAttribute(upgradable_stats[o][1], n_item_stat + (upgradable_stats[o][3] * it_lvl))
  2070.                                             end
  2071.                                         end
  2072.                                        
  2073.                                         local uid = it_u:getUniqueId()
  2074.                                         if slotc == 0 then
  2075.                                             it_u:setAttribute(ITEM_ATTRIBUTE_NAME, STATS_SYSTEM_CONFIG.weapon_levels[it_lvl][1] .. " " .. getItemAttribute(uid, ITEM_ATTRIBUTE_NAME))
  2076.                                         end
  2077.                                         it_u:setAttribute(ITEM_ATTRIBUTE_NAME, getItemAttribute(uid, ITEM_ATTRIBUTE_NAME) .. " " .. (it_lvl > 0 and "+" or "") .. it_lvl)
  2078.                                        
  2079.                                         if it_lvl > 5 then
  2080.                                             rares = rares + 1
  2081.                                         end
  2082.                                     end
  2083.                                 end
  2084.                             end
  2085.                         end
  2086.                     end
  2087.                 end
  2088.             end    
  2089.         end
  2090.     end
  2091.     return rares
  2092. end
  2093.  
  2094. function improveChance(c, monsterName, extraPercent, killer)
  2095.     local m = MonsterType(monsterName):getLoot()
  2096.     if math.random(1, 100) <= extraPercent then
  2097.         local t = {}
  2098.         for i = 1, #m do
  2099.             t[i] = {itemId = m[i].itemId, chance = m[i].chance}
  2100.         end
  2101.        
  2102.         local min = 1
  2103.         local t_s = {}
  2104.         local low5 = #t-5
  2105.         while #t > low5 do
  2106.             min = 1
  2107.             for i = 1, #t do
  2108.                 if math.min(t[i].chance, t[min].chance) == t[i].chance then
  2109.                     min = i
  2110.                 end
  2111.             end
  2112.             t_s[#t_s + 1] = {itemId = t[min].itemId, chance = t[min].chance}
  2113.             table.remove(t, min)
  2114.         end
  2115.        
  2116.         local chosenId = math.random(1, #t_s)
  2117.        
  2118.         local h = c:getItemHoldingCount()
  2119.         if h > 0 then
  2120.             local extra = true
  2121.             for i = 1, h do
  2122.                 if ItemType(c:getItem(i - 1):getId()) == t_s[chosenId].itemId then
  2123.                     extra = false
  2124.                     break
  2125.                 end
  2126.             end
  2127.            
  2128.             if extra then
  2129.                 if math.random(1, 100000) <= (t_s[chosenId].chance + (t_s[chosenId].chance * extraPercent / 100)) * configManager.getNumber(configKeys.RATE_LOOT) then
  2130.                     c:addItem(m[chosenId].itemId, 1)
  2131.                     if killer then
  2132.                         local iid = ItemType(m[chosenId].itemId)
  2133.                         Player(killer):sendTextMessage(MESSAGE_EVENT_ADVANCE, "Extra loot: " .. (iid:getArticle() ~= "" and iid:getArticle() .. " " or "") .. iid:getName())
  2134.                     end
  2135.                 end
  2136.             end
  2137.         end
  2138.     end                
  2139.     return true
  2140. end
  2141.  
  2142. function improveStackables(c, v)
  2143.     local h = c:getItemHoldingCount()
  2144.     if h > 0 then
  2145.         for i = 1, h do
  2146.             local it_u = c:getItem(i - 1)
  2147.             local it_id = ItemType(it_u)
  2148.             if it_id:isStackable() then
  2149.                 local amount = math.random(0, v)
  2150.                 if amount > 0 then
  2151.                     c:addItem(it_u:getId(), amount)
  2152.                 end
  2153.             elseif it_u:isContainer() then
  2154.                 improveStackables(it_u, v)
  2155.             end
  2156.         end
  2157.     end
  2158. return true
  2159. end
  2160.  
  2161. function find_loot_Container(pos, extraPercent, monsterName, extraStackable, killer)
  2162.     local rares = 0
  2163.     local c = Tile(pos):getTopDownItem()
  2164.     if c ~= nil then
  2165.         if c:isContainer() then
  2166.             rares = rares + assign_loot_Stat(c)
  2167.             if rares > 0 then
  2168.                 if STATS_SYSTEM_CONFIG.rare_popup then
  2169.                     local spectators = Game.getSpectators(pos, false, true, 7, 7, 5, 5)
  2170.                     for i = 1, #spectators do
  2171.                         spectators[i]:say(STATS_SYSTEM_CONFIG.rare_text, TALKTYPE_MONSTER_SAY, false, spectators[i], pos)
  2172.                     end
  2173.                 end
  2174.  
  2175.                 if STATS_SYSTEM_CONFIG.rare_effect then
  2176.                     pos:sendMagicEffect(STATS_SYSTEM_CONFIG.rare_effect_id)
  2177.                 end
  2178.             end
  2179.            
  2180.             if extraPercent then
  2181.                 if extraPercent > 0 then
  2182.                     if monsterName then
  2183.                         improveChance(c, monsterName, extraPercent, killer)
  2184.                     end
  2185.                 end
  2186.             end
  2187.            
  2188.             if extraStackable then
  2189.                 if extraStackable > 0 then
  2190.                     improveStackables(c, extraStackable)
  2191.                 end
  2192.             end
  2193.            
  2194.         end
  2195.     end
  2196. end
  2197.  
  2198. function Creature.isSummon(self)
  2199.     return self:getMaster()
  2200. end
  2201.  
  2202. function stat_onKill(player, target, lastHit)
  2203.     local extraPercent = 0
  2204.     local extraStackable = 0
  2205.  
  2206.     if target:isMonster() then
  2207.         local ring = player:getSlotItem(CONST_SLOT_RING)
  2208.         local monster = MonsterType(target:getName())
  2209.         if ring then
  2210.             local slotc = ring:getStatSlotCount()
  2211.             local cur_slots = ring:getStatSlots()
  2212.             if slotc > 0 then
  2213.                 for i = 1, slotc do
  2214.                     if cur_slots[i][1] == 'exp' then
  2215.                         local nexp = monster:getExperience()
  2216.                         local k = Game.getExperienceStage(player:getLevel())
  2217.                         local st = player:getStamina()
  2218.                         if st > 2400 then
  2219.                             nexp = nexp * k*1.5
  2220.                         elseif st < 1 then
  2221.                             nexp =  0
  2222.                         elseif st < 841 then
  2223.                             nexp = math.floor(nexp/2)
  2224.                         else
  2225.                             nexp = nexp
  2226.                         end
  2227.                        
  2228.                         if cur_slots[i][2]:match("%%") then
  2229.                             local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  2230.                             player:addExperience(math.random(1, math.ceil((nexp * tonumber(a..b)) / 100)), true)
  2231.                         else
  2232.                             player:addExperience(math.random(1, tonumber(cur_slots[i][2])), true)
  2233.                         end
  2234.                     elseif cur_slots[i][1] == 'loot' then
  2235.                         if cur_slots[i][2]:match("%%") then
  2236.                             local a, b = cur_slots[i][2]:match('([+-])(%d+)%%')
  2237.                             extraPercent = extraPercent + tonumber(a..b)
  2238.                         else
  2239.                             extraStackable = extraStackable + tonumber(cur_slots[i][2])
  2240.                         end
  2241.                     end
  2242.                 end
  2243.             end
  2244.         end
  2245.     end
  2246.  
  2247.     if not STATS_SYSTEM_CONFIG.lootUpgradedItems then
  2248.         return true
  2249.     end
  2250.    
  2251.     if target:isPlayer() or target:isSummon() then
  2252.         return true
  2253.     end
  2254.    
  2255.     addEvent(find_loot_Container, 2, target:getPosition(), extraPercent, target:getName(), extraStackable, player:getId())
  2256.     return true
  2257. end
Add Comment
Please, Sign In to add comment