1function Player:onBrowseField(position)
2 return true
3end
4
5function Player:onLook(thing, position, distance)
6 if thing:isMonster() then
7 if _MONSTER_LOOT[thing:getName()] then
8 local description = "You see " .. thing:getDescription(distance)
9
10 description = description.. "\nClasse: [ " .._MONSTER_LOOT[thing:getName()][00].Type.. " ]."
11 self:sendTextMessage(MESSAGE_INFO_DESCR, description)
12 return true
13 end
14 end
15 local description = "You see " .. thing:getDescription(distance)
16 if self:getGroup():getAccess() then
17 if thing:isItem() then
18 description = string.format("%s\nItem ID: %d", description, thing:getId())
19
20 local actionId = thing:getActionId()
21 if actionId ~= 0 then
22 description = string.format("%s, Action ID: %d", description, actionId)
23 end
24
25 local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_UNIQUEID)
26 if uniqueId > 0 and uniqueId < 65536 then
27 description = string.format("%s, Unique ID: %d", description, uniqueId)
28 end
29
30 local itemType = thing:getType()
31
32 local transformEquipId = itemType:getTransformEquipId()
33 local transformDeEquipId = itemType:getTransformDeEquipId()
34 if transformEquipId ~= 0 then
35 description = string.format("%s\nTransforms to: %d (onEquip)", description, transformEquipId)
36 elseif transformDeEquipId ~= 0 then
37 description = string.format("%s\nTransforms to: %d (onDeEquip)", description, transformDeEquipId)
38 end
39
40 local decayId = itemType:getDecayId()
41 if decayId ~= -1 then
42 description = string.format("%s\nDecays to: %d", description, decayId)
43 end
44 elseif thing:isCreature() then
45 local str = "%s\nHealth: %d / %d"
46 if thing:isPlayer() and thing:getMaxMana() > 0 then
47 str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana())
48 end
49 description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
50 end
51
52 local position = thing:getPosition()
53 description = string.format(
54 "%s\nPosition: %d, %d, %d",
55 description, position.x, position.y, position.z
56 )
57
58 if thing:isCreature() then
59 if thing:isPlayer() then
60 local client = thing:getClient()
61 --description = string.format("%s\nIP: %s PING: %i FPS: %i.", description, Game.convertIpToString(thing:getIp()), client.ping, client.fps)
62 end
63 end
64 end
65 self:sendTextMessage(MESSAGE_INFO_DESCR, description)
66end
67
68function Player:onLookInBattleList(creature, distance)
69 local description = "You see " .. creature:getDescription(distance)
70 if self:getGroup():getAccess() then
71 local str = "%s\nHealth: %d / %d"
72 if creature:isPlayer() and creature:getMaxMana() > 0 then
73 str = string.format("%s, Mana: %d / %d", str, creature:getMana(), creature:getMaxMana())
74 end
75 description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
76
77 local position = creature:getPosition()
78 description = string.format(
79 "%s\nPosition: %d, %d, %d",
80 description, position.x, position.y, position.z
81 )
82
83 if creature:isPlayer() then
84 local client = thing:getClient()
85 --description = string.format("%s\nIP: %s PING: %i FPS: %i.", description, Game.convertIpToString(thing:getIp()), client.ping, client.fps)
86 end
87 end
88 self:sendTextMessage(MESSAGE_INFO_DESCR, description)
89end
90
91function Player:onLookInTrade(partner, item, distance)
92 self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
93end
94
95function Player:onLookInShop(itemType, count)
96 return true
97end
98
99function Player:onMoveItem(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
100 if item.uid > 0 then
101 self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
102 return false
103 end
104
105 if item:getAttribute("wrapid") ~= 0 then
106 local tile = Tile(toPosition)
107 if (fromPosition.x ~= CONTAINER_POSITION and toPosition.x ~= CONTAINER_POSITION) or tile and not tile:getHouse() then
108 if tile and not tile:getHouse() then
109 self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
110 return false
111 end
112 end
113 end
114
115 if toPosition.x ~= CONTAINER_POSITION then
116 return true
117 end
118
119 if item:getTopParent() == self and bit.band(toPosition.y, 0x40) == 0 then
120 local itemType, moveItem = ItemType(item:getId())
121 if bit.band(itemType:getSlotPosition(), SLOTP_TWO_HAND) ~= 0 and toPosition.y == CONST_SLOT_LEFT then
122 moveItem = self:getSlotItem(CONST_SLOT_RIGHT)
123 elseif itemType:getWeaponType() == WEAPON_SHIELD and toPosition.y == CONST_SLOT_RIGHT then
124 moveItem = self:getSlotItem(CONST_SLOT_LEFT)
125 if moveItem and bit.band(ItemType(moveItem:getId()):getSlotPosition(), SLOTP_TWO_HAND) == 0 then
126 return true
127 end
128 end
129
130 if moveItem then
131 local parent = item:getParent()
132 if parent:isContainer() and parent:getSize() == parent:getCapacity() then
133 self:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM))
134 return false
135 else
136 return moveItem:moveTo(parent)
137 end
138 end
139 end
140
141 return true
142end
143
144function Player:onItemMoved(item, count, fromPosition, toPosition, fromCylinder, toCylinder)
145end
146
147function Player:onMoveCreature(creature, fromPosition, toPosition)
148 if creature:isNpc() then
149 self:sendCancelMessage(RETURNVALUE_NOTPOSSIBLE)
150 return false
151 end
152 return true
153end
154
155local function hasPendingReport(name, targetName, reportType)
156 local f = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "r")
157 if f then
158 io.close(f)
159 return true
160 else
161 return false
162 end
163end
164
165function Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
166 local name = self:getName()
167 if hasPendingReport(name, targetName, reportType) then
168
169 return
170 end
171
172 local file = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "a")
173 if not file then
174 self:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Houve um erro em seu processo de report. Por favor, contate o administrador.")
175 return
176 end
177
178 io.output(file)
179 io.write("------------------------------\n")
180 io.write("Reportado por: " .. name .. "\n")
181 io.write("Alvo: " .. targetName .. "\n")
182 io.write("Tipo: " .. reportType .. "\n")
183 io.write("Razao: " .. reportReason .. "\n")
184 io.write("Comentario: " .. comment .. "\n")
185 if reportType ~= REPORT_TYPE_BOT then
186 io.write("Translation: " .. translation .. "\n")
187 end
188 io.write("------------------------------\n")
189 io.close(file)
190
191 return
192end
193
194function Player:onReportBug(message, position, category)
195 local DIAS_SEMANA = {
196 ["Monday"] = "Segunda";
197
198 ["Wednesday"] = "Quarta";
199 ["Thursday"] = "Quinta";
200 ["Friday"] = "Sexta";
201
202 ["Sunday"] = "Domingo";
203 }
204 local MES_NAME = {
205 [01] = "Janeiro";
206 [02] = "Fevereiro";
207
208 [04] = "Abril";
209 [05] = "Maio";
210 [06] = "Junho";
211 [07] = "Julho";
212 [08] = "Agosto";
213 [09] = "Setembro";
214 [10] = "Outubro";
215 [11] = "Novembro";
216 [12] = "Dezembro";
217 }
218
219 local name = self:getName()
220 local Mes = tonumber(os.date("%m", os.time()))
221 local Dia = tonumber(os.date("%d", os.time()))
222 local Horas = tonumber(os.date("%H", os.time()))
223 local Minutos = tonumber(os.date("%M", os.time()))
224 local HourMinutes = Horas .. ':' .. Minutos
225 local Semana = os.date('%A')
226 local file = io.open("data/reports/bugs/bugs.txt", "a")
227
228 if not file then
229 self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "Houve um erro em seu processo de report. Por favor, contate o administrador.")
230 return true
231 end
232
233 io.output(file)
234 io.write("Name: " .. name)
235 io.write("\n" ..DIAS_SEMANA[Semana].. ", " ..Dia.. " de " ..MES_NAME[Mes].. ", as " ..HourMinutes)
236 if category == BUG_CATEGORY_MAP then
237 io.write("\nMap Position: [" .. position.x .. ", " .. position.y .. ", " .. position.z .. "]")
238 end
239 local playerPosition = self:getPosition()
240 io.write("\nPosition: [" .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n\n")
241 io.write(message .. "\n")
242 io.write("------------------------------------------------\n\n")
243 io.close(file)
244
245 return true
246end
247
248function Player:onTurn(direction)
249 return true
250end
251
252function Player:onTradeRequest(target, item)
253 return true
254end
255
256function Player:onTradeAccept(target, item, targetItem)
257 return true
258end
259
260function Player:onTradeCompleted(target, item, targetItem, isSuccess)
261 return
262end
263
264local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
265soulCondition:setTicks(4 * 60 * 1000)
266soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
267
268local function useStamina(player)
269 local staminaMinutes = player:getStamina()
270 if staminaMinutes == 0 then
271 return
272 end
273
274 local playerId = player:getId()
275 local currentTime = os.time()
276 local timePassed = currentTime - nextUseStaminaTime[playerId]
277 if timePassed <= 0 then
278 return
279 end
280
281 if timePassed > 60 then
282 if staminaMinutes > 2 then
283 staminaMinutes = staminaMinutes - 2
284 else
285 staminaMinutes = 0
286 end
287 nextUseStaminaTime[playerId] = currentTime + 120
288 else
289 staminaMinutes = staminaMinutes - 1
290 nextUseStaminaTime[playerId] = currentTime + 60
291 end
292 player:setStamina(staminaMinutes)
293end
294
295function Player:onGainExperience(source, exp, rawExp)
296 if self:getStorageValue(_SYSTEM.FENDAS_DIMENSIONAL[01]) > 00 then
297 return true
298 end
299 if not source or source:isPlayer() then
300 return exp
301 end
302
303 -- Soul regeneration
304 local vocation = self:getVocation()
305 if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
306 soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
307 self:addCondition(soulCondition)
308 end
309
310 -- Apply experience stage multiplier
311 exp = exp * Game.getExperienceStage(self:getLevel())
312
313 -- Stamina modifier
314 if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
315 useStamina(self)
316
317 local staminaMinutes = self:getStamina()
318 if staminaMinutes > 2400 and self:isPremium() then
319 exp = exp * 1.5
320 elseif staminaMinutes <= 840 then
321 exp = exp * 0.5
322 end
323 end
324
325 -- Warzone EXP
326 if self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) > 0 then
327 if self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 01 then
328 exp = exp * 1.05
329 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 02 then
330 exp = exp * 1.10
331 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 03 then
332 exp = exp * 1.15
333 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 04 then
334 exp = exp * 1.20
335 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 05 then
336 exp = exp * 1.25
337 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 06 then
338 exp = exp * 1.30
339 elseif self:getStorageValue(_GLOBAL_RANDOM.WARZONE.EXP_STORAGE) == 07 then
340 exp = exp * 1.35
341 end
342 end
343
344 if Game.getStorageValue(_GLOBAL_RANDOM.EVENTOS_TABLE[00].EVENT_ID) == 07 then
345 if self:getStorageValue(_GLOBAL_RANDOM.EVENTOS_TABLE[07].EXP_BONUS) > 0 then
346 local EXP_BONUS = self:getStorageValue(_GLOBAL_RANDOM.EVENTOS_TABLE[07].EXP_BONUS) / 100
347 local NEW_EXP = exp * EXP_BONUS
348 exp = exp + NEW_EXP
349 end
350 end
351
352 if self:isPlayer() then
353 if self:getStorageValue(_SYSTEM.PENALIDADES[01]) > 0 then
354 if exp > self:getStorageValue(_SYSTEM.PENALIDADES[01]) then
355 local temp = exp - self:getStorageValue(_SYSTEM.PENALIDADES[01])
356 self:setStorageValue(_SYSTEM.PENALIDADES[01], nil)
357 self:sendCancelMessage("@Penalidade 0")
358 return temp
359 elseif exp == self:getStorageValue(_SYSTEM.PENALIDADES[01]) then
360 self:setStorageValue(_SYSTEM.PENALIDADES[01], nil)
361 self:sendCancelMessage("@Penalidade 0")
362 return 0
363 else
364 self:setStorageValue(_SYSTEM.PENALIDADES[01], (self:getStorageValue(_SYSTEM.PENALIDADES[01]) - exp))
365 self:sendCancelMessage("@Penalidade " ..self:getStorageValue(_SYSTEM.PENALIDADES[01]))
366 return 0
367 end
368 end
369 end
370
371 if self:getStorageValue(_SYSTEM.SHOP_WARZONE) == 04 then
372 exp = exp * 2
373 end
374
375 -- DESAFIO
376 if self:getStorageValue(_DESAFIOS[00].DESAFIO_ID) > 00 then
377 onPlayerDesafios(self, 05, exp)
378 end
379 self:sendCancelMessage("@Analyser#01#" ..exp)
380 return exp
381end
382
383function Player:onLoseExperience(exp)
384 return exp
385end
386
387function Player:onGainSkillTries(skill, tries)
388 if APPLY_SKILL_MULTIPLIER == false then
389 return tries
390 end
391 if skill == SKILL_MAGLEVEL then
392 return false
393 end
394
395 return tries * configManager.getNumber(configKeys.RATE_SKILL)
396end
397
398function Player:onWrapItem(item, position)
399 local topCylinder = item:getTopParent()
400 if not topCylinder then
401 return
402 end
403
404 local tile = Tile(topCylinder:getPosition())
405 if not tile then
406 return
407 end
408
409 local house = tile:getHouse()
410 if not house then
411 self:sendCancelMessage("You can only wrap and unwrap this item inside a house.")
412 return
413 end
414
415 if house ~= self:getHouse() and not string.find(house:getAccessList(SUBOWNER_LIST):lower(), "%f[%a]" .. self:getName():lower() .. "%f[%A]") then
416 self:sendCancelMessage("You cannot wrap or unwrap items from a house, which you are only guest to.")
417 return
418 end
419
420 local wrapId = item:getAttribute("wrapid")
421 if wrapId == 0 then
422 return
423 end
424
425 local oldId = item:getId()
426 item:remove(1)
427 local item = tile:addItem(wrapId)
428 if item then
429 item:setAttribute("wrapid", oldId)
430 end
431end
432
433function Player:onQueueLeave(queue)
434 self:sendExtendedOpcode(ExtendedOPCodes.CODE_DUNGEONS, json.encode({action = "queue", data = {joined = false}}))
435 local dungeon = queue:getDungeon()
436 local players = Game.getPlayers()
437 local inQueue = queue:getPlayersNumber()
438 for _, player in ipairs(players) do
439 player:sendExtendedOpcode(
440 ExtendedOPCodes.CODE_DUNGEONS,
441 json.encode({action = "queueUpdate", data = {id = dungeon:getId(), queue = inQueue, estimated = dungeon:getEstimatedQueueTime(player)}})
442 )
443 end
444end