Ir para conteúdo

Monstros duelando entre si


Skulls

Posts Recomendados

Boa noite galera

 

Como levantei no tópico: http://www.xtibia.com/forum/topic/238784-monstros-se-matando/monstros selvagens são todos tratados como amigos e, portanto, não é possível setar target neles com funções de target normal. Além disso, o callBack onTarget() não funciona para monstros.

 

Desde então estou em busca de uma forma de fazer monstros lutarem entre si sem mexer na source e, com algumas sugestões do Lobo @Night Wolf eu consegui chegar a algo bem satisfatório para o que eu precisava. Portanto, compartilho com você a base do sistema (fiz outras coisas para o meu objetivo que acho bobeira postar aqui, mas a base do sistema de luta está aqui).

 

Então vamos lá.

Primeiramente, esse sistema é baseado em dois eventos: onThink (que repete de x em x segundos) e onAttack(para evitar que o monstro ataque players quando estiver atacando monstros.

 

Vá em creaturescripts e crie as seguintes tags em creaturescripts.xml:

<event type="think" name="monsters" event="script" value="monsters.lua"/>
<event type="attack" name="monstersatt" event="script" value="monsters.lua"/>

Feito isso, vá na pasta lib (data/lib) e crie um arquivo chamado monsterslib.lua. La dentro coloque:

 

 

local config = {
    storages = {time = 5553, tgt = 5554},
    away_dist = 2,
}

--[[Aqui você define as particularidades do alvo do monstro
Por exemplo: Se o alvo for ele mesmo, ele não ataca
Se o alvo for da mesma especie, isto é, tiver o mesmo nome ele não ataca
e por ai vai]]--
function verifyTarget(cid, target)
if not isCreature(target) and not isCreature(cid) then
return false
end
if target == cid then
return false
end
return true
end
--[[Aqui é feita a verificação da área centrada no monstro e com lado igual a 2d a procura de alvos. Eu fiz para dar prioridades a monstros. Se houver um monstro e um player ele vai virar no monstro. Outro detalhe aqui é que esses monstros vao atacar o player pelo sistema novo e não pelo dano base]]-- function setTarget(cid, d) range = d or 3 if isCreature(cid) then for i, tile in pairs(getArea(getCreaturePosition(cid), range, range)) do if getTileThingByPos(tile) then tile.stackpos = STACKPOS_TOP_CREATURE local tmp = getThingFromPos(tile) if isMonster(tmp.uid) then if verifyTarget(cid, tmp.uid) == true then doCreatureSetStorage(cid, config.storages.tgt, tmp.uid) break end elseif isPlayer(tmp.uid) then doCreatureSetStorage(cid, config.storages.tgt, tmp.uid) end end end end end --[[Aqui o ataque é realizado, se o monstro tem a distancia necessaria. Vale lembrar que pode-se personalizar o dano e seus efeitos para diferentes monstros. Para isso bata criar uma função setDamage(cid, target) que seta o dano e seus efeitos de acordo com o atacante e seu alvo]]--
function attack(cid, target, att_distance)
if not isCreature(cid) and not isCreature(target) then
return false
end
local dir = getDirectionTo(getCreaturePosition(cid), getCreaturePosition(target))
if getDistanceBetween(getCreaturePosition(cid), getCreaturePosition(target)) > att_distance then
if (getDistanceBetween(getCreaturePosition(cid), getCreaturePosition(target)) > att_distance + config.away_dist) then
doCreatureSetStorage(cid, config.storages.tgt, -1)
return false
end
doCreatureSetNoMove(cid, false)
local toPos = getPosByDir(getCreaturePosition(cid), dir, 1)
toPos.stackpos = 253
if getThingFromPos(toPos).uid == 0 then
doMoveCreature(cid, dir)
end
else
doCreatureSetNoMove(cid, true)
doCreatureSetLookDirection(cid, dir)
setDamage(cid, target)
end
end
doTargetCombatHealth(cid, target, COMBAT_PHYSICALDAMAGE, -5, -20, CONST_ME_DRAWBLOOD)

 

 

 

Feito isso, agora crie um arquivo chamado monsters.lua dentro de creaturescripts/scripts, e cole isso dentro

 

 

local config = {
    storages = {time = 5553, tgt = 5554},
    attRange = 1,
}

function onThink(cid)
if not isCreature(cid) then
return false
end
if getCreatureStorage(cid, config.storages.tgt) == -1 then
setTarget(cid)
else
if isCreature(getCreatureStorage(cid, config.storages.tgt)) then
if getCreatureStorage(cid, config.storages.time) - os.time() <= 0 then
doCreatureSetStorage(cid, config.storages.time, os.time() + 1)
attack(cid, getCreatureStorage(cid, config.storages.tgt), config.attRange)
end
else
doCreatureSetStorage(cid, config.storages.tgt, -1)
end
end
end

function onAttack(cid, target) if isPlayer(target) then if getCreatureStorage(cid, config.storages.tgt) ~= target then return false end end return true end

 

 

 

Pronto é isso, você tem um pequeno framework configurável para fazer seus monstros se matarem.

Para implementar o script no monstro basta ir no arquivo .xml dos monstros que deseja incluir esse sistema e colocar, logo após as defense, a tag:

  <script>
      <event name="minionatt"/>
      <event name="minion"/>
  </script>

Abaixo um exemplo de utilização do framework, simulando uma luta de "raças" entre dwarfs e orcs de diferentes tipos:

 

 

giphy.gif

 

giphy.gif

 

 

 

O código está bem auto explicativo. Qualquer dúvida me avisem.

Espero que gostem.

 

Abraços,

Editado por Skulls
Link para o comentário
Compartilhar em outros sites

O sistema parece estar bom, porem o jeito que você escreve seus códigos é ruim. uma dica, quando for criar um código ao invés de fazer:



> if (true) then
>> if (true) then
>>> if (true) then
>>>> if (true) then
>>>>> Código
>>>> end
>>> end
>> end
> end

Crie seus código assim:



> if (false) then
> return
> end

> if (false) then
> return
> end

> if (false) then
> return
> end

> if (false) then
> return
> end

> Código


Assim facilita muito a leitura, e intendimento e manutenção do código.


Link para o comentário
Compartilhar em outros sites

 

O sistema parece estar bom, porem o jeito que você escreve seus códigos é ruim. uma dica, quando for criar um código ao invés de fazer:

> if (true) then
>>  if (true) then
>>>  if (true) then
>>>>  if (true) then 
>>>>>  Código
>>>> end
>>> end
>> end
> end

Crie seus código assim:

> if (false) then
> return
> end

> if (false) then
> return
> end

> if (false) then
> return
> end

> if (false) then
> return
> end

>  Código

Assim facilita muito a leitura, e intendimento e manutenção do código.

 

Bom, eu entendo o seu posicionamento. Mas ai eu acho que é mais uma questão de gosto. Eu gosto de ler os códigos linearmente, por isso escrevo da forma que escrevo, do meu ponto de vista fica mais fácil pra mim verificar tudo que é feito escrevendo em cascata.

 

Mas, vou aceitar a sugestão pois, em termos didáticos, é mais fácil ensinar/mostrar um código para alguém com a sua forma de escrita.

 

Valeu.

 

@@Marco Oliveira

Obrigado cara!

 

Abraços,

editei o que achei pertinente com relação a sugestão do banana.

 

Editado por Skulls
Link para o comentário
Compartilhar em outros sites

ficou realmente bom, acredito que o onThink se tornaria pesado pra esse caso mas não tiro o mérito da forma que vc utilizou. A função verify é facilmente editável e isso é um ponto ultra positivo pois permite fácil implementação com tabelas pra setar raças atacáveis e evitar minions atacando bosses (nome diferente)

Só fica aqui uma questão pessoal: pq não permitir que a setTarget varie de monstro pra monstro? Orcs odeiam trolls mas eles odeiam muito mais os humanos, por exemplo.

Link para o comentário
Compartilhar em outros sites

ficou realmente bom, acredito que o onThink se tornaria pesado pra esse caso mas não tiro o mérito da forma que vc utilizou. A função verify é facilmente editável e isso é um ponto ultra positivo pois permite fácil implementação com tabelas pra setar raças atacáveis e evitar minions atacando bosses (nome diferente)

 

Só fica aqui uma questão pessoal: pq não permitir que a setTarget varie de monstro pra monstro? Orcs odeiam trolls mas eles odeiam muito mais os humanos, por exemplo.

Set target varie de que forma de monstro para monstro?

De qualquer forma minha settarget ficou meio durona mesmo, mas é pq pro que eu preciso só é necessário que ele dê preferencia a criaturas do que a players.

 

Obrigado pelo comentário. Você acha que ficaria pesado? Eu tava achando, mas agora to na duvida. Eu fiz um test clean (com server vazio) com pra la de mil monstros e rodou liso em um pc normal, não dedicado e não servidor.

Editado por Skulls
Link para o comentário
Compartilhar em outros sites

É algo de complexidade n^2 no pior caso, n no melhor caso e nlogn de caso médio, considerando que tem varias coisas rodando em paralelo não é o ideal rs.

Link para o comentário
Compartilhar em outros sites

  • 1 year later...

@Skulls

ola, tentei usar esse código mas na hora de rodar esta dando este erro:

 o que pode ser?

Distro: TFS 0.4

 

Screenshot_1.png

 

e mesmo se eu ignoro esses erros e tento criar o monstro que eu coloquei as tags de evento me aparece o erro abaixo:

 

Screenshot_2.png

 

Screenshot_1.png.708923430a5bf6bb950bc456e4332325.png

Screenshot_2.png.d8cca5318b7bb029fdc379441b5aa2dd.png

Editado por fefuxd
Link para o comentário
Compartilhar em outros sites

  • 3 months later...
  • 7 months later...
×
×
  • Criar Novo...