Guest User

Untitled

a guest
Sep 6th, 2020
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.10 KB | None | 0 0
  1. CONTAINER_WEIGHT_CHECK = true -- true = enable / false = disable
  2. CONTAINER_WEIGHT_MAX = 1000000 -- 1000000 = 10k = 10000.00 oz
  3.  
  4. local storeItemID = {
  5. -- registered item ids here are not tradable with players
  6. -- these items can be set to moveable at items.xml
  7. -- 500 charges exercise weapons
  8. 32384, -- exercise sword
  9. 32385, -- exercise axe
  10. 32386, -- exercise club
  11. 32387, -- exercise bow
  12. 32388, -- exercise rod
  13. 32389, -- exercise wand
  14.  
  15. -- 50 charges exercise weapons
  16. 32124, -- training sword
  17. 32125, -- training axe
  18. 32126, -- training club
  19. 32127, -- training bow
  20. 32128, -- training wand
  21. 32129, -- training club
  22.  
  23. -- magic gold and magic converter (activated/deactivated)
  24. 32109, -- magic gold converter
  25. 33299, -- magic gold converter
  26. 26378, -- gold converter
  27. 29020, -- gold converter
  28.  
  29. -- foods
  30. 35172, -- roasted wyvern wings
  31. 35173, -- carrot pie
  32. 35174, -- tropical marinated tiger
  33. 35175, -- delicatessen salad
  34. 35176, -- chilli con carniphila
  35. 35177, -- svargrond salmon filet
  36. 35178, -- carrion casserole
  37. 35179, -- consecrated beef
  38. 35180, -- overcooked noodles
  39. }
  40.  
  41. -- Capacity imbuement store
  42. local STORAGE_CAPACITY_IMBUEMENT = 42154
  43.  
  44. -- Players cannot throw items on teleports if set to true
  45. local blockTeleportTrashing = true
  46.  
  47. local titles = {
  48. {storageID = 14960, title = " Scout"},
  49. {storageID = 14961, title = " Sentinel"},
  50. {storageID = 14962, title = " Steward"},
  51. {storageID = 14963, title = " Warden"},
  52. {storageID = 14964, title = " Squire"},
  53. {storageID = 14965, title = " Warrior"},
  54. {storageID = 14966, title = " Keeper"},
  55. {storageID = 14967, title = " Guardian"},
  56. {storageID = 14968, title = " Sage"},
  57. {storageID = 14969, title = " Tutor"},
  58. {storageID = 14970, title = " Senior Tutor"},
  59. {storageID = 14971, title = " King"},
  60. }
  61.  
  62. local function getTitle(uid)
  63. local player = Player(uid)
  64. if not player then return false end
  65.  
  66. for i = #titles, 1, -1 do
  67. if player:getStorageValue(titles[i].storageID) == 1 then
  68. return titles[i].title
  69. end
  70. end
  71.  
  72. return false
  73. end
  74.  
  75. function Player:onBrowseField(position)
  76. return true
  77. end
  78.  
  79. local function getHours(seconds)
  80. return math.floor((seconds/60)/60)
  81. end
  82.  
  83. local function getMinutes(seconds)
  84. return math.floor(seconds/60)
  85. end
  86.  
  87. local function getSeconds(seconds)
  88. return seconds%60
  89. end
  90.  
  91. local function getTime(seconds)
  92. local hours, minutes = getHours(seconds), getMinutes(seconds)
  93. if (minutes > 59) then
  94. minutes = minutes-hours*60
  95. end
  96.  
  97. if (minutes < 10) then
  98. minutes = "0" ..minutes
  99. end
  100.  
  101. return hours..":"..minutes.. "h"
  102. end
  103.  
  104. local function getTimeinWords(secs)
  105. local hours, minutes, seconds = getHours(secs), getMinutes(secs), getSeconds(secs)
  106. if (minutes > 59) then
  107. minutes = minutes-hours*60
  108. end
  109.  
  110. local timeStr = ''
  111.  
  112. if hours > 0 then
  113. timeStr = timeStr .. ' hours '
  114. end
  115.  
  116. timeStr = timeStr .. minutes .. ' minutes and '.. seconds .. ' seconds.'
  117.  
  118. return timeStr
  119. end
  120.  
  121. function Player:onLook(thing, position, distance)
  122. local description = "You see "
  123. if thing:isItem() then
  124. if thing.actionid == 5640 then
  125. description = description .. "a honeyflower patch."
  126. elseif thing.actionid == 5641 then
  127. description = description .. "a banana palm."
  128. elseif thing.itemid >= ITEM_HEALTH_CASK_START and thing.itemid <= ITEM_HEALTH_CASK_END
  129. or thing.itemid >= ITEM_MANA_CASK_START and thing.itemid <= ITEM_MANA_CASK_END
  130. or thing.itemid >= ITEM_SPIRIT_CASK_START and thing.itemid <= ITEM_SPIRIT_CASK_END
  131. or thing.itemid >= ITEM_KEG_START and thing.itemid <= ITEM_KEG_END then
  132. description = description .. thing:getDescription(distance)
  133. local charges = thing:getCharges()
  134. if charges then
  135. description = string.format("%s\nIt has %d refillings left.", description, charges)
  136. end
  137. else
  138. description = description .. thing:getDescription(distance)
  139. end
  140.  
  141. local itemType = thing:getType()
  142. if (itemType and itemType:getImbuingSlots() > 0) then
  143. local imbuingSlots = "Imbuements: ("
  144. for slot = 0, itemType:getImbuingSlots() - 1 do
  145. if slot > 0 then
  146. imbuingSlots = string.format("%s, ", imbuingSlots)
  147. end
  148. local duration = thing:getImbuementDuration(slot)
  149. if duration > 0 then
  150. local imbue = thing:getImbuement(slot)
  151. imbuingSlots = string.format("%s%s %s %s",
  152. imbuingSlots, imbue:getBase().name, imbue:getName(), getTime(duration))
  153. else
  154. imbuingSlots = string.format("%sEmpty Slot", imbuingSlots)
  155. end
  156. end
  157. imbuingSlots = string.format("%s).", imbuingSlots)
  158. description = string.gsub(description, "It weighs", imbuingSlots.. "\nIt weighs")
  159. end
  160. else
  161. description = description .. thing:getDescription(distance)
  162. if thing:isMonster() then
  163. local master = thing:getMaster()
  164. if master and table.contains({'thundergiant','grovebeast','emberwing','skullfrost'}, thing:getName():lower()) then
  165. description = description..' (Master: ' .. master:getName() .. '). \z
  166. It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
  167. end
  168. end
  169. end
  170.  
  171. if self:getGroup():getAccess() then
  172. if thing:isItem() then
  173. description = string.format("%s\nItem ID: %d", description, thing:getId())
  174.  
  175. local actionId = thing:getActionId()
  176. if actionId ~= 0 then
  177. description = string.format("%s, Action ID: %d", description, actionId)
  178. end
  179.  
  180. local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_UNIQUEID)
  181. if uniqueId > 0 and uniqueId < 65536 then
  182. description = string.format("%s, Unique ID: %d", description, uniqueId)
  183. end
  184.  
  185. local itemType = thing:getType()
  186.  
  187. local transformEquipId = itemType:getTransformEquipId()
  188. local transformDeEquipId = itemType:getTransformDeEquipId()
  189. if transformEquipId ~= 0 then
  190. description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
  191. elseif transformDeEquipId ~= 0 then
  192. description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
  193. end
  194.  
  195. local decayId = itemType:getDecayId()
  196. if decayId ~= -1 then
  197. description = string.format("%s\nDecays to: %d", description, decayId)
  198. end
  199.  
  200. local clientId = itemType:getClientId()
  201. if clientId then
  202. description = string.format("%s\nClient ID: %d", description, clientId)
  203. end
  204.  
  205. elseif thing:isCreature() then
  206. local str = "%s\nHealth: %d / %d"
  207. if thing:isPlayer() and thing:getMaxMana() > 0 then
  208. str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
  209. end
  210. description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
  211. end
  212.  
  213. description = string.format(
  214. "%s\nPosition: %d, %d, %d",
  215. description, position.x, position.y, position.z
  216. )
  217.  
  218. if thing:isCreature() then
  219. if thing:isPlayer() then
  220. description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
  221. end
  222. end
  223. end
  224. self:sendTextMessage(MESSAGE_INFO_DESCR, description)
  225. end
  226.  
  227. function Player:onLookInBattleList(creature, distance)
  228. local description = "You see " .. creature:getDescription(distance)
  229. if creature:isMonster() then
  230. local master = creature:getMaster()
  231. local summons = {'thundergiant','grovebeast','emberwing','skullfrost'}
  232. if master and table.contains(summons, creature:getName():lower()) then
  233. description = description..' (Master: ' .. master:getName() .. '). \z
  234. It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
  235. end
  236. end
  237. if self:getGroup():getAccess() then
  238. local str = "%s\nHealth: %d / %d"
  239. if creature:isPlayer() and creature:getMaxMana() > 0 then
  240. str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
  241. end
  242. description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
  243.  
  244. local position = creature:getPosition()
  245. description = string.format(
  246. "%s\nPosition: %d, %d, %d",
  247. description, position.x, position.y, position.z
  248.  
  249. )
  250.  
  251. if creature:isPlayer() then
  252. description = string.format("%s\nIP: %s", description, Game.convertIpToString(creature:getIp()))
  253. end
  254. end
  255. self:sendTextMessage(MESSAGE_INFO_DESCR, description)
  256. end
  257.  
  258. function Player:onLookInTrade(partner, item, distance)
  259. self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
  260. end
  261.  
  262. function Player:onLookInShop(itemType, count)
  263. return true
  264. end
  265.  
  266. local config = {
  267. maxItemsPerSeconds = 1,
  268. exhaustTime = 2000,
  269. }
  270.  
  271. if not pushDelay then
  272. pushDelay = { }
  273. end
  274.  
  275. local function antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  276. if toPosition.x == CONTAINER_POSITION then
  277. return true
  278. end
  279.  
  280. local tile = Tile(toPosition)
  281. if not tile then
  282. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  283. return false
  284. end
  285.  
  286. local cid = self:getId()
  287. if not pushDelay[cid] then
  288. pushDelay[cid] = {items = 0, time = 0}
  289. end
  290.  
  291. pushDelay[cid].items = pushDelay[cid].items + 1
  292.  
  293. local currentTime = os.mtime()
  294. if pushDelay[cid].time == 0 then
  295. pushDelay[cid].time = currentTime
  296. elseif pushDelay[cid].time == currentTime then
  297. pushDelay[cid].items = pushDelay[cid].items + 1
  298. elseif currentTime > pushDelay[cid].time then
  299. pushDelay[cid].time = 0
  300. pushDelay[cid].items = 0
  301. end
  302.  
  303. if pushDelay[cid].items > config.maxItemsPerSeconds then
  304. pushDelay[cid].time = currentTime + config.exhaustTime
  305. end
  306.  
  307. if pushDelay[cid].time > currentTime then
  308. self:sendCancelMessage("You can't move that item so fast.")
  309. return false
  310. end
  311.  
  312. return true
  313. end
  314.  
  315. function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  316.  
  317. -- No move items with actionID = 100
  318. if item:getActionId() == NOT_MOVEABLE_ACTION then
  319. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  320. return false
  321. end
  322.  
  323. -- No move if item count > 20 items
  324. local tile = Tile(toPosition)
  325. if tile and tile:getItemCount() > 20 then
  326. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  327. return false
  328. end
  329.  
  330. -- No move parcel very heavy
  331. if CONTAINER_WEIGHT_CHECK and ItemType(item:getId()):isContainer()
  332. and item:getWeight() > CONTAINER_WEIGHT_MAX then
  333. self:sendCancelMessage("Your cannot move this item too heavy.")
  334. return false
  335. end
  336.  
  337. -- Loot Analyser
  338. local t = Tile(fromCylinder:getPosition())
  339. local corpse = t:getTopDownItem()
  340. if corpse then
  341. local itemType = corpse:getType()
  342. if itemType:isCorpse() and toPosition.x == CONTAINER_POSITION then
  343. self:sendLootStats(item)
  344. end
  345. end
  346.  
  347. -- Cults of Tibia begin
  348. local frompos = Position(33023, 31904, 14) -- Checagem
  349. local topos = Position(33052, 31932, 15) -- Checagem
  350. if self:getPosition():isInRange(frompos, topos) and item:getId() == 26397 then
  351. local tileBoss = Tile(toPosition)
  352. if tileBoss and tileBoss:getTopCreature() and tileBoss:getTopCreature():isMonster() then
  353. if tileBoss:getTopCreature():getName():lower() == 'the remorseless corruptor' then
  354. tileBoss:getTopCreature():addHealth(-17000)
  355. item:remove(1)
  356. if tileBoss:getTopCreature():getHealth() <= 300 then
  357. tileBoss:getTopCreature():remove()
  358. local monster = Game.createMonster('the corruptor of souls', toPosition)
  359. monster:registerEvent('CheckTile')
  360. if Game.getStorageValue('healthSoul') > 0 then
  361. monster:addHealth(-(monster:getHealth() - Game.getStorageValue('healthSoul')))
  362. end
  363. Game.setStorageValue('CheckTile', os.time()+30)
  364. end
  365. elseif tileBoss:getTopCreature():getName():lower() == 'the corruptor of souls' then
  366. Game.setStorageValue('CheckTile', os.time()+30)
  367. item:remove(1)
  368. end
  369. end
  370. end
  371. -- Cults of Tibia end
  372.  
  373. -- SSA exhaust
  374. local exhaust = { }
  375. if toPosition.x == CONTAINER_POSITION and toPosition.y == CONST_SLOT_NECKLACE
  376. and item:getId() == ITEM_STONE_SKIN_AMULET then
  377. local pid = self:getId()
  378. if exhaust[pid] then
  379. self:sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED)
  380. return false
  381. else
  382. exhaust[pid] = true
  383. addEvent(function() exhaust[pid] = false end, 2000, pid)
  384. return true
  385. end
  386. end
  387.  
  388. -- Store Inbox
  389. local containerIdFrom = fromPosition.y - 64
  390. local containerFrom = self:getContainerById(containerIdFrom)
  391. if (containerFrom) then
  392. if (containerFrom:getId() == ITEM_STORE_INBOX
  393. and toPosition.y >= 1 and toPosition.y <= 11 and toPosition.y ~= 3) then
  394. self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
  395. return false
  396. end
  397. end
  398.  
  399. local containerTo = self:getContainerById(toPosition.y-64)
  400. if (containerTo) then
  401. if (containerTo:getId() == ITEM_STORE_INBOX) then
  402. self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
  403. return false
  404. end
  405. -- Gold Pouch
  406. if (containerTo:getId() == ITEM_GOLD_POUCH) then
  407. if (not (item:getId() == ITEM_CRYSTAL_COIN or item:getId() == ITEM_PLATINUM_COIN
  408. or item:getId() == ITEM_GOLD_COIN)) then
  409. self:sendCancelMessage("You can move only money to this container.")
  410. return false
  411. end
  412. end
  413. end
  414.  
  415.  
  416. -- Bath tube
  417. local toTile = Tile(toCylinder:getPosition())
  418. local topDownItem = toTile:getTopDownItem()
  419. if topDownItem and table.contains({ BATHTUB_EMPTY, BATHTUB_FILLED }, topDownItem:getId()) then
  420. return false
  421. end
  422.  
  423. -- Handle move items to the ground
  424. if toPosition.x ~= CONTAINER_POSITION then
  425. return true
  426. end
  427.  
  428. -- Check two-handed weapons
  429. if item:getTopParent() == self and bit.band(toPosition.y, 0x40) == 0 then
  430. local itemType, moveItem = ItemType(item:getId())
  431. if bit.band(itemType:getSlotPosition(), SLOTP_TWO_HAND) ~= 0 and toPosition.y == CONST_SLOT_LEFT then
  432. moveItem = self:getSlotItem(CONST_SLOT_RIGHT)
  433. elseif itemType:getWeaponType() == WEAPON_SHIELD and toPosition.y == CONST_SLOT_RIGHT then
  434. moveItem = self:getSlotItem(CONST_SLOT_LEFT)
  435. if moveItem and bit.band(ItemType(moveItem:getId()):getSlotPosition(), SLOTP_TWO_HAND) == 0 then
  436. return true
  437. end
  438. end
  439.  
  440. if moveItem then
  441. local parent = item:getParent()
  442. if parent:getSize() == parent:getCapacity() then
  443. self:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM))
  444. return false
  445. else
  446. return moveItem:moveTo(parent)
  447. end
  448. end
  449. end
  450.  
  451. -- Reward System
  452. if toPosition.x == CONTAINER_POSITION then
  453. local containerId = toPosition.y - 64
  454. local container = self:getContainerById(containerId)
  455. if not container then
  456. return true
  457. end
  458.  
  459. -- Do not let the player insert items into either the Reward Container or the Reward Chest
  460. local itemId = container:getId()
  461. if itemId == ITEM_REWARD_CONTAINER or itemId == ITEM_REWARD_CHEST then
  462. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  463. return false
  464. end
  465.  
  466. -- The player also shouldn't be able to insert items into the boss corpse
  467. local tileCorpse = Tile(container:getPosition())
  468. for index, value in ipairs(tileCorpse:getItems() or { }) do
  469. if value:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 and value:getName() == container:getName() then
  470. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  471. return false
  472. end
  473. end
  474. end
  475.  
  476. -- Do not let the player move the boss corpse.
  477. if item:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 then
  478. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  479. return false
  480. end
  481.  
  482. -- Players cannot throw items on reward chest
  483. local tileChest = Tile(toPosition)
  484. if tileChest and tileChest:getItemById(ITEM_REWARD_CHEST) then
  485. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  486. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  487. return false
  488. end
  489.  
  490. -- Players cannot throw items on teleports
  491. if blockTeleportTrashing and toPosition.x ~= CONTAINER_POSITION then
  492. local thing = Tile(toPosition):getItemByType(ITEM_TYPE_TELEPORT)
  493. if thing then
  494. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  495. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  496. return false
  497. end
  498. end
  499.  
  500. if tile and tile:getItemById(370) then -- Trapdoor
  501. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  502. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  503. return false
  504. end
  505.  
  506. if not antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder) then
  507. return false
  508. end
  509.  
  510. return true
  511. end
  512.  
  513. function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  514. end
  515.  
  516. function Player:onMoveCreature(creature, fromPosition, toPosition)
  517. return true
  518. end
  519.  
  520. local function hasPendingReport(name, targetName, reportType)
  521. local f = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "r")
  522. if f then
  523. io.close(f)
  524. return true
  525. else
  526. return false
  527. end
  528. end
  529.  
  530. function Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
  531. local name = self:getName()
  532. if hasPendingReport(name, targetName, reportType) then
  533. self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your report is being processed.")
  534. return
  535. end
  536.  
  537. local file = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "a")
  538. if not file then
  539. self:sendTextMessage(MESSAGE_EVENT_ADVANCE,
  540. "There was an error when processing your report, please contact a gamemaster.")
  541. return
  542. end
  543.  
  544. io.output(file)
  545. io.write("------------------------------\n")
  546. io.write("Reported by: " .. name .. "\n")
  547. io.write("Target: " .. targetName .. "\n")
  548. io.write("Type: " .. reportType .. "\n")
  549. io.write("Reason: " .. reportReason .. "\n")
  550. io.write("Comment: " .. comment .. "\n")
  551. if reportType ~= REPORT_TYPE_BOT then
  552. io.write("Translation: " .. translation .. "\n")
  553. end
  554. io.write("------------------------------\n")
  555. io.close(file)
  556. self:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("Thank you for reporting %s. Your report \z
  557. will be processed by %s team as soon as possible.", targetName, configManager.getString(configKeys.SERVER_NAME)))
  558. return
  559. end
  560.  
  561. function Player:onReportBug(message, position, category)
  562. if self:getAccountType() == ACCOUNT_TYPE_NORMAL then
  563. return false
  564. end
  565.  
  566. local name = self:getName()
  567. local file = io.open("data/reports/bugs/" .. name .. " report.txt", "a")
  568.  
  569. if not file then
  570. self:sendTextMessage(MESSAGE_EVENT_DEFAULT,
  571. "There was an error when processing your report, please contact a gamemaster.")
  572. return true
  573. end
  574.  
  575. io.output(file)
  576. io.write("------------------------------\n")
  577. io.write("Name: " .. name)
  578. if category == BUG_CATEGORY_MAP then
  579. io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
  580. end
  581. local playerPosition = self:getPosition()
  582. io.write(" [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n")
  583. io.write("Comment: " .. message .. "\n")
  584. io.close(file)
  585.  
  586. self:sendTextMessage(MESSAGE_EVENT_DEFAULT,
  587. "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".")
  588. return true
  589. end
  590.  
  591. function Player:onTurn(direction)
  592. if self:getGroup():getAccess() and self:getDirection() == direction then
  593. local nextPosition = self:getPosition()
  594. nextPosition:getNextPosition(direction)
  595.  
  596. self:teleportTo(nextPosition, true)
  597. end
  598.  
  599. return true
  600. end
  601.  
  602. function Player:onTradeRequest(target, item)
  603. -- No trade items with actionID = 100
  604. if item:getActionId() == NOT_MOVEABLE_ACTION then
  605. return false
  606. end
  607.  
  608. if isInArray(storeItemID,item.itemid) then
  609. return false
  610. end
  611. return true
  612. end
  613.  
  614. function Player:onTradeAccept(target, item, targetItem)
  615. self:closeImbuementWindow()
  616. target:closeImbuementWindow()
  617. return true
  618. end
  619.  
  620. local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
  621. soulCondition:setTicks(4 * 60 * 1000)
  622. soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
  623.  
  624. local function useStamina(player)
  625. local staminaMinutes = player:getStamina()
  626. if staminaMinutes == 0 then
  627. return
  628. end
  629.  
  630. local playerId = player:getId()
  631. local currentTime = os.time()
  632. local timePassed = currentTime - nextUseStaminaTime[playerId]
  633. if timePassed <= 0 then
  634. return
  635. end
  636.  
  637. if timePassed > 60 then
  638. if staminaMinutes > 2 then
  639. staminaMinutes = staminaMinutes - 2
  640. else
  641. staminaMinutes = 0
  642. end
  643. nextUseStaminaTime[playerId] = currentTime + 120
  644. else
  645. staminaMinutes = staminaMinutes - 1
  646. nextUseStaminaTime[playerId] = currentTime + 60
  647. end
  648. player:setStamina(staminaMinutes)
  649. end
  650.  
  651. local function useStaminaXp(player)
  652. local staminaMinutes = player:getExpBoostStamina() / 60
  653. if staminaMinutes == 0 then
  654. return
  655. end
  656.  
  657. local playerId = player:getId()
  658. local currentTime = os.time()
  659. local timePassed = currentTime - nextUseXpStamina[playerId]
  660. if timePassed <= 0 then
  661. return
  662. end
  663.  
  664. if timePassed > 60 then
  665. if staminaMinutes > 2 then
  666. staminaMinutes = staminaMinutes - 2
  667. else
  668. staminaMinutes = 0
  669. end
  670. nextUseXpStamina[playerId] = currentTime + 120
  671. else
  672. staminaMinutes = staminaMinutes - 1
  673. nextUseXpStamina[playerId] = currentTime + 60
  674. end
  675. player:setExpBoostStamina(staminaMinutes * 60)
  676. end
  677.  
  678. function Player:onGainExperience(source, exp, rawExp)
  679. if not source or source:isPlayer() then
  680. return exp
  681. end
  682.  
  683. -- Soul regeneration
  684. local vocation = self:getVocation()
  685. if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
  686. soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
  687. self:addCondition(soulCondition)
  688. end
  689.  
  690. -- Experience Stage Multiplier
  691. local expStage = getRateFromTable(experienceStages, self:getLevel(), configManager.getNumber(configKeys.RATE_EXP))
  692. exp = exp * expStage
  693. baseExp = rawExp * expStage
  694. if Game.getStorageValue(GlobalStorage.XpDisplayMode) > 0 then
  695. displayRate = expStage
  696. else
  697. displayRate = 1
  698. end
  699.  
  700. if self:getStorageValue(298370) >= os.time() then
  701. exp = exp * 2
  702. end
  703.  
  704. -- Client 12 Bonus Experience
  705. local clientVersion = self:getClient().version
  706. if clientVersion >= 1220 then
  707. exp = exp * 1.1
  708. end
  709.  
  710.  
  711. -- Prey Bonus
  712. for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
  713. if (self:getPreyCurrentMonster(slot) == source:getName()
  714. and self:getPreyBonusType(slot) == CONST_BONUS_XP_BONUS) then
  715. exp = exp + math.floor(exp * (self:getPreyBonusValue(slot) / 100))
  716. break
  717. end
  718. if (self:getPreyTimeLeft(slot) / 60) > 0 then
  719. preyTimeLeft(self, slot) -- slot consumption, outside of the mosnter check
  720. end
  721. end
  722.  
  723. -- Store Bonus
  724. useStaminaXp(self) -- Use store boost stamina
  725.  
  726. local Boost = self:getExpBoostStamina()
  727. local stillHasBoost = Boost > 0
  728. local storeXpBoostAmount = stillHasBoost and self:getStoreXpBoost() or 0
  729.  
  730. self:setStoreXpBoost(storeXpBoostAmount)
  731.  
  732. if (storeXpBoostAmount > 0) then
  733. exp = exp + (baseExp * (storeXpBoostAmount/100)) -- Exp Boost
  734. end
  735.  
  736. -- Stamina Bonus
  737. if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
  738. useStamina(self)
  739. local staminaMinutes = self:getStamina()
  740. if staminaMinutes > 2400 and self:isPremium() then
  741. exp = exp * 1.5
  742. self:setStaminaXpBoost(150)
  743. elseif staminaMinutes <= 840 then
  744. exp = exp * 0.5 --TODO destroy loot of people with 840- stamina
  745. self:setStaminaXpBoost(50)
  746. else
  747. self:setStaminaXpBoost(100)
  748. end
  749. end
  750.  
  751. -- Boosted creature
  752. if source:getName():lower() == BoostedCreature.name:lower() then
  753. exp = exp * 2
  754. end
  755.  
  756. self:setBaseXpGain(displayRate * 100)
  757. return exp
  758. end
  759.  
  760. function Player:onLoseExperience(exp)
  761. return exp
  762. end
  763.  
  764. SkillsTable = {
  765. [0] = { --[[ SKILL_FIST ]]
  766. stage = {
  767. [{0, 30}] = 50,
  768. [{31, 50}] = 35,
  769. [{51, 70}] = 20,
  770. [{71, 80}] = 15,
  771. [{81, 90}] = 10,
  772. [{91, 110}] = 5,
  773. [{111, 300}] = 2
  774. },
  775. rate = configKeys.RATE_SKILL
  776. },
  777. [1] = { --[[ SKILL_CLUB ]]
  778. stage = {
  779. [{0, 30}] = 50,
  780. [{31, 50}] = 35,
  781. [{51, 70}] = 20,
  782. [{71, 80}] = 15,
  783. [{81, 90}] = 10,
  784. [{91, 110}] = 5,
  785. [{111, 300}] = 2
  786. },
  787. rate = configKeys.RATE_SKILL
  788. },
  789. [2] = { --[[ SKILL_SWORD ]]
  790. stage = {
  791. [{0, 30}] = 50,
  792. [{31, 50}] = 35,
  793. [{51, 70}] = 20,
  794. [{71, 80}] = 15,
  795. [{81, 90}] = 10,
  796. [{91, 110}] = 5,
  797. [{111, 300}] = 2
  798. },
  799. rate = configKeys.RATE_SKILL
  800. },
  801. [3] = { --[[ SKILL_AXE ]]
  802. stage = {
  803. [{0, 30}] = 50,
  804. [{31, 50}] = 35,
  805. [{51, 70}] = 20,
  806. [{71, 80}] = 15,
  807. [{81, 90}] = 10,
  808. [{91, 110}] = 5,
  809. [{111, 300}] = 2
  810. },
  811. rate = configKeys.RATE_SKILL
  812. },
  813. [4] = { --[[ SKILL_DISTANCE ]]
  814. stage = {
  815. [{0, 30}] = 50,
  816. [{31, 50}] = 35,
  817. [{51, 70}] = 20,
  818. [{71, 80}] = 15,
  819. [{81, 90}] = 10,
  820. [{91, 110}] = 5,
  821. [{111, 300}] = 2
  822. },
  823. rate = configKeys.RATE_SKILL
  824. },
  825. [5] = { --[[ SKILL_SHIELD ]]
  826. stage = {
  827. [{0, 30}] = 50,
  828. [{31, 50}] = 30,
  829. [{51, 70}] = 20,
  830. [{71, 90}] = 10,
  831. [{91, 110}] = 5,
  832. [{111, 300}] = 2
  833. },
  834. rate = configKeys.RATE_SKILL
  835. },
  836. [6] = { --[[ SKILL_FISHING ]]
  837. stage = {
  838. [{0, 20}] = 40,
  839. [{21, 40}] = 30,
  840. [{41, 60}] = 20,
  841. [{61, 80}] = 10,
  842. [{81, 100}] = 5,
  843. [{101, 300}] = 2
  844. },
  845. rate = configKeys.RATE_SKILL
  846. },
  847. [7] = { --[[ SKILL_MAGLEVEL ]]
  848. stage = {
  849. [{0, 25}] = 13,
  850. [{26, 50}] = 10,
  851. [{51, 70}] = 6,
  852. [{71, 80}] = 5,
  853. [{81, 90}] = 4,
  854. [{91, 100}] = 3,
  855. [{101, 300}] = 2
  856. },
  857. rate = configKeys.RATE_MAGIC
  858. }
  859. }
  860.  
  861. function getSkillsRate(level, stages)
  862. if stages then
  863. for sLevel, multiplier in pairs(stages) do
  864. if level >= sLevel[1] and level <= sLevel[2] then
  865. return multiplier
  866. end
  867. end
  868. end
  869. return 1
  870. end
  871.  
  872. function Player:onGainSkillTries(skill, tries)
  873. if APPLY_SKILL_MULTIPLIER == false then
  874. return tries
  875. end
  876. local skills = SkillsTable[skill]
  877. if skills then
  878. if skill == SKILL_MAGLEVEL then
  879. return tries * getSkillsRate(self:getMagicLevel(), skills.stage)
  880. end
  881. return tries * getSkillsRate(self:getSkillLevel(skill), skills.stage)
  882. end
  883. return tries
  884. end
  885.  
  886. function Player:onRemoveCount(item)
  887. self:sendWaste(item:getId())
  888. end
  889.  
  890. function Player:onRequestQuestLog()
  891. self:sendQuestLog()
  892. end
  893.  
  894. function Player:onRequestQuestLine(questId)
  895. self:sendQuestLine(questId)
  896. end
  897.  
  898. function Player:onStorageUpdate(key, value, oldValue, currentFrameTime)
  899. self:updateStorage(key, value, oldValue, currentFrameTime)
  900. end
  901.  
  902. function Player:canBeAppliedImbuement(imbuement, item)
  903. local categories = {}
  904. local slots = ItemType(item:getId()):getImbuingSlots()
  905. if slots > 0 then
  906. for slot = 0, slots - 1 do
  907. local duration = item:getImbuementDuration(slot)
  908. if duration > 0 then
  909. local imbue = item:getImbuement(slot)
  910. local catid = imbue:getCategory().id
  911. table.insert(categories, catid)
  912. end
  913. end
  914. end
  915.  
  916. if isInArray(categories, imbuement:getCategory().id) then
  917. return false
  918. end
  919.  
  920. if imbuement:isPremium() and self:getPremiumDays() < 1 then
  921. return false
  922. end
  923.  
  924. if self:getStorageValue(Storage.ForgottenKnowledge.Tomes) > 0 then
  925. imbuable = true
  926. else
  927. return false
  928. end
  929.  
  930. if not self:canImbueItem(imbuement, item) then
  931. return false
  932. end
  933.  
  934. return true
  935. end
  936.  
  937. function Player:onApplyImbuement(imbuement, item, slot, protectionCharm)
  938. for _, pid in pairs(imbuement:getItems()) do
  939. if self:getItemCount(pid.itemid) < pid.count then
  940. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You don't have all necessary items.")
  941. return false
  942. end
  943. end
  944.  
  945. if item:getImbuementDuration(slot) > 0 then
  946. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ERROR, "An error ocurred, please reopen imbuement window.")
  947. return false
  948. end
  949. local base = imbuement:getBase()
  950. local price = base.price + (protectionCharm and base.protection or 0)
  951.  
  952. local chance = protectionCharm and 100 or base.percent
  953. if math.random(100) > chance then -- failed attempt
  954. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "Oh no!\n\nThe imbuement has failed. You have lost the astral sources and gold you needed for the imbuement.\n\nNext time use a protection charm to better your chances.")
  955. -- Removing items
  956. for _, pid in pairs(imbuement:getItems()) do
  957. self:removeItem(pid.itemid, pid.count)
  958. end
  959. -- Removing money
  960. self:removeMoneyNpc(price)
  961. -- Refreshing shrine window
  962. local nitem = Item(item.uid)
  963. self:sendImbuementPanel(nitem)
  964. return false
  965. end
  966.  
  967. -- Removing items
  968. for _, pid in pairs(imbuement:getItems()) do
  969. if not self:removeItem(pid.itemid, pid.count) then
  970. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You don't have all necessary items.")
  971. return false
  972. end
  973. end
  974.  
  975. if not self:removeMoneyNpc(price) then
  976. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You don't have enough money " ..price.. " gps.")
  977. return false
  978. end
  979.  
  980. if not item:addImbuement(slot, imbuement:getId()) then
  981. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "Item failed to apply imbuement.")
  982. return false
  983. end
  984.  
  985. -- Update item
  986. local nitem = Item(item.uid)
  987. self:sendImbuementPanel(nitem)
  988. return true
  989. end
  990.  
  991. function Player:clearImbuement(item, slot)
  992. local slots = ItemType(item:getId()):getImbuingSlots()
  993. if slots < slot then
  994. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR, "Sorry, not possible.")
  995. return false
  996. end
  997.  
  998. if item:getTopParent() ~= self or item:getParent() == self then
  999. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  1000. "An error occurred while applying the clearing charm to the item.")
  1001. return false
  1002. end
  1003.  
  1004. -- slot is not used
  1005. local info = item:getImbuementDuration(slot)
  1006. if info == 0 then
  1007. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  1008. "An error occurred while applying the clearing charm to the item.")
  1009. return false
  1010. end
  1011.  
  1012. local imbuement = item:getImbuement(slot)
  1013. if not self:removeMoneyNpc(imbuement:getBase().removecust) then
  1014. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  1015. "You don't have enough money " ..imbuement:getBase().removecust.. " gps.")
  1016. return false
  1017. end
  1018.  
  1019. if not item:cleanImbuement(slot) then
  1020. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  1021. "An error occurred while applying the clearing charm to the item.")
  1022. return false
  1023. end
  1024.  
  1025. -- Update item
  1026. local nitem = Item(item.uid)
  1027. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_SUCCESS,
  1028. "Congratulations! You have successfully applied the clearing charm to your item.");
  1029. self:sendImbuementPanel(nitem)
  1030.  
  1031. return true
  1032. end
  1033.  
  1034. function Player:onCombat(target, item, primaryDamage, primaryType, secondaryDamage, secondaryType)
  1035. if not item or not target then
  1036. return primaryDamage, primaryType, secondaryDamage, secondaryType
  1037. end
  1038.  
  1039. local slots = ItemType(item:getId()):getImbuingSlots()
  1040. if slots > 0 then
  1041. for i = 0, slots - 1 do
  1042. local imbuement = item:getImbuement(i)
  1043. if imbuement then
  1044. local percent = imbuement:getElementDamage()
  1045. local totalDmg = primaryDamage --store it for damage adjustment
  1046. if percent and percent > 0 then
  1047. if primaryDamage ~= 0 then
  1048. local factor = percent / 100
  1049. secondaryType = imbuement:getCombatType()
  1050. primaryDamage = totalDmg * (1 - factor)
  1051. secondaryDamage = totalDmg * (factor)
  1052. end
  1053. end
  1054. end
  1055. end
  1056. end
  1057.  
  1058. return primaryDamage, primaryType, secondaryDamage, secondaryType
  1059. end
  1060.  
Add Comment
Please, Sign In to add comment