Ir para conteúdo

L3K0T

Membro
  • Registro em

  • Última visita

  1. NPC Oressa 04:51 Oressa: Monks are disciplined martial artists, mastering the flow of combat with their fists and inner spirit. ... 04:51 Oressa: They are agile and can take considerable damage, dodging attacks while dealing consistent damage in close combat. ... 04:51 Oressa: If you wish to be a master of hand-to-hand combat and spiritual balance, you should consider choosing the monk vocation. local internalNpcName = "Oressa" local npcType = Game.createNpcType(internalNpcName) local npcConfig = {} npcConfig.name = internalNpcName npcConfig.description = internalNpcName npcConfig.health = 100 npcConfig.maxHealth = npcConfig.health npcConfig.walkInterval = 2000 npcConfig.walkRadius = 2 npcConfig.outfit = { lookType = 148, lookHead = 114, lookBody = 78, lookLegs = 96, lookFeet = 114, lookAddons = 2, } npcConfig.flags = { floorchange = false, } npcConfig.voices = { interval = 15000, chance = 50, { text = "You can't take it all with you - sell your Dawnport things before \z you receive the gear of your definite vocation!", }, { text = "Leave all Dawnport things behind you and choose your destiny!" }, { text = "Come to me if you need healing!" }, { text = "Choose your vocation and explore the mainland!" }, { text = "Talk to me to choose your definite vocation! Become a knight, paladin, druid, sorcerer or monk!" }, { text = "World needs brave adventurers like you. Choose your vocation and sail to the mainland!" }, { text = "Poisoned? Bleeding? Wounded? I can help!" }, } local keywordHandler = KeywordHandler:new() local npcHandler = NpcHandler:new(keywordHandler) npcType.onThink = function(npc, interval) npcHandler:onThink(npc, interval) end npcType.onAppear = function(npc, creature) npcHandler:onAppear(npc, creature) end npcType.onDisappear = function(npc, creature) npcHandler:onDisappear(npc, creature) end npcType.onMove = function(npc, creature, fromPosition, toPosition) npcHandler:onMove(npc, creature, fromPosition, toPosition) end npcType.onSay = function(npc, creature, type, message) npcHandler:onSay(npc, creature, type, message) end npcType.onCloseChannel = function(npc, creature) npcHandler:onCloseChannel(npc, creature) end -- Basic keywords keywordHandler:addKeyword({ "name" }, StdModule.say, { npcHandler = npcHandler, text = "I am Oressa Fourwinds, the {healer}. ", }) keywordHandler:addKeyword({ "healer" }, StdModule.say, { npcHandler = npcHandler, text = "If you are hurt my child, I will {heal} your wounds.", }) keywordHandler:addKeyword({ "job" }, StdModule.say, { npcHandler = npcHandler, text = "I can {heal} you if you are hurt. I can also help you choose your {vocation}. ", }) keywordHandler:addKeyword({ "doors" }, StdModule.say, { npcHandler = npcHandler, text = "Behind each of those doors, the equipment and skills of one vocation lies - \z sorcerer, paladin, knight, druid or monk. ...", "When you have reached level 8, you can choose your definite vocation. You have to talk to me to receive it, \z and then you may open one of the doors, take up your vocation's gear, and leave the island. But be aware: ...", "Once you have chosen your vocation and stepped through a door, you cannot go back or choose a different vocation. \z So choose well!", }) keywordHandler:addKeyword({ "inigo" }, StdModule.say, { npcHandler = npcHandler, text = "He has seen much, and likes to help the younger ones. If you have questions about what to do, \z or whom to ask for anything, go to Inigo.", }) keywordHandler:addKeyword({ "richard" }, StdModule.say, { npcHandler = npcHandler, text = "Found a new way of living and took to it like a fish to water.", }) keywordHandler:addKeyword({ "coltrayne" }, StdModule.say, { npcHandler = npcHandler, text = "Ah. Some wounds never heal. <sighs> Shipwrecked in body and mind. Nowhere to go, so he doesn't leave.", }) keywordHandler:addKeyword({ "morris" }, StdModule.say, { npcHandler = npcHandler, text = "He broods over problems he won't share. But maybe you can help him with a little quest or two.", }) keywordHandler:addKeyword({ "hamish" }, StdModule.say, { npcHandler = npcHandler, text = "He lives only for his experiments and potions", }) keywordHandler:addKeyword({ "dawnport" }, StdModule.say, { npcHandler = npcHandler, text = { "This is a strange place. Many beings are called to it. I dreamed of it long before I came here. ...", "Something spoke to me, telling me I had to be its voice; a voice of the Oracle here for the sake of \z the adventurers that would come to defend {World} against evil and need to {choose} their destiny.", }, }) keywordHandler:addKeyword({ "rookgaard" }, StdModule.say, { npcHandler = npcHandler, text = "I have heard of it, yes.", }) --From topic of vocation to topic of the "yes" message (choosing vocation) local topicTable = { [5] = VOCATION.ID.KNIGHT, [6] = VOCATION.ID.PALADIN, [7] = VOCATION.ID.DRUID, [8] = VOCATION.ID.SORCERER, [9] = 9, -- Monk Vocation ID } local vocationRoomPositions = { [5] = { x = 32068, y = 31884, z = 6 }, [6] = { x = 32059, y = 31884, z = 6 }, [7] = { x = 32073, y = 31884, z = 6 }, [8] = { x = 32054, y = 31884, z = 6 }, [9] = { x = 32064, y = 31884, z = 6 }, -- ATENÇÃO: Edite as coordenadas para a sala do Monk } local function creatureSayCallback(npc, creature, type, message) local player = Player(creature) local playerId = player:getId() if not npcHandler:checkInteraction(npc, creature) then return false end local health = player:getHealth() local vocationDefaultMessages = { "A vocation is your profession and destiny, determining your skills and way of fighting. \z There are five vocations in Tibia: {knight}, {sorcerer}, {paladin}, {druid} or {monk}. \z Each one has its unique special abilities. ... ", "When you leave the outpost through one of the gates upstairs, you will be equipped with \z training gear of a specific vocation in order to defend yourself against the monsters outside. ... ", "You can try them out as often as you wish to. When you have gained enough experience to reach level 8, \z you are ready to choose the definite vocation that is to become your destiny. ... ", "Think carefully, as you can't change your vocation later on! You will have to choose your vocation in order \z to leave Dawnport for the main continent through one of these {doors} behind me. ... ", "Talk to me again when you are ready to choose your vocation, and I will set you on your way. ", } -- Heal and help dialog if MsgContains(message, "healing") and npcHandler:getTopic(playerId) == 0 then if player:getLevel() < 8 then if health < 40 or player:getCondition(CONDITION_POISON) then if health < 40 then player:addHealth(40 - health) player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) end if player:getCondition(CONDITION_POISON) then player:removeCondition(CONDITION_POISON) player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) end npcHandler:say("You are hurt, my child. I will heal your wounds.", npc, creature) npcHandler:setTopic(playerId, 0) else return npcHandler:say("You do not need any healing right now.", npc, creature) end end elseif MsgContains(message, "help") and npcHandler:getTopic(playerId) == 0 then if player:getCondition(CONDITION_POISON) == nil or health > 40 then return npcHandler:say("You do not need any healing right now.", npc, creature) end if health < 40 or player:getCondition(CONDITION_POISON) then if health < 40 then player:addHealth(40 - health) player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) end if player:getCondition(CONDITION_POISON) then player:removeCondition(CONDITION_POISON) player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) end npcHandler:say("You are hurt, my child. I will heal your wounds.", npc, creature) npcHandler:setTopic(playerId, 0) end -- Vocation dialog elseif npcHandler:getTopic(playerId) == 0 and MsgContains(message, "vocation") then npcHandler:say(vocationDefaultMessages, npc, creature, 10) npcHandler:setTopic(playerId, 0) -- Choosing dialog start elseif (MsgContains(message, "choosing") or MsgContains(message, "choose")) and npcHandler:getTopic(playerId) == 0 then if player:getLevel() >= 8 then npcHandler:say( "I'll help you decide. \z Tell me: Do you like to keep your {distance}, or do you like {close} combat?", npc, creature ) npcHandler:setTopic(playerId, 2) else npcHandler:say(vocationDefaultMessages, npc, creature, 10) npcHandler:setTopic(playerId, 0) end elseif MsgContains(message, "distance") and npcHandler:getTopic(playerId) == 2 then npcHandler:say("Tell me: Do you prefer to fight with {bow} and {spear}, or do you want to cast {magic}?", npc, creature) npcHandler:setTopic(playerId, 3) -- close combat choices (Knight or Monk) elseif MsgContains(message, "close") and npcHandler:getTopic(playerId) == 2 then npcHandler:say("Tell me: Do you prefer to fight with heavy {weapons} and a shield, or rely on your {fists} and martial arts?", npc, creature) npcHandler:setTopic(playerId, 10) -- knight elseif MsgContains(message, "weapons") and npcHandler:getTopic(playerId) == 10 then npcHandler:say({ "Then you should choose the {vocation} of a knight and become a valiant fighter with sword and shield. ...", "Knights are the toughest of all vocations. They can take more damage and carry more items than the other \z vocations, but they will deal less damage than paladins, druids or sorcerers. ...", "Knights can wield one- or two-handed swords, axes and clubs, and they can cast a few spells to draw a \z monster's attention to them. ...", "So tell me: DO YOU WISH TO BECOME A VALIANT KNIGHT? Answer with a proud {YES} if that is your choice!", }, npc, creature, 10) npcHandler:setTopic(playerId, 5) -- monk elseif MsgContains(message, "fists") and npcHandler:getTopic(playerId) == 10 then npcHandler:say({ "Then you should follow the path of the {monk}, masters of spiritual energy and hand-to-hand combat. ...", "Monks are disciplined fighters who rely on their inner strength and agility to dodge attacks while striking \z swiftly and powerfully. ...", "They are tougher than mages and deal fierce damage using their specialized fist fighting skills. ...", "So tell me: DO YOU WISH TO BECOME A DISCIPLINED MONK? Answer with a proud {YES} if that is your choice!", }, npc, creature, 10) npcHandler:setTopic(playerId, 9) -- Paladin elseif (MsgContains(message, "bow") or MsgContains(message, "spear")) and npcHandler:getTopic(playerId) == 3 then npcHandler:say({ "Then you should join the ranks of the paladins, noble hunters and rangers of the wild, who rely on the \z swiftness of movement and ranged attacks. ...", "Paladins are jacks of all trades. They are tougher than the magically gifted and can carry more items \z than druids or sorcerers, but they can take not as much damage as a knight can. ...", "Paladins deal more damage than knights but less than druids or sorcerers, and have the longest range \z in their distance attacks. ...", "They can also use holy magic to slay the unholy and undead in particular. ...", "DO YOU WISH TO BECOME A DARING PALADIN? Answer with a proud {YES} if that is your choice!", }, npc, creature, 10) npcHandler:setTopic(playerId, 6) -- Mage elseif MsgContains(message, "magic") and npcHandler:getTopic(playerId) == 3 then npcHandler:say( "Tell me: Do you prefer to {heal} and cast the power of nature and ice, or do you want to rain \z fire and {death} on your foes?", npc, creature ) npcHandler:setTopic(playerId, 4) -- Druid elseif MsgContains(message, "heal") and npcHandler:getTopic(playerId) == 4 then npcHandler:say({ "Then you should learn the ways of the druids, healers and powerful masters of natural magic. ...", "Druids can heal their friends and allies, but they can also cast powerful ice and earth magic \z to kill their enemies. They can do a little energy, fire or death damage as well. ...", "Druids cannot take much damage or carry many items, but they deal \z much more damage than paladins or knights. ...", "So tell me: DO YOU WISH TO BECOME A SAGACIOUS DRUID? Answer with a proud {YES} if that is your choice!", }, npc, creature, 10) npcHandler:setTopic(playerId, 7) -- Sorcerer elseif MsgContains(message, "death") and npcHandler:getTopic(playerId) == 4 then npcHandler:say({ "Then you should become a sorcerer, a mighty wielder of deathly energies and arcane fire. ...", "Sorcerers are powerful casters of magic. They use fire, energy and death magic to lay low their enemies. \z They can do a little ice or earth damage as well. ...", "Sorcerers cannot take much damage or carry many items, \z but they deal much more damage than paladins or knights. ...", "So tell me: DO YOU WISH TO BECOME A POWERFUL SORCERER? Answer with a proud {YES} if that is your choice!", }, npc, creature, 10) npcHandler:setTopic(playerId, 8) -- Choosing dialog start elseif MsgContains(message, "decided") and npcHandler:getTopic(playerId) == 0 then npcHandler:say("So tell me, which {vocation} do you want to choose: {knight}, {sorcerer}, {paladin}, {druid} or {monk}?", npc, creature) -- Say vocations name elseif MsgContains(message, "sorcerer") and npcHandler:getTopic(playerId) == 0 then local message = { "Sorcerers are powerful casters of death, energy and fire magic. \z They can do a little ice or earth damage as well. ...", "Sorcerers cannot take much damage or carry many items, but they deal more damage than paladins or knights, \z and can target several enemies. ...", "If you wish to be a caster of fire and energy, hurling death magic at your foes, \z you should consider choosing the sorcerer vocation.", } if player:getLevel() >= 8 then table.insert(message, "So tell me: DO YOU WISH TO BECOME A POWERFUL SORCERER?" .. " Answer with a proud {YES} if that is your choice!") npcHandler:setTopic(playerId, 8) else npcHandler:setTopic(playerId, 0) end npcHandler:say(message, npc, creature, 10) elseif MsgContains(message, "druid") and npcHandler:getTopic(playerId) == 0 then local message = { "Druids are healers and powerful masters of ice and earth magic. \z They can also do a little energy, fire or death damage as well. ... ", "Druids cannot take much damage or carry many items, but they deal more damage than paladins or knights, \z and can target several enemies. ... ", "If you wish to be a healer and wielder of powerful natural magic, \z you should consider choosing the druid vocation.", } if player:getLevel() >= 8 then table.insert(message, "So tell me: DO YOU WISH TO BECOME A SAGACIOUS DRUID?" .. " Answer with a proud {YES} if that is your choice!") npcHandler:setTopic(playerId, 7) else npcHandler:setTopic(playerId, 0) end npcHandler:say(message, npc, creature, 10) elseif MsgContains(message, "paladin") and npcHandler:getTopic(playerId) == 0 then local message = { "Paladins are sturdy distance fighters. They are tougher than druids or sorcerers and can carry more items, \z but they are less tough than a knight. ... ", "Paladins have the longest attack range, and can deal the most damage on a single target. ... ", "They can also use holy magic to slay the unholy and undead in particular. ... ", "If you like to keep a distance to your enemy, shooting while you outdistance him, \z you should consider choosing the paladin vocation.", } if player:getLevel() >= 8 then table.insert(message, "So tell me: DO YOU WISH TO BECOME A DARING PALADIN?" .. " Answer with a proud {YES} if that is your choice!") npcHandler:setTopic(playerId, 6) else npcHandler:setTopic(playerId, 0) end npcHandler:say(message, npc, creature, 10) elseif MsgContains(message, "knight") and npcHandler:getTopic(playerId) == 0 then local message = { "Knights are stalwart melee fighters, the toughest of all vocations. They can take more damage and carry \z more items than the other vocations, but they will deal less damage than paladins, druids or sorcerers. ... ", "Knights can wield one- or two-handed swords, axes and clubs, and they can cast a few spells to draw a \z monster's attention to them. ... ", "If you want to be a tough melee fighter who can resist much longer than anyone else, \z you should consider choosing the knight vocation.", } if player:getLevel() >= 8 then table.insert(message, "DO YOU WISH TO BECOME A VALIANT KNIGHT? Answer with a proud {YES} if that is your choice!") npcHandler:setTopic(playerId, 5) else npcHandler:setTopic(playerId, 0) end npcHandler:say(message, npc, creature, 10) elseif MsgContains(message, "monk") and npcHandler:getTopic(playerId) == 0 then local message = { "Monks are disciplined martial artists, mastering the flow of combat with their fists and inner spirit. ...", "They are agile and can take considerable damage, dodging attacks while dealing consistent damage in close combat. ...", "If you wish to be a master of hand-to-hand combat and spiritual balance, \z you should consider choosing the monk vocation.", } if player:getLevel() >= 8 then table.insert(message, "DO YOU WISH TO BECOME A DISCIPLINED MONK? Answer with a proud {YES} if that is your choice!") npcHandler:setTopic(playerId, 9) else npcHandler:setTopic(playerId, 0) end npcHandler:say(message, npc, creature, 10) elseif (npcHandler:getTopic(playerId) >= 5) and (npcHandler:getTopic(playerId) <= 9) then if MsgContains(message, "yes") then for index, value in pairs(topicTable) do if npcHandler:getTopic(playerId) == index then if player:getStorageValue(Storage.Dawnport.DoorVocation) == -1 then -- Change to new vocation, convert magic level and skills and set proper stats player:changeVocation(value) player:setStorageValue(Storage.Dawnport.DoorVocation, value) if configManager.getBoolean(configKeys.TELEPORT_PLAYER_TO_VOCATION_ROOM) then local position = vocationRoomPositions[index] player:teleportTo(Position(position.x, position.y, position.z)) player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) end else npcHandler:setTopic(playerId, 0) return true end end end -- Remove Mainland smuggling items removeMainlandSmugglingItems(player) npcHandler:say({ "SO BE IT. CAST OFF YOUR TRAINING GEAR AND RISE, NOBLE " .. player:getVocation():getName():upper() .. "! ...", "Go through the correct door. Open the chest and take the equipment inside \z before you leave to the north. ...", "Take the ship to reach the Mainland. Farewell, friend and good luck in all you undertake!", }, npc, creature, 10) npcHandler:setTopic(playerId, 0) elseif MsgContains(message, "no") then local vocationMessage = { [5] = "{paladin}, {sorcerer}, {druid} or {monk}", [6] = "{knight}, {sorcerer}, {druid} or {monk}", [7] = "{knight}, {paladin}, {sorcerer} or {monk}", [8] = "{knight}, {paladin}, {druid} or {monk}", [9] = "{knight}, {paladin}, {sorcerer} or {druid}", } npcHandler:say({ "As you wish. If you wish to learn something about the " .. vocationMessage[npcHandler:getTopic(playerId)] .. " vocation, tell me.", }, npc, creature, 10) npcHandler:setTopic(playerId, 0) end end return true end local function greetCallback(npc, creature) local player = Player(creature) local playerId = player:getId() if player:getLevel() >= 8 then npcHandler:setMessage( MESSAGE_GREET, "Welcome, young adventurer. Tell me if you need help in \z {choosing} your {vocation}, or if you have {decided} on the {vocation} you want to choose." ) else npcHandler:setMessage( MESSAGE_GREET, "Welcome to the temple of Dawnport, child. \z If you need {healing}, I can help you. Ask me about a {vocation} if you need counsel." ) end return true end npcHandler:setCallback(CALLBACK_GREET, greetCallback) npcHandler:setMessage(MESSAGE_FAREWELL, "Good bye, child.") npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback) npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true) -- npcType registering the npcConfig table npcType:register(npcConfig)
  2. L3K0T alterou sua foto pessoal
  3. Que tipo de skill? Sword, magic level,..?
  4. BrownDeveloper reagiu a uma resposta no tópico: System Drop Global - L3K0T TFS 0.4
  5. L3K0T postou uma resposta no tópico em Suporte Tibia OTServer
    @RaviRogowski,usa OVH segura e tem proteção ddos gratis
  6. L3K0T reagiu a uma resposta no tópico: Apresentamos com orgulho: VERTUS SPRITER
  7. arcaydecom reagiu a uma resposta no tópico: WebSite Poketibia 1.0
  8. arawnzz reagiu a uma resposta no tópico: Sprite Stones, Badges e Gyns para Poketibia
  9. V2 O ServerStatusV2 é um app Android leve e eficiente para monitorar o status de portas TCP de qualquer servidor remoto, com notificações instantâneas de queda mesmo quando o app está fechado. Veja como ele funciona: Configuração de IP Ao abrir o app, basta digitar o endereço IP ou hostname do seu servidor na caixinha de texto. Toque em “MONITORAR” e o app grava o IP em cache (SharedPreferences), iniciando imediatamente o monitoramento. Um botão “ALTERAR IP” permite trocar de servidor sem reinstalar o app: ele para o serviço, limpa o IP salvo e volta para o modo de input. Monitoramento em segundo plano Internamente, o app inicia um Foreground Service que roda em background, exibindo uma notificação fixa (“Rodando em background…”). Mesmo se a Activity for fechada ou removida dos apps recentes, o serviço é reiniciado automaticamente, garantindo vigilância 24/7. Polling inteligente com Kotlin Coroutines A cada 10 segundos, o serviço tenta abrir conexão (socket) com as portas configuradas (80, 443, 7171, 7172, 587). Se qualquer porta cair (conexão falha após 1 000 ms), o app dispara uma notificação heads-up com som e vibração, alertando imediatamente. Interface de Status A Activity exibe um relatório agrupado por categoria (Site, Servidor e E-mail), mostrando “Online ✔️” ou “Offline ❌” para cada porta. Logo no primeiro ciclo, o app já exibe o status real sem precisar aguardar. Personalização e robustez O host fica salvo entre execuções, portanto você não precisa redigitar o IP sempre que abrir o app. O código usa ConcurrentHashMap e CoroutineScope, garantindo thread-safety e fácil cancelamento. Foi pensado para não sobrecarregar o servidor nem gerar bloqueio de IP, mantendo o polling num intervalo seguro de 10 s. Com o ServerStatusV2 você terá uma visão clara e confiável do uptime do seu OTServ (ou de qualquer outro serviço TCP), notificando quedas em tempo real e mantendo histórico local enquanto quiser. App: app.apk Scan: https://www.virustotal.com/gui/file/d0bdba516afc3634101b234e24e624302f7f850c892d6275e2c9f552e0db49db?nocache=1 BY L3K0T V4 Além dos recursos já descritos, nesta versão v4 o ServerStatusV2 agora monitora também: OTServ nas portas 7171, 7172 e 7173 Site na porta 80 e 443 E-mail nas portas 25, 587 e 465 Veja o que foi adicionado e aprimorado: Categorias de portas estendidas Antes víamos apenas “Site”, “Servidor” e “E-mail” com portas básicas. Agora há uma categoria “OTServ” para as três portas de jogo/login/console (7171, 7172, 7173), e a categoria “E-mail” cobre SMTP clássico (25), Submission com STARTTLS (587) e SMTPS legacy (465). Máscara de IP automática Ao digitar ou colar algo como 192168011, o campo transforma em 192.168.0.11 automaticamente, facilitando a entrada sem precisar digitar os pontos. Persistência com SharedPreferences e “ALTERAR IP” O IP fica salvo entre execuções. Se precisar trocar de servidor, basta tocar em ALTERAR IP, que interrompe o serviço, limpa o cache e permite nova edição. Foreground Service resiliente Serviço roda em background com notificação fixa, resiste a remoção de apps recentes e, em v4, inclui: Ignorar otimizações de bateria (Battery Saver/Doze Mode). WakeLock parcial para manter o CPU acordado enquanto monitora, evitando ser suspenso. Polling inteligente a cada 10 s Usando Kotlin Coroutines, cada porta é testada via socket com timeout de 1 000 ms. Se qualquer uma delas falhar, uma notificação heads-up com som e vibração alerta instantaneamente. Interface de Status Relatório agrupado por categoria, com bolinha (“●”), ícone e texto “Online ✔️” ou “Offline ❌”. Atualização logo no primeiro ciclo, sem esperar o polling inicial. Leve e robusto Usa ConcurrentHashMap para status thread-safe e cancelamento fácil de coroutines. Mantém intervalo de 10 s para evitar sobrecarga ou bloqueio de IP pelo servidor. App: app.apk Scan: https://www.virustotal.com/gui/file/d0bdba516afc3634101b234e24e624302f7f850c892d6275e2c9f552e0db49db?nocache=1 BY L3K0T
  10. Bom, como todos sabem, existe o shop.lua em servidores 0.4 para receber itens. Muitos deles têm loops infinitos ou fazem uma varredura completa no banco de dados, o que pode deixá-los instáveis. Isso ocorre principalmente quando o script não verifica adequadamente se há itens para processar ou se o banco de dados está sobrecarregado com consultas desnecessárias. No entanto, com algumas melhorias, podemos otimizar esse processo, garantindo que o servidor se mantenha estável e eficiente. No nosso exemplo, aplicamos algumas mudanças importantes: Checagem eficiente de itens pendentes: A consulta ao banco de dados foi otimizada para verificar se existem realmente itens pendentes para o jogador. Se não houver itens, o script termina sua execução rapidamente, evitando sobrecarga. Evitar loops infinitos: O loop foi ajustado para garantir que, se não houver mais itens para processar, o script saia sem continuar verificando o banco de dados, prevenindo loops desnecessários. Logs: Foi adicionado um sistema de logs, onde cada transação bem sucedida do jogador é registrada com data e hora, além de informações sobre o jogador e os itens recebidos. Execução controlada com intervalos: Ao invés de fazer consultas contínuas ao banco de dados, o script executa checagens de tempos em tempos, configuráveis pelo parâmetro SQL_interval. Isso distribui as verificações ao longo do tempo e evita que o servidor fique sobrecarregado com solicitações simultâneas. Segue o scripts: data/globalevents/scripts/shop.lua function getCurrentDateTime() local currentDateTime = os.date("%Y-%m-%d %H:%M:%S") return currentDateTime end function createDirectoryIfNotExists(dir) local command = "mkdir -p " .. dir os.execute(command) end function saveLog(message) local logFilePath = "data/logs/shop/shop.txt" local logDir = "data/logs/shop/" createDirectoryIfNotExists(logDir) local currentDateTime = getCurrentDateTime() local logMessage = string.format("[%s] %s\n", currentDateTime, message) local file = io.open(logFilePath, "a") if file then file:write(logMessage) file:close() else print("Erro ao tentar escrever no arquivo de log.") end end SHOP_MSG_TYPE = 19 SQL_interval = 5 function onThink(interval, lastExecution) local result_plr = db.getResult("SELECT * FROM z_ots_comunication WHERE `type` = 'login';") if result_plr:getID() == -1 then return true end local hasMoreItems = false while true do local id = tonumber(result_plr:getDataInt("id")) local cid = getCreatureByName(tostring(result_plr:getDataString("name"))) if isPlayer(cid) then hasMoreItems = true local itemtogive_id = tonumber(result_plr:getDataInt("param1")) local itemtogive_count = tonumber(result_plr:getDataInt("param2")) local add_item_name = tostring(result_plr:getDataString("param6")) local received_item = 0 local full_weight = 0 if isItemRune(itemtogive_id) then full_weight = getItemWeightById(itemtogive_id, 1) else full_weight = getItemWeightById(itemtogive_id, itemtogive_count) end local free_cap = getPlayerFreeCap(cid) if full_weight <= free_cap then local new_item = doCreateItemEx(itemtogive_id, itemtogive_count) received_item = doPlayerAddItemEx(cid, new_item) if received_item == RETURNVALUE_NOERROR then doPlayerSendTextMessage(cid, SHOP_MSG_TYPE, string.format("Você recebeu >> %s << da loja.", add_item_name)) doPlayerSave(cid) db.executeQuery("DELETE FROM `z_ots_comunication` WHERE `id` = " .. id .. ";") db.executeQuery("UPDATE `z_shop_history` SET `trans_state`='realized', `trans_real`=" .. os.time() .. " WHERE id = " .. id .. ";") saveLog(string.format("[%s] %s (ID: %d), Você recebeu >> %s << da loja.", getCurrentDateTime(), tostring(result_plr:getDataString("name")), id, add_item_name)) end else doPlayerSendTextMessage(cid, SHOP_MSG_TYPE, string.format("Você não tem capacidade suficiente para >> %s <<. Necessário: %.2f oz. Disponível: %.2f oz.", add_item_name, full_weight, free_cap)) saveLog(string.format("[%s] %s (ID: %d), Tentou comprar >> %s <<, mas não tinha capacidade suficiente. Necessário: %.2f oz. Disponível: %.2f oz.", getCurrentDateTime(), tostring(result_plr:getDataString("name")), id, add_item_name, full_weight, free_cap)) end end if not result_plr:next() then break end end result_plr:free() if not hasMoreItems then return false end return true end data/globalevents/globalevents.xml <globalevent name="shop" interval="30000" script="shop.lua"/> *Testado em Myaac *Testado em OTX2 8.60 *Testado em Ubuntu 20.04 *Não precisa criar pasta, ele mesmo cria. Com essas melhorias, a performance do servidor foi significativamente melhorada, garantindo que o sistema de loja funcione de forma mais estável e eficiente, sem sobrecarregar o banco de dados ou causar lags. Agora, a transação de itens na loja ocorre de forma mais controlada e com menos chance de erros ou travamentos. by @L3K0T
  11. Versões mais recentes do OTServ, como TFS 1.0 ou superior, requerem versões mais novas do Ubuntu, geralmente 18.04 ou superior, devido à compatibilidade com bibliotecas e dependências atualizadas. Já servidores mais antigos, como TFS 0.3 e 0.4, funcionam melhor em versões anteriores do Ubuntu, como 16.04 ou 14.04 ou 12.04 dependendo da configuração do sistema.
  12. L3K0T reagiu a uma resposta no tópico: (Resolvido)Player nao salva quando desloga
  13. L3K0T postou uma resposta no tópico em Suporte Tibia OTServer
    local internalNpcName = "Guardian" local npcType = Game.createNpcType(internalNpcName) local npcConfig = {} npcConfig.name = internalNpcName npcConfig.description = internalNpcName npcConfig.health = 100 npcConfig.maxHealth = npcConfig.health npcConfig.walkInterval = 0 npcConfig.walkRadius = 2 npcConfig.outfit = { lookTypeEx = 2152, } npcConfig.flags = { floorchange = false, } local keywordHandler = KeywordHandler:new() local npcHandler = NpcHandler:new(keywordHandler) npcType.onThink = function(npc, interval) npcHandler:onThink(npc, interval) end npcType.onAppear = function(npc, creature) npcHandler:onAppear(npc, creature) end npcType.onDisappear = function(npc, creature) npcHandler:onDisappear(npc, creature) end npcType.onMove = function(npc, creature, fromPosition, toPosition) npcHandler:onMove(npc, creature, fromPosition, toPosition) end npcType.onSay = function(npc, creature, type, message) npcHandler:onSay(npc, creature, type, message) end npcType.onCloseChannel = function(npc, creature) npcHandler:onCloseChannel(npc, creature) end local function creatureSayCallback(npc, creature, type, message) local player = Player(creature) if not player then return false end if message:lower() == "abre-te sésamo" then local topos = Position(32311, 11005, 6) player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) player:teleportTo(topos) topos:sendMagicEffect(CONST_ME_TELEPORT) end return true end keywordHandler:addKeyword({ "abre-te sésamo" }, StdModule.say, {npcHandler = npcHandler, text = "Diga a palavra mágica e será transportado!"}) npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback) npcType:register(npcConfig)
  14. isso é pq a versão ou config da sprite ou item.otb não é compativel
  15. TESTA AI local config = { centerRoom = Position(33584, 32689, 14), BossPosition = Position(33584, 32689, 14), playerPositions = { Position(33593, 32644, 14), Position(33593, 32645, 14), Position(33593, 32646, 14), Position(33593, 32647, 14), Position(33593, 32648, 14) }, newPosition = Position(33585, 32693, 14), cooldownTime = 120 --(2 minutos) } function onUse(player, item, fromPosition, target, toPosition, isHotkey) local lastUse = Game.getStorageValue(GlobalStorage.FerumbrasAscendantQuest.MazoranLeverCooldown) local currentTime = os.time() if lastUse > 0 and currentTime - lastUse < config.cooldownTime then local remainingTime = config.cooldownTime - (currentTime - lastUse) player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Você precisa aguardar " .. remainingTime .. " segundos para puxar a alavanca novamente.") return true end if item.itemid == 9825 then local specs, spec = Game.getSpectators(config.centerRoom, false, false, 15, 15, 15, 15) for i = 1, #specs do spec = specs[i] if spec:isPlayer() then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Alguém já está enfrentando Mazoran.") return true end end local spectators = Game.getSpectators(config.BossPosition, false, false, 20, 20, 20, 20) for i = 1, #spectators do local spectator = spectators[i] if spectator:isMonster() then spectator:remove() return true end end Game.createMonster("Mazoran", config.BossPosition, true, true) for y = 32644, 32648 do local playerTile = Tile(Position(33593, y, 14)):getTopCreature() if playerTile and playerTile:isPlayer() then playerTile:getPosition():sendMagicEffect(CONST_ME_POFF) playerTile:teleportTo(config.newPosition) playerTile:getPosition():sendMagicEffect(CONST_ME_TELEPORT) end end Game.setStorageValue(GlobalStorage.FerumbrasAscendantQuest.MazoranLeverCooldown, currentTime) Game.setStorageValue(GlobalStorage.FerumbrasAscendantQuest.MazoranTimer, 1) addEvent(clearForgotten, 30 * 60 * 1000, Position(33572, 32679, 14), Position(33599, 32701, 14), Position(33319, 32318, 13), GlobalStorage.FerumbrasAscendantQuest.MazoranTimer) item:transform(9826) elseif item.itemid == 9826 then item:transform(9825) end return true end
  16. Fluppe Naves reagiu a uma resposta no tópico: Tibia Ginius Versão 1.1 by L3K0T
  17. Alterei a função canWalkthrough para Impedir o atravessamento de pisos específicos (como 11059 e 11060) se já houver um jogador sobre eles e assim ninguem entra no mesmo depot que é comum em pvp então vamos retirar isso. Verificar o tipo de mundo (PVP / non-PVP / etc..) e zonas de proteção. No PVP, jogadores podem atravessar se estiverem fora de uma zona de proteção ou quando ambos não estiverem em combate. Segue as alterações: vá em Player.cpp e ache: bool Player::canWalkthrough(const Creature* creature) const { if(creature == this || hasFlag(PlayerFlag_CanPassThroughAllCreatures) || creature->isWalkable() || std::find(forceWalkthrough.begin(), forceWalkthrough.end(), creature->getID()) != forceWalkthrough.end() || (creature->getMaster() && creature->getMaster() != this && canWalkthrough(creature->getMaster()))) return true; const Player* player = creature->getPlayer(); if(!player) return false; if((((g_game.getWorldType() == WORLDTYPE_OPTIONAL && #ifdef __WAR_SYSTEM__ !player->isEnemy(this, true) && #endif player->getVocation()->isAttackable()) || player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) || (player->getVocation()->isAttackable() && player->getLevel() < (uint32_t)g_config.getNumber(ConfigManager::PROTECTION_LEVEL))) && player->getTile()->ground && Item::items[player->getTile()->ground->getID()].walkStack) && (!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || player->getAccess() <= getAccess())) return true; return (player->isGhost() && getGhostAccess() < player->getGhostAccess()) || (isGhost() && getGhostAccess() > player->getGhostAccess()); } altere para bool Player::canWalkthrough(const Creature* creature) const { if(creature == this || hasCustomFlag(PlayerCustomFlag_CanTurnhop) || creature->isWalkable() || (creature->getMaster() && creature->getMaster() != this && canWalkthrough(creature->getMaster()))) return true; const Player* player = creature->getPlayer(); if(!player) return false; const Tile* tile = player->getTile(); if(tile && tile->ground) { // Verifica se o tile e o chão existem uint16_t groundID = tile->ground->getID(); if(groundID == 11059 || groundID == 11060) { return false; // Bloqueia atravessamento para esses pisos } } if((((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !player->isEnemy(this, true) && #ifdef __WAR_SYSTEM__ !player->isEnemy(this, true) && #endif player->getVocation()->isAttackable()) || player->getTile()->hasFlag(TILESTATE_PROTECTIONZONE) || (player->getVocation()->isAttackable() && player->getLevel() < (uint32_t)g_config.getNumber(ConfigManager::PROTECTION_LEVEL))) && player->getTile()->ground && Item::items[player->getTile()->ground->getID()].walkStack) && (!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || player->getAccess() <= getAccess())) return true; return (player->isGhost() && getGhostAccess() < player->getGhostAccess()) || (isGhost() && getGhostAccess() > player->getGhostAccess()); } pronto só recompilar e testar.
  18. use xammp da versão mais antiga

Informação Importante

Confirmação de Termo