sábado, 12 de maio de 2012

Aula 8 - Um pouco sobre Volatiles

Aula 8 - Um pouco sobre Volatiles
Bom, primeiramente, para quem não sabe, volatile são os itens usáveis no jogo. São aqueles em que você clica com o botão direito do mouse ou joga um item em cima de outro e acontece algo. Na TMSRV, as volatiles são definidas na itemlist.csv onde ficam armazenados todos os itens do jogo. Era definido como um efeito, escrito assim:
EF_VOLATILE,ID

Um exemplo é:
525,Olho_Crescente,78.0,0.0.0.0.0,0,0,0,0,0,EF_VOLATILE,8,EF_GRID,0

O item "Olho Crescente" tem ID volatile 8. É um item que se usa, ou seja, clica com o direito, e vai realizar a função que está na VOLATILE 8.

Depois de muito tempo sem poder modificar esse tipo de coisa com facilidade, nós podemos criar/editar volatiles atuais. Na realidade, não editamos as atuais, apenas as desativamos e criamos outra por cima.
Por exemplo: o item Poeira de Ori já tem a função na TMSRV, certo? O que iriamos fazer é desativar a volatile atual da poeira e assim na nossa DLL adicionar conforme você quer, com as rates, funções novas, etc... 

Na DLL só muda uma coisa. Não é mais definido pela itemlist, e sim pelo ID do item. Na DLL que postei, tudo é controlado no arquivo Volatiles/VolatileControl.cpp


Criando uma nova Volatile
Uma nova volatile tem a seguinte definição:
void Volatile::NOMEDAVOLATILE(int clientid, int SrcSlot, int DstSlot, int warp)

Com isso você declarará no arquivo VolatileControl.h dentro da class Volatile assim:
void NOMEDAVOLATILE(int clientid, int SrcSlot, int DstSlot);
Não deverá usar o Volatile::

Iremos fazer o seguinte volatile completo: Caixa da Sabedoria, item ID 4117.

Bom, o nome do Volatile tem que ser autoexplicativo. Usaremos então: 
void Caixa_da_Sabedoria(int clientid, int SrcSlot, int DstSlot, int warp)
Isso você deve adicionar no VolatileControl.h dentro da class Volatile, ficando assim:
class Volatile {
public:
void Pedido_Armia(int clientid, int SrcSlot, int DstSlot, int warp);
void Pedido_Dungeon(int clientid, int SrcSlot, int DstSlot, int warp);
void Poeira_de_Ori(int clientid, int SrcSlot, int DstSlot);
void PacLac(int clientid, int SrcSlot, int DstSlot);
void Abre_Pac(int clientid, int SrcSlot, int DstSlot);
void Caixa_da_Sabedoria(int clientid, int SrcSlot, int DstSlot, int warp);
};
Ou seja, bem fácil, não é mesmo?

Após isso, criaremos um .cpp seguindo isso:
Em Name: você colocará: Caixa da Sabedoria. Uma observação que terei que fazer é sobre o Location.
Você deverá apertar "Browser" e logo após isso navegar até a pasta base do projeto. Vá na pasta Source/TMsrv/TMSrv_PacketProtocolV754/ e aperte selecionar. Se você não fizer isso, não poderá dar include nos headers.

Bom, após isso clique em Add
Adicione os headers DLLMain.h e VolatileControl.h assim:
nclude "DLLMain.h"
#include "VolatileControl.h"
#include "SendPackets.h"

Após isso adicionaremos a tal definição que falamos anteriormente:
void Volatile::Caixa_da_Sabedoria(int clientid, int SrcSlot, int DstSlot, int warp)
{
}

Adicionaremos o básico, que é a struct MOB e a declaração dos packets.
st_Mob *player = (st_Mob*)GetMobFromIndex(clientid);
SendPackets *send = new SendPackets();

Depois faremos o código normalmente, do jeito que sempre fazemos, pensando...
Bom, o item de quest é necessário:
Verificar level está dentro do limite 40~115.
Verificar se é arch/mortal

Para verificar o level utilizaremos:
if(player->bStatus.Level >= LEVEL MINIMO && player->bStatus.Level <= LEVEL MAXIMO)
{
// COMANDOS
} else {
// COMANDOS
}

Na dll que postei, não está definido a forma de verificar se é arch/mortal, mas normalmente é:
if(player->Equip[0].EFV2 == 1 /* Mortal */ || player->Equip[0].EFV2 == 2)
{
}

Após entrarmos em todas as condições, deveremos dar a experiência para o personagem, tirar o item, e atualizá-lo.
Na struct do mob temos uma variável que é para experiência do personagem e ela é player->Exp. Então é simples. Usaremos o operador +=
player->Exp += EXPERIÊNCIA ADICIONADA

A única forma de atualizar a experiência do personagem é usando:
GetCurrentScore(clientid);

Eu deixei uma função que retira a unidade se for possível ou apaga o item do inventário, e ela é essa:
void Funcoes::AmountMinus(int clientid, int slot)
{
st_Mob *player = (st_Mob*)GetMobFromIndex(clientid);
if(player->Inventory[slot].EF1 == 61)
if(player->Inventory[slot].EFV1 > 1)
player->Inventory[slot].EFV1 --;
else
player->Inventory[slot].Index = 0;
else if(player->Inventory[slot].EF2 == 61)
if(player->Inventory[slot].EFV2 > 1)
player->Inventory[slot].EFV2 --;
else
player->Inventory[slot].Index = 0;
else if(player->Inventory[slot].EF3 == 61)
if(player->Inventory[slot].EFV3 > 1)
player->Inventory[slot].EFV3 --;
else
player->Inventory[slot].Index = 0;
else 
player->Inventory[slot].Index = 0;
}

Então adicionaremos mais:
AmountMinus(clientid, SrcSlot);
Código por enquanto está assim:
void Volatiles::Caixa_da_Sabedoria(int clientid, int SrcSlot, int DstSlot, int warp)
{
st_Mob *player = (st_Mob*)GetMobFromIndex(clientid);
Funcoes *func = new Funcoes(); 
SendPackets *send = new SendPackets();
if(player->bStatus.Level >= 39 && player->bStatus.Level < 117)
{
if(player->Equip[0].EFV2 == 1 || player->Equip[0].EFV2 == 2)
{
player->Exp += 50000;
GetCurrentScore(clientid);
AmountMinus(clientid, SrcSlot);
} else {
SendClientMsg(clientid, "Apenas personagens mortais e archs!");
AmountMinus(clientid, SrcSlot);
return;
}
} else {
SendClientMsg(clientid, "Level inadequado!");
AmountMinus(clientid, SrcSlot);
return;
}
}

O que falta?

Atualizar com o SendAll(clientid);

Com tudo isso feito, iremos para o VolatileControl.cpp. Lá fica o controle.
Adicione um case com o ID do item (4117) abaixo do último case, antes do default:
case 4117:
vola->Caixa_da_Sabedoria(clientid, SrcSlot, DstSlot, warp);
break;

Entre no jogo e teste. Pronto, funcional.

Aproveitei minha hora dessa madrugada, 00:30~01:02 para criar essa aula, foi feita rapidamente então.. hehe, espero que gostem.

2 comentários: