Berntan

data/stats.lua

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