Monstros duelando entre si

Skulls
Por Skulls
em Globalevents e Spells

Skulls

Coordenador de Eventos
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 26/02/07Posts: 859Gênero: Masculino

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,

Marco Oliveira

avatar
Visconde
Visconde

INFOS

Grupo: ViscondeRegistrado: 21/06/15Posts: 331Gênero: Masculino

Muito bom, reputado!

BananaFight

Allahu Akbar
avatar
Conde
Conde

INFOS

Grupo: CondeRegistrado: 14/02/13Posts: 702Gênero: Masculino

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.


Skulls

Coordenador de Eventos
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 26/02/07Posts: 859Gênero: Masculino

 

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.

 

Administrador

xTibia 2017
avatar
Administrador
Administrador

INFOS

Grupo: AdministradorRegistrado: 09/07/05Posts: 5780Gênero: Outro

Ótima contribuição, como sempre!

DICA

Utilize botão @UP, no início de seu tópico, para atualizar o destaque de seu tópico em "Tópicos Recentes" na index, fará com que mais pessoas o vejam.

 

 

Skulls

Coordenador de Eventos
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 26/02/07Posts: 859Gênero: Masculino

Ótima contribuição, como sempre!

Obrigado!

Night Wolf

Coordenador de Desenvolvimento
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 14/02/14Posts: 341Gênero: MasculinoChar no Tibia: Night Wolf

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.

I9AtE9T.png
/NW

Skulls

Coordenador de Eventos
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 26/02/07Posts: 859Gênero: Masculino

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.

Night Wolf

Coordenador de Desenvolvimento
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 14/02/14Posts: 341Gênero: MasculinoChar no Tibia: Night Wolf

Pra você ter noção eu fiz uma spell que mandava o player andar pra frente durante 20 segundos, essa daqui e ela funcionou liso, mas quando passei prum sv ela travava :/

I9AtE9T.png
/NW

Skulls

Coordenador de Eventos
avatar
Herói
Herói

INFOS

Grupo: HeróiRegistrado: 26/02/07Posts: 859Gênero: Masculino

É 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.

fefuxd

avatar
Campones
Campones

INFOS

Grupo: CamponesRegistrado: 13/01/17Posts: 28Gênero: Masculino

@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

raizinhoxd

avatar
Campones
Campones

INFOS

Grupo: CamponesRegistrado: 11/03/17Posts: 2Gênero: Masculino

ola, tudo bom,, gostaria de saber melhor os passos para fazer isso. podeira me ajudar??

Heartless1993

avatar
Campones
Campones

INFOS

Grupo: CamponesRegistrado: 31/05/17Posts: 1

não funcionou distro 0.36

leeeo

avatar
Campones
Campones

INFOS

Grupo: CamponesRegistrado: 27/01/17Posts: 14Gênero: Masculino

não funcionou em distro 1.2