Faaaala galera! Tudo bom? Desde ontem eu estou tentando fazer npc, foi bem chatinho de corrigir os bugs e etc. Enfim, o importante é que ele está pronto, e pelo que eu testei, não há nenhum bug comprometedor.
Como funciona: Como é um npc, eu vou mostrar como pode ser a conversa:
Jogador: Info
Npc: Eu posso criar seu monstro, apenas diga criar e siga as instruções. Diga reset para recomeçar.
Jogador: Criar
Npc: Diga o nome do seu monstro. Lembre-se, é melhor ter tantos gps com você.
Jogador [Nome do Monstro]
Npc: O nome está correto, agora seleciona a raça para o seu monstro. A raça é o que vai definir os ataques e a aparencia do seu monstro, escolha entre: venom, undead, blood e fire.
Jogador: [Venom ou Undead ou Blood ou Fire]
Npc: A raça do seu monstro foi escolhida como [Raça escolhida], agora escolha a aparencia do seu monstro.
Npc: A lista de aparencias é esta: [Lista de aparências para raça escolhida].
Jogador: [Nome do monstro da aparência]
Npc: A aparencia do seu monstro foi escolhida, agora diga até 3 voses para seu monstro e para finalizar, diga fim.
Jogador: [Voz]
Npc: [Nada]
Jogador: fim
Npc: Parabéns! Seu monstro foi criado. Em breve ele poderá ser usado.
Jogador: reset
Npc: O sistema foi resetado para você.
Feito, entenderam? Vamos ao npc...
NPC
local keywordHandler = KeywordHandler:new() local npcHandler = NpcHandler:new(keywordHandler) NpcSystem.parseParameters(npcHandler) local talkState = {} local info = {} function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end function onThink() npcHandler:onThink() end function creatureSayCallback(cid, type, msg) if(not npcHandler:isFocused(cid)) then return false end local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid local race = { ['venom'] = {['attacks'] = {1, 2}, ['looktype'] = {['slime'] = '<look type="19" head="20" body="30" legs="40" feet="50" corpse="1496"/>'}}, ['undead'] = {['attacks'] = {3, 4}, ['looktype'] = {['undead dragon'] = '<look type="231" corpse="6306"/>'}}, ['fire'] = {['attacks'] = {5, 6}, ['looktype'] = {['demon'] = '<look type="35" corpse="5995"/>'}}, ['blood'] = {['attacks'] = {7, 8}, ['looktype'] = {['vampire'] = '<look type="68" head="20" body="30" legs="40" feet="50" corpse="6006"/>'}} } local cost = 1000 -- custo para criar o monstro local one = FALSE -- um monstro por jogador? TRUE para sim e FALSE para não if talkState[talkUser] == nil and msg == "info" then selfSay("Eu posso criar seu monstro, apenas diga criar e siga as instruções. Diga reset para recomeçar.", cid) elseif talkState[talkUser] == nil and msg == "criar" then if getPlayerStorageValue(cid, 40000) == 1 and one == TRUE then selfSay("Você já criou seu monstro, não pode criar outro.", cid) else selfSay("Diga o nome do seu monstro. Lembre-se, é melhor ter " .. cost .. " gps com você.", cid) talkState[talkUser] = 0 return TRUE end elseif msg == "reset" then table.remove(info, table.find(info, cid)) selfSay("O sistema foi resetado para você.", cid) talkState[talkUser] = nil return TRUE end if talkState[talkUser] == 0 then if isValid(msg) then if monsterExist(msg) == FALSE then info["'" .. cid .. "'"] = {} table.insert(info["'" .. cid .. "'"], msg) talkState[talkUser] = 1 selfSay("O nome está correto, agora seleciona a raça para o seu monstro. A raça é o que vai definir os ataques e a aparencia do seu monstro, escolha entre: venom, undead, blood e fire.", cid) else selfSay("Desculpe, este monstro já existe.", cid) end else selfSay("Nome invalido.", cid) end elseif talkState[talkUser] == 1 then if race[msg] then table.insert(info["'" .. cid .. "'"], msg) talkState[talkUser] = 2 selfSay("A raça do seu monstro foi escolhida como " .. msg .. ", agora escolha a aparencia do seu monstro.", cid) selfSay("A lista de aparencias é esta: " .. getoutfit(race[info["'" .. cid .. "'"][2]]['looktype']) .. ".", cid) else selfSay("Esta raça não pode ser escolhida.", cid) end elseif talkState[talkUser] == 2 then if race[info["'" .. cid .. "'"][2]]['looktype'][msg] then talkState[talkUser] = 3 table.insert(info["'" .. cid .. "'"], race[info["'" .. cid .. "'"][2]]['looktype'][msg]) selfSay("A aparencia do seu monstro foi escolhida, agora diga até 3 voses para seu monstro e para finalizar, diga fim.", cid) else selfSay("Este outfit não pode ser escolhido.") end elseif talkState[talkUser] == 3 and msg ~= "fim" then if #info["'" .. cid .. "'"] == 3 or #info["'" .. cid .. "'"][4] < 3 then if #info["'" .. cid .. "'"] == 3 then info["'" .. cid .. "'"][4] = {} end table.insert(info["'" .. cid .. "'"][4], msg) else selfSay("Você já alcançou o máximo de voses.", cid) end elseif talkState[talkUser] == 3 and msg == "fim" then if doPlayerRemoveMoney(cid, cost) then table.insert(info["'" .. cid .. "'"], race[info["'" .. cid .. "'"][2]]['attacks']) doCreateMonsterIn(info["'" .. cid .. "'"]) talkState[talkUser] = nil setPlayerStorageValue(cid, 40000, 1) selfSay("Parabéns! Seu monstro foi criado. Em breve ele poderá ser usado.", cid) table.remove(info, table.find(info, cid)) else selfSay("Desculpe, você não tem dinheiro.", cid) end end return true end npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback) npcHandler:addModule(FocusModule:new()) function monsterExist(s) local info = io.open("data/monster/monsters.xml", "r") local re = info:read("*all") if string.find(string.lower(re), "'" .. string.lower(s) .. "'") or string.find(string.lower(re), '"' .. string.lower(s) .. '"') then return TRUE end return FALSE end function doCreateMonsterIn(tab) local attacks = { [1] = '<attack name="melee" interval="2000" skill="30" attack="35"/>', [2] = '<attack name="earth" interval="1000" chance="14" range="4" target="1" min="-100" max="-200"> <attribute key="areaEffect" value="plantattack"/> </attack>', [3] = '<attack name="melee" interval="2000" min="-0" max="-185"/>', [4] = '<attack name="lifedrain" interval="1000" chance="14" radius="4" target="0" min="-50" max="-225"> <attribute key="areaEffect" value="smallclouds"/> </attack>', [5] = '<attack name="melee" interval="2000" skill="30" attack="35"/>', [6] = '<attack name="fire" interval="1000" chance="11" range="7" radius="4" target="1" min="-150" max="-175"> <attribute key="shootEffect" value="fire"/> <attribute key="areaEffect" value="firearea"/> </attack>', [7] = '<attack name="melee" interval="2000" min="-50" max="-150"/>', [8] = '<attack name="energy" interval="1000" chance="14" range="7" min="-65" max="-175"> <attribute key="shootEffect" value="energy"/> </attack>' } local info = io.open("data/lib/model.txt", "r") local re = info:read("*all") local arquive = io.open("data/monster/" .. tab[1] .. ".xml", "w+") arquive:write(re) arquive:close() local arq = io.open("data/monster/" .. tab[1] .. ".xml", "r") local ri = arq:read("*all") local sub = string.gsub(ri, "-- NAME", tab[1]) local sub2 = string.gsub(sub, "-- RACE", tab[2]) local sub3 = string.gsub(sub2, "-- LOOK", tab[3]) local sub4, sub5 = nil, nil if #tab == 5 then for n, voice in pairs(tab[4]) do sub4 = sub4 and string.gsub(sub4, "-- VOICE" .. n, '<voice sentence="' .. voice .. '"/>') or string.gsub(sub3, "-- VOICE1", '<voice sentence="' .. voice .. '"/>') end end local fo = #tab == 5 and tab[5] or tab[4] sub4 = sub4 or sub3 for n, atid in pairs(fo) do sub5 = sub5 and string.gsub(sub5, "-- ATTACK" .. n, attacks[atid]) or string.gsub(sub4, "-- ATTACK1", attacks[atid]) end sub5 = sub5 or sub4 local file = io.open("data/monster/monsters.xml", "r") local re = file:read("*all") local new = io.open("data/monster/monsters.xml", "w+") local su, sub2 = string.gsub(re, '-- XML', '<monster name="' .. tab[1] .. '" file="' .. tab[1] .. '.xml"/>\n-- XML') new:write(su) local arquive = io.open("data/monster/" .. tab[1] .. ".xml", "w+") arquive:write(sub5) arquive:close() addEvent(doReloadInfo, 180 * 1000, RELOAD_MONSTERS) end function getoutfit(tab) local s = nil for opt, _ in pairs(tab) do s = s and s .. ", " .. opt or opt end return s end function isValid(msg) if #msg < 3 or #msg > 10 then return nil end for i = 1, #msg do if not(string.match(msg, "%a", i)) or (string.match(msg, "%a", i) ~= string.sub(msg, i, i) and string.match(msg, "%s", i) ~= string.sub(msg, i, i)) then return nil end end return TRUE end
Feito isso, vá em data/lib, crie um arquivo chamado model.txt.
Lib
<?xml version="1.0" encoding="UTF-8"?> <monster name="-- NAME" nameDescription="a -- NAME" race="-- RACE" experience="0" speed="225" manacost="0"> <health now="3000" max="3000"/> -- LOOK <targetchange interval="5000" chance="0"/> <strategy attack="90" defense="10"/> <flags> <flag summonable="0"/> <flag attackable="1"/> <flag hostile="0"/> <flag illusionable="0"/> <flag convinceable="0"/> <flag pushable="0"/> <flag canpushitems="0"/> <flag canpushcreatures="0"/> <flag targetdistance="1"/> <flag staticattack="90"/> <flag runonhealth="0"/> </flags> <attacks> -- ATTACK1 -- ATTACK2 </attacks> <defenses armor="30" defense="35"/> <voices interval="10000" chance="10"> -- VOICE1 -- VOICE2 -- VOICE3 </voices> <loot> </loot> </monster>
Por ultimo vá em data/monster, abra o arquivo monsters.xml e abaixo de <monsters> cole isto:
-- XML
Feito, o npc está instalado.
O npc vai criar um novo monstro no otserv, todas as raças estão balanceadas. Depois de 3 minutos ele irá executar o reload para os monstros e o novo monstro estará disponível.
Eu aconselho que apenas os mais experientes mudem o script, mas eu vou ensinar como adicionar mais looktypes para cada raça.
Vá nesta tabela:
local race = { ['venom'] = {['attacks'] = {1, 2}, ['looktype'] = {['slime'] = '<look type="19" head="20" body="30" legs="40" feet="50" corpse="1496"/>'}}, ['undead'] = {['attacks'] = {3, 4}, ['looktype'] = {['undead dragon'] = '<look type="231" corpse="6306"/>'}}, ['fire'] = {['attacks'] = {5, 6}, ['looktype'] = {['demon'] = '<look type="35" corpse="5995"/>'}}, ['blood'] = {['attacks'] = {7, 8}, ['looktype'] = {['vampire'] = '<look type="68" head="20" body="30" legs="40" feet="50" corpse="6006"/>'}} }
Observe esta parte:
{['slime'] = '<look type="19" head="20" body="30" legs="40" feet="50" corpse="1496"/>'}
Agora, observe como poderia ser adicionada:
{['slime'] = '<look type="19" head="20" body="30" legs="40" feet="50" corpse="1496"/>', ['wasp'] = '<look type="44" head="20" body="30" legs="40" feet="50" corpse="5989"/>'}
E assim você pode adicionar quantas mais desejar.
Video
http://www.youtube.com/watch?v=Bmg37YQLJ00
--
Espero que gostem do npc, demorei bastante para fazer. Abraços. Se houver algum bug, por favor avisem.