Guest User

Untitled

a guest
May 14th, 2021
23
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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({'sorcerer familiar','knight familiar','druid familiar','paladin familiar'},
  165. thing:getName():lower()) then
  166. description = description..' (Master: ' .. master:getName() .. '). \z
  167. It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
  168. end
  169. end
  170. end
  171.  
  172. if self:getGroup():getAccess() then
  173. if thing:isItem() then
  174. description = string.format("%s\nItem ID: %d", description, thing:getId())
  175.  
  176. local actionId = thing:getActionId()
  177. if actionId ~= 0 then
  178. description = string.format("%s, Action ID: %d", description, actionId)
  179. end
  180.  
  181. local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_UNIQUEID)
  182. if uniqueId > 0 and uniqueId < 65536 then
  183. description = string.format("%s, Unique ID: %d", description, uniqueId)
  184. end
  185.  
  186. local itemType = thing:getType()
  187.  
  188. local transformEquipId = itemType:getTransformEquipId()
  189. local transformDeEquipId = itemType:getTransformDeEquipId()
  190. if transformEquipId ~= 0 then
  191. description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
  192. elseif transformDeEquipId ~= 0 then
  193. description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
  194. end
  195.  
  196. local decayId = itemType:getDecayId()
  197. if decayId ~= -1 then
  198. description = string.format("%s\nDecays to: %d", description, decayId)
  199. end
  200.  
  201. local clientId = itemType:getClientId()
  202. if clientId then
  203. description = string.format("%s\nClient ID: %d", description, clientId)
  204. end
  205.  
  206. elseif thing:isCreature() then
  207. local str = "%s\nHealth: %d / %d"
  208. if thing:isPlayer() and thing:getMaxMana() > 0 then
  209. str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
  210. end
  211. description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
  212. end
  213.  
  214. description = string.format(
  215. "%s\nPosition: %d, %d, %d",
  216. description, position.x, position.y, position.z
  217. )
  218.  
  219. if thing:isCreature() then
  220. if thing:isPlayer() then
  221. description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp()))
  222. end
  223. end
  224. end
  225. self:sendTextMessage(MESSAGE_LOOK, description)
  226. end
  227.  
  228. function Player:onLookInBattleList(creature, distance)
  229. local description = "You see " .. creature:getDescription(distance)
  230. if creature:isMonster() then
  231. local master = creature:getMaster()
  232. local summons = {'sorcerer familiar','knight familiar','druid familiar','paladin familiar'}
  233. if master and table.contains(summons, creature:getName():lower()) then
  234. description = description..' (Master: ' .. master:getName() .. '). \z
  235. It will disappear in ' .. getTimeinWords(master:getStorageValue(Storage.PetSummon) - os.time())
  236. end
  237. end
  238. if self:getGroup():getAccess() then
  239. local str = "%s\nHealth: %d / %d"
  240. if creature:isPlayer() and creature:getMaxMana() > 0 then
  241. str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
  242. end
  243. description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
  244.  
  245. local position = creature:getPosition()
  246. description = string.format(
  247. "%s\nPosition: %d, %d, %d",
  248. description, position.x, position.y, position.z
  249.  
  250. )
  251.  
  252. if creature:isPlayer() then
  253. description = string.format("%s\nIP: %s", description, Game.convertIpToString(creature:getIp()))
  254. end
  255. end
  256. self:sendTextMessage(MESSAGE_LOOK, description)
  257. end
  258.  
  259. function Player:onLookInTrade(partner, item, distance)
  260. self:sendTextMessage(MESSAGE_LOOK, "You see " .. item:getDescription(distance))
  261. end
  262.  
  263. function Player:onLookInShop(itemType, count)
  264. return true
  265. end
  266.  
  267. local config = {
  268. maxItemsPerSeconds = 1,
  269. exhaustTime = 2000,
  270. }
  271.  
  272. if not pushDelay then
  273. pushDelay = { }
  274. end
  275.  
  276. local function antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  277. if toPosition.x == CONTAINER_POSITION then
  278. return true
  279. end
  280.  
  281. local tile = Tile(toPosition)
  282. if not tile then
  283. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  284. return false
  285. end
  286.  
  287. local cid = self:getId()
  288. if not pushDelay[cid] then
  289. pushDelay[cid] = {items = 0, time = 0}
  290. end
  291.  
  292. pushDelay[cid].items = pushDelay[cid].items + 1
  293.  
  294. local currentTime = os.mtime()
  295. if pushDelay[cid].time == 0 then
  296. pushDelay[cid].time = currentTime
  297. elseif pushDelay[cid].time == currentTime then
  298. pushDelay[cid].items = pushDelay[cid].items + 1
  299. elseif currentTime > pushDelay[cid].time then
  300. pushDelay[cid].time = 0
  301. pushDelay[cid].items = 0
  302. end
  303.  
  304. if pushDelay[cid].items > config.maxItemsPerSeconds then
  305. pushDelay[cid].time = currentTime + config.exhaustTime
  306. end
  307.  
  308. if pushDelay[cid].time > currentTime then
  309. self:sendCancelMessage("You can't move that item so fast.")
  310. return false
  311. end
  312.  
  313. return true
  314. end
  315.  
  316. function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  317.  
  318. -- No move items with actionID = 100
  319. if item:getActionId() == NOT_MOVEABLE_ACTION then
  320. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  321. return false
  322. end
  323.  
  324. -- No move if item count > 20 items
  325. local tile = Tile(toPosition)
  326. if tile and tile:getItemCount() > 20 then
  327. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  328. return false
  329. end
  330.  
  331. -- No move parcel very heavy
  332. if CONTAINER_WEIGHT_CHECK and ItemType(item:getId()):isContainer()
  333. and item:getWeight() > CONTAINER_WEIGHT_MAX then
  334. self:sendCancelMessage("Your cannot move this item too heavy.")
  335. return false
  336. end
  337.  
  338. -- Cults of Tibia begin
  339. local frompos = Position(33023, 31904, 14) -- Checagem
  340. local topos = Position(33052, 31932, 15) -- Checagem
  341. if self:getPosition():isInRange(frompos, topos) and item:getId() == 26397 then
  342. local tileBoss = Tile(toPosition)
  343. if tileBoss and tileBoss:getTopCreature() and tileBoss:getTopCreature():isMonster() then
  344. if tileBoss:getTopCreature():getName():lower() == 'the remorseless corruptor' then
  345. tileBoss:getTopCreature():addHealth(-17000)
  346. item:remove(1)
  347. if tileBoss:getTopCreature():getHealth() <= 300 then
  348. tileBoss:getTopCreature():remove()
  349. local monster = Game.createMonster('the corruptor of souls', toPosition)
  350. monster:registerEvent('CheckTile')
  351. if Game.getStorageValue('healthSoul') > 0 then
  352. monster:addHealth(-(monster:getHealth() - Game.getStorageValue('healthSoul')))
  353. end
  354. Game.setStorageValue('CheckTile', os.time()+30)
  355. end
  356. elseif tileBoss:getTopCreature():getName():lower() == 'the corruptor of souls' then
  357. Game.setStorageValue('CheckTile', os.time()+30)
  358. item:remove(1)
  359. end
  360. end
  361. end
  362. -- Cults of Tibia end
  363.  
  364. -- SSA exhaust
  365. local exhaust = {20000}
  366. if toPosition.x == CONTAINER_POSITION and toPosition.y == CONST_SLOT_NECKLACE
  367. and item:getId() == ITEM_STONE_SKIN_AMULET then
  368. local pid = self:getId()
  369. if exhaust[pid] then
  370. self:sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED)
  371. return false
  372. else
  373. exhaust[pid] = true
  374. addEvent(function() exhaust[pid] = true end, 20000, pid)
  375. return true
  376. end
  377. end
  378.  
  379. -- Store Inbox
  380. local containerIdFrom = fromPosition.y - 64
  381. local containerFrom = self:getContainerById(containerIdFrom)
  382. if (containerFrom) then
  383. if (containerFrom:getId() == ITEM_STORE_INBOX
  384. and toPosition.y >= 1 and toPosition.y <= 11 and toPosition.y ~= 3) then
  385. self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
  386. return false
  387. end
  388. end
  389.  
  390. local containerTo = self:getContainerById(toPosition.y-64)
  391. if (containerTo) then
  392. if (containerTo:getId() == ITEM_STORE_INBOX) or (containerTo:getParent():isContainer() and containerTo:getParent():getId() == ITEM_STORE_INBOX and containerTo:getId() ~= ITEM_GOLD_POUCH) then
  393. self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
  394. return false
  395. end
  396. -- Gold Pouch
  397. if (containerTo:getId() == ITEM_GOLD_POUCH) then
  398. if (not (item:getId() == ITEM_CRYSTAL_COIN or item:getId() == ITEM_PLATINUM_COIN
  399. or item:getId() == ITEM_GOLD_COIN)) then
  400. self:sendCancelMessage("You can move only money to this container.")
  401. return false
  402. end
  403. end
  404. end
  405.  
  406.  
  407. -- Bath tube
  408. local toTile = Tile(toCylinder:getPosition())
  409. local topDownItem = toTile:getTopDownItem()
  410. if topDownItem and table.contains({ BATHTUB_EMPTY, BATHTUB_FILLED }, topDownItem:getId()) then
  411. return false
  412. end
  413.  
  414. -- Handle move items to the ground
  415. if toPosition.x ~= CONTAINER_POSITION then
  416. return true
  417. end
  418.  
  419. -- Check two-handed weapons
  420. if item:getTopParent() == self and bit.band(toPosition.y, 0x40) == 0 then
  421. local itemType, moveItem = ItemType(item:getId())
  422. if bit.band(itemType:getSlotPosition(), SLOTP_TWO_HAND) ~= 0 and toPosition.y == CONST_SLOT_LEFT then
  423. moveItem = self:getSlotItem(CONST_SLOT_RIGHT)
  424. if moveItem and itemType:getWeaponType() == WEAPON_DISTANCE and ItemType(moveItem:getId()):getWeaponType() == WEAPON_QUIVER then
  425. return true
  426. end
  427. elseif itemType:getWeaponType() == WEAPON_SHIELD and toPosition.y == CONST_SLOT_RIGHT then
  428. moveItem = self:getSlotItem(CONST_SLOT_LEFT)
  429. if moveItem and bit.band(ItemType(moveItem:getId()):getSlotPosition(), SLOTP_TWO_HAND) == 0 then
  430. return true
  431. end
  432. end
  433.  
  434. if moveItem then
  435. local parent = item:getParent()
  436. if parent:getSize() == parent:getCapacity() then
  437. self:sendTextMessage(MESSAGE_FAILURE, Game.getReturnMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM))
  438. return false
  439. else
  440. return moveItem:moveTo(parent)
  441. end
  442. end
  443. end
  444.  
  445. -- Reward System
  446. if toPosition.x == CONTAINER_POSITION then
  447. local containerId = toPosition.y - 64
  448. local container = self:getContainerById(containerId)
  449. if not container then
  450. return true
  451. end
  452.  
  453. -- Do not let the player insert items into either the Reward Container or the Reward Chest
  454. local itemId = container:getId()
  455. if itemId == ITEM_REWARD_CONTAINER or itemId == ITEM_REWARD_CHEST then
  456. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  457. return false
  458. end
  459.  
  460. -- The player also shouldn't be able to insert items into the boss corpse
  461. local tileCorpse = Tile(container:getPosition())
  462. for index, value in ipairs(tileCorpse:getItems() or { }) do
  463. if value:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 and value:getName() == container:getName() then
  464. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  465. return false
  466. end
  467. end
  468. end
  469.  
  470. -- Do not let the player move the boss corpse.
  471. if item:getAttribute(ITEM_ATTRIBUTE_CORPSEOWNER) == 2^31 - 1 then
  472. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  473. return false
  474. end
  475.  
  476. -- Players cannot throw items on reward chest
  477. local tileChest = Tile(toPosition)
  478. if tileChest and tileChest:getItemById(ITEM_REWARD_CHEST) then
  479. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  480. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  481. return false
  482. end
  483.  
  484. -- Players cannot throw items on teleports
  485. if blockTeleportTrashing and toPosition.x ~= CONTAINER_POSITION then
  486. local thing = Tile(toPosition):getItemByType(ITEM_TYPE_TELEPORT)
  487. if thing then
  488. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  489. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  490. return false
  491. end
  492. end
  493.  
  494. if tile and tile:getItemById(370) then -- Trapdoor
  495. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  496. self:getPosition():sendMagicEffect(CONST_ME_POFF)
  497. return false
  498. end
  499.  
  500. if not antiPush(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder) then
  501. return false
  502. end
  503.  
  504. return true
  505. end
  506.  
  507. function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
  508. end
  509.  
  510. function Player:onMoveCreature(creature, fromPosition, toPosition)
  511. if creature:isPlayer() and creature:getStorageValue(Storage.isTraining) == 1 and self:getGroup():hasFlag(PlayerFlag_CanPushAllCreatures) == false then
  512. self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
  513. return false
  514. end
  515. return true
  516. end
  517.  
  518. local function hasPendingReport(name, targetName, reportType)
  519. local f = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "r")
  520. if f then
  521. io.close(f)
  522. return true
  523. else
  524. return false
  525. end
  526. end
  527.  
  528. function Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
  529. local name = self:getName()
  530. if hasPendingReport(name, targetName, reportType) then
  531. self:sendTextMessage(MESSAGE_REPORT, "Your report is being processed.")
  532. return
  533. end
  534.  
  535. local file = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "a")
  536. if not file then
  537. self:sendTextMessage(MESSAGE_REPORT,
  538. "There was an error when processing your report, please contact a gamemaster.")
  539. return
  540. end
  541.  
  542. io.output(file)
  543. io.write("------------------------------\n")
  544. io.write("Reported by: " .. name .. "\n")
  545. io.write("Target: " .. targetName .. "\n")
  546. io.write("Type: " .. reportType .. "\n")
  547. io.write("Reason: " .. reportReason .. "\n")
  548. io.write("Comment: " .. comment .. "\n")
  549. if reportType ~= REPORT_TYPE_BOT then
  550. io.write("Translation: " .. translation .. "\n")
  551. end
  552. io.write("------------------------------\n")
  553. io.close(file)
  554. self:sendTextMessage(MESSAGE_REPORT, string.format("Thank you for reporting %s. Your report \z
  555. will be processed by %s team as soon as possible.", targetName, configManager.getString(configKeys.SERVER_NAME)))
  556. return
  557. end
  558.  
  559. function Player:onReportBug(message, position, category)
  560. if self:getAccountType() == ACCOUNT_TYPE_NORMAL then
  561. return false
  562. end
  563.  
  564. local name = self:getName()
  565. local file = io.open("data/reports/bugs/" .. name .. " report.txt", "a")
  566.  
  567. if not file then
  568. self:sendTextMessage(MESSAGE_REPORT,
  569. "There was an error when processing your report, please contact a gamemaster.")
  570. return true
  571. end
  572.  
  573. io.output(file)
  574. io.write("------------------------------\n")
  575. io.write("Name: " .. name)
  576. if category == BUG_CATEGORY_MAP then
  577. io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
  578. end
  579. local playerPosition = self:getPosition()
  580. io.write(" [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n")
  581. io.write("Comment: " .. message .. "\n")
  582. io.close(file)
  583.  
  584. self:sendTextMessage(MESSAGE_REPORT,
  585. "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".")
  586. return true
  587. end
  588.  
  589. function Player:onTurn(direction)
  590. if self:getGroup():getAccess() and self:getDirection() == direction then
  591. local nextPosition = self:getPosition()
  592. nextPosition:getNextPosition(direction)
  593.  
  594. self:teleportTo(nextPosition, true)
  595. end
  596.  
  597. return true
  598. end
  599.  
  600. function Player:onTradeRequest(target, item)
  601. -- No trade items with actionID = 100
  602. if item:getActionId() == NOT_MOVEABLE_ACTION then
  603. return false
  604. end
  605.  
  606. if isInArray(storeItemID,item.itemid) then
  607. return false
  608. end
  609. return true
  610. end
  611.  
  612. function Player:onTradeAccept(target, item, targetItem)
  613. self:closeImbuementWindow()
  614. target:closeImbuementWindow()
  615. return true
  616. end
  617.  
  618. local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
  619. soulCondition:setTicks(4 * 60 * 1000)
  620. soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
  621.  
  622. local function useStamina(player)
  623. local staminaMinutes = player:getStamina()
  624. if staminaMinutes == 0 then
  625. return
  626. end
  627.  
  628. local playerId = player:getId()
  629. local currentTime = os.time()
  630. local timePassed = currentTime - nextUseStaminaTime[playerId]
  631. if timePassed <= 0 then
  632. return
  633. end
  634.  
  635. if timePassed > 60 then
  636. if staminaMinutes > 2 then
  637. staminaMinutes = staminaMinutes - 2
  638. else
  639. staminaMinutes = 0
  640. end
  641. nextUseStaminaTime[playerId] = currentTime + 120
  642. else
  643. staminaMinutes = staminaMinutes - 1
  644. nextUseStaminaTime[playerId] = currentTime + 60
  645. end
  646. player:setStamina(staminaMinutes)
  647. end
  648.  
  649. local function useStaminaXp(player)
  650. local staminaMinutes = player:getExpBoostStamina() / 60
  651. if staminaMinutes == 0 then
  652. return
  653. end
  654.  
  655. local playerId = player:getId()
  656. local currentTime = os.time()
  657. local timePassed = currentTime - nextUseXpStamina[playerId]
  658. if timePassed <= 0 then
  659. return
  660. end
  661.  
  662. if timePassed > 60 then
  663. if staminaMinutes > 2 then
  664. staminaMinutes = staminaMinutes - 2
  665. else
  666. staminaMinutes = 0
  667. end
  668. nextUseXpStamina[playerId] = currentTime + 120
  669. else
  670. staminaMinutes = staminaMinutes - 1
  671. nextUseXpStamina[playerId] = currentTime + 60
  672. end
  673. player:setExpBoostStamina(staminaMinutes * 60)
  674. end
  675.  
  676. function Player:onGainExperience(source, exp, rawExp)
  677. if not source or source:isPlayer() then
  678. return exp
  679. end
  680.  
  681. -- Client 12 Bonus Experience
  682. local clientVersion = self:getClient().version
  683. if clientVersion >= 1200 then
  684. exp = exp * 1.3
  685. end
  686.  
  687. -- Soul regeneration
  688. local vocation = self:getVocation()
  689. if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
  690. soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
  691. self:addCondition(soulCondition)
  692. end
  693.  
  694. -- Experience Stage Multiplier
  695. local expStage = getRateFromTable(experienceStages, self:getLevel(), configManager.getNumber(configKeys.RATE_EXP))
  696. exp = exp * expStage
  697. baseExp = rawExp * expStage
  698. if Game.getStorageValue(GlobalStorage.XpDisplayMode) > 0 then
  699. displayRate = expStage
  700. else
  701. displayRate = 1
  702. end
  703.  
  704. -- Prey Bonus
  705. for slot = CONST_PREY_SLOT_FIRST, CONST_PREY_SLOT_THIRD do
  706. if (self:getPreyCurrentMonster(slot) == source:getName()
  707. and self:getPreyBonusType(slot) == CONST_BONUS_XP_BONUS) then
  708. exp = exp + math.floor(exp * (self:getPreyBonusValue(slot) / 100))
  709. break
  710. end
  711. if (self:getPreyTimeLeft(slot) / 60) > 0 then
  712. preyTimeLeft(self, slot) -- slot consumption, outside of the mosnter check
  713. end
  714. end
  715.  
  716. -- Store Bonus
  717. useStaminaXp(self) -- Use store boost stamina
  718.  
  719. local Boost = self:getExpBoostStamina()
  720. local stillHasBoost = Boost > 0
  721. local storeXpBoostAmount = stillHasBoost and self:getStoreXpBoost() or 0
  722.  
  723. self:setStoreXpBoost(storeXpBoostAmount)
  724.  
  725. if (storeXpBoostAmount > 0) then
  726. exp = exp + (baseExp * (storeXpBoostAmount/100)) -- Exp Boost
  727. end
  728.  
  729. -- Stamina Bonus
  730. if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
  731. useStamina(self)
  732. local staminaMinutes = self:getStamina()
  733. if staminaMinutes > 2340 and self:isPremium() then
  734. exp = exp * 1.5
  735. self:setStaminaXpBoost(150)
  736. elseif staminaMinutes <= 840 then
  737. exp = exp * 0.5 --TODO destroy loot of people with 840- stamina
  738. self:setStaminaXpBoost(50)
  739. else
  740. self:setStaminaXpBoost(100)
  741. end
  742. end
  743.  
  744. -- Boosted creature
  745. if source:getName():lower() == (Game.getBoostedCreature()):lower() then
  746. exp = exp * 2
  747. end
  748.  
  749. -- Event scheduler
  750. if SCHEDULE_EXP_RATE ~= 100 then
  751. exp = (exp * SCHEDULE_EXP_RATE)/100
  752. end
  753. self:setBaseXpGain(displayRate * 100)
  754. return exp
  755. end
  756.  
  757. function Player:onLoseExperience(exp)
  758. return exp
  759. end
  760.  
  761. function Player:onGainSkillTries(skill, tries)
  762. -- Dawnport skills limit
  763. if isSkillGrowthLimited(self, skill) then
  764. return 0
  765. end
  766. if APPLY_SKILL_MULTIPLIER == false then
  767. return tries
  768. end
  769.  
  770. -- Event scheduler skill rate
  771. if SCHEDULE_SKILL_RATE ~= 100 then
  772. tries = (tries * SCHEDULE_SKILL_RATE)/100
  773. end
  774.  
  775. local skillRate = configManager.getNumber(configKeys.RATE_SKILL)
  776. local magicRate = configManager.getNumber(configKeys.RATE_MAGIC)
  777.  
  778. if(skill == SKILL_MAGLEVEL) then -- Magic getLevel
  779. return tries * getRateFromTable(magicLevelStages, self:getMagicLevel(), magicRate)
  780. end
  781.  
  782. return tries * getRateFromTable(skillsStages, self:getEffectiveSkillLevel(skill), skillRate)
  783. end
  784.  
  785. function Player:onRemoveCount(item)
  786. self:sendWaste(item:getId())
  787. end
  788.  
  789. function Player:onRequestQuestLog()
  790. self:sendQuestLog()
  791. end
  792.  
  793. function Player:onRequestQuestLine(questId)
  794. self:sendQuestLine(questId)
  795. end
  796.  
  797. function Player:onStorageUpdate(key, value, oldValue, currentFrameTime)
  798. self:updateStorage(key, value, oldValue, currentFrameTime)
  799. end
  800.  
  801. function Player:canBeAppliedImbuement(imbuement, item)
  802. local categories = {}
  803. local slots = ItemType(item:getId()):getImbuingSlots()
  804. if slots > 0 then
  805. for slot = 0, slots - 1 do
  806. local duration = item:getImbuementDuration(slot)
  807. if duration > 0 then
  808. local imbue = item:getImbuement(slot)
  809. local catid = imbue:getCategory().id
  810. table.insert(categories, catid)
  811. end
  812. end
  813. end
  814.  
  815. if isInArray(categories, imbuement:getCategory().id) then
  816. return false
  817. end
  818.  
  819. if imbuement:isPremium() and self:getPremiumDays() < 1 then
  820. return false
  821. end
  822.  
  823. if self:getStorageValue(Storage.ForgottenKnowledge.Tomes) > 0 then
  824. imbuable = true
  825. else
  826. return false
  827. end
  828.  
  829. if not self:canImbueItem(imbuement, item) then
  830. return false
  831. end
  832.  
  833. return true
  834. end
  835.  
  836. function Player:onApplyImbuement(imbuement, item, slot, protectionCharm)
  837. for slot = CONST_SLOT_HEAD, CONST_SLOT_AMMO do
  838. local slotItem = self:getSlotItem(slot)
  839. if slotItem and slotItem == item then
  840. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You can't imbue a equipped item.")
  841. self:closeImbuementWindow()
  842. return true
  843. end
  844. end
  845.  
  846. for _, pid in pairs(imbuement:getItems()) do
  847. if (self:getItemCount(pid.itemid) + self:getStashItemCount(pid.itemid)) < pid.count then
  848. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You don't have all necessary items.")
  849. return false
  850. end
  851. end
  852.  
  853. if item:getImbuementDuration(slot) > 0 then
  854. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ERROR, "An error ocurred, please reopen imbuement window.")
  855. return false
  856. end
  857. local base = imbuement:getBase()
  858. local price = base.price + (protectionCharm and base.protection or 0)
  859.  
  860. local chance = protectionCharm and 100 or base.percent
  861. if math.random(100) > chance then -- failed attempt
  862. 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.")
  863. -- Removing items
  864. for _, pid in pairs(imbuement:getItems()) do
  865. self:removeItem(pid.itemid, pid.count)
  866. end
  867. -- Removing money
  868. self:removeMoneyNpc(price)
  869. -- Refreshing shrine window
  870. local nitem = Item(item.uid)
  871. self:sendImbuementPanel(nitem)
  872. return false
  873. end
  874.  
  875. -- Removing items
  876. for _, pid in pairs(imbuement:getItems()) do
  877. local invertoryItemCount = self:getItemCount(pid.itemid)
  878. if invertoryItemCount >= pid.count then
  879. if not(self:removeItem(pid.itemid, pid.count)) then
  880. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ERROR, "An error ocurred, please reopen imbuement window.")
  881. return false
  882. end
  883. else
  884. local mathItemCount = pid.count
  885. if invertoryItemCount > 0 and self:removeItem(pid.itemid, invertoryItemCount) then
  886. mathItemCount = mathItemCount - invertoryItemCount
  887. end
  888.  
  889. if not(self:removeStashItem(pid.itemid, mathItemCount)) then
  890. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ERROR, "An error ocurred, please reopen imbuement window.")
  891. return false
  892. end
  893. end
  894. end
  895.  
  896. if not self:removeMoneyNpc(price) then
  897. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "You don't have enough money " ..price.. " gps.")
  898. return false
  899. end
  900.  
  901. if not item:addImbuement(slot, imbuement:getId()) then
  902. self:sendImbuementResult(MESSAGEDIALOG_IMBUEMENT_ROLL_FAILED, "Item failed to apply imbuement.")
  903. return false
  904. end
  905.  
  906. -- Update item
  907. local nitem = Item(item.uid)
  908. self:sendImbuementPanel(nitem)
  909. return true
  910. end
  911.  
  912. function Player:clearImbuement(item, slot)
  913. local slots = ItemType(item:getId()):getImbuingSlots()
  914. if slots < slot then
  915. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR, "Sorry, not possible.")
  916. return false
  917. end
  918.  
  919. if item:getTopParent() ~= self or item:getParent() == self then
  920. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  921. "An error occurred while applying the clearing charm to the item.")
  922. return false
  923. end
  924.  
  925. -- slot is not used
  926. local info = item:getImbuementDuration(slot)
  927. if info == 0 then
  928. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  929. "An error occurred while applying the clearing charm to the item.")
  930. return false
  931. end
  932.  
  933. local imbuement = item:getImbuement(slot)
  934. if not self:removeMoneyNpc(imbuement:getBase().removecust) then
  935. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  936. "You don't have enough money " ..imbuement:getBase().removecust.. " gps.")
  937. return false
  938. end
  939.  
  940. if not item:cleanImbuement(slot) then
  941. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_ERROR,
  942. "An error occurred while applying the clearing charm to the item.")
  943. return false
  944. end
  945.  
  946. -- Update item
  947. local nitem = Item(item.uid)
  948. self:sendImbuementResult(MESSAGEDIALOG_CLEARING_CHARM_SUCCESS,
  949. "Congratulations! You have successfully applied the clearing charm to your item.");
  950. self:sendImbuementPanel(nitem)
  951.  
  952. return true
  953. end
  954.  
  955. function Player:onCombat(target, item, primaryDamage, primaryType, secondaryDamage, secondaryType)
  956. if not item or not target then
  957. return primaryDamage, primaryType, secondaryDamage, secondaryType
  958. end
  959.  
  960. if ItemType(item:getId()):getWeaponType() == WEAPON_AMMO then
  961. if isInArray({ITEM_OLD_DIAMOND_ARROW, ITEM_DIAMOND_ARROW}, item:getId()) then
  962. return primaryDamage, primaryType, secondaryDamage, secondaryType
  963. else
  964. item = self:getSlotItem(CONST_SLOT_LEFT)
  965. end
  966. end
  967.  
  968. local slots = ItemType(item:getId()):getImbuingSlots()
  969. if slots > 0 then
  970. for i = 0, slots - 1 do
  971. local imbuement = item:getImbuement(i)
  972. if imbuement then
  973. local percent = imbuement:getElementDamage()
  974. local totalDmg = primaryDamage --store it for damage adjustment
  975. if percent and percent > 0 then
  976. if primaryDamage ~= 0 then
  977. local factor = percent / 100
  978. secondaryType = imbuement:getCombatType()
  979. primaryDamage = totalDmg * (1 - factor)
  980. secondaryDamage = totalDmg * (factor)
  981. end
  982. end
  983. end
  984. end
  985. end
  986.  
  987. return primaryDamage, primaryType, secondaryDamage, secondaryType
  988. end
  989.  
  990.  
RAW Paste Data