terça-feira, 1 de julho de 2008

E finalmente a #&@#@ da criatura andou.

Olááááá terráqueos.

Pois bem, tive meu primeiro final de semana de férias. Porém foram dias de explorar as catacumbas esquecidas do meu kitinete e dar uma faxina lá.

Porém, consegui fazer o bendito monstro andar. O comando WalkWayPoint parece não fazer nada. Detodas as formas que o coloquei ele não fazia meu monstro andar pelos WayPoints, eu então experimentei o comando ActionRandomWalk e funcionou perfeitamente, mas eu não estava satisfeito, então criei um script para o evento OnHeartBeat da criatura para ela mover de um WayPoint para outro, andar aleatoriamente por um tempo, mover para o próximo WayPoint, andar aleatoriamente e assim seguir o ciclo.

Aqui está o cript que criei:

//:://////////////////////////////////////////////////
//:: sh_c_heartbeat
/*
Default OnHeartbeat script for NPCs.

This script causes NPCs to perform default animations
while not otherwise engaged.

This script duplicates the behavior of the default
script and just cleans up the code and removes
redundant conditional checks.

*/
//:://////////////////////////////////////////////////
//:: Copyright (c) 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 12/22/2002
//:://////////////////////////////////////////////////
// ChazM 6/20/05 if is encounter crature no longer checked - ambient anims flag set on spawn instead.
// ChazM 1/6/06 modified call to WalkWayPoints()
// ChazM 3/6/06 fixed AI level exit condition bug
// ChazM 3/23/06 added DoDebug(); no functionality changes
// SubHeaven 06/28/2008 added custom waypoint control

#include "nw_i0_generic"
#include "ginc_debug"

void DoDebug(string sMessage)
{

//if ((GetTag(OBJECT_SELF) != "3030_dwarf") && (GetTag(OBJECT_SELF) != "c_cow"))
return;
PrettyDebug("NW_C2_DEFAULT1 " + GetName(OBJECT_SELF) + ": " + sMessage);
}

void main()
{
DoDebug("I'm haveing a heartbeat!!!");
// * if not runnning normal or better Ai then exit for performance reasons
if (GetAILevel() == AI_LEVEL_VERY_LOW)
{
DoDebug("goodness gracious - i have very low AI!");
//SendMessageToPC(GetFirstPC(), "goodness gracious - i have very low AI!");
return;
}

// Buff ourselves up right away if we should
if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))
{
// This will return TRUE if an enemy was within 40.0 m
// and we buffed ourselves up instantly to respond --
// simulates a spellcaster with protections enabled
// already.
if(TalentAdvancedBuff(40.0))
{
// This is a one-shot deal
SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);

//SendMessageToPC(GetFirstPC(), "GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY) e TalentAdvancedBuff(40.0");

// This return means we skip sending the user-defined
// heartbeat signal in this one case.
return;
}
}


//PrettyDebug("Entering big if");
if(GetHasEffect(EFFECT_TYPE_SLEEP))
{
// If we're asleep and this is the result of sleeping
// at night, apply the floating 'z's visual effect
// every so often

if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
{
effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
if(d10() > 6)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
}
}
}
// If we have the 'constant' waypoints flag set, walk to the next
// waypoint.
else if ( GetWalkCondition(NW_WALK_FLAG_CONSTANT) )
{
DoDebug("Calling WalkWayPoints!");
//string sMensagem = "Calling WalkWayPoints!";
//SendMessageToPC(GetFirstPC(), sMensagem);
WalkWayPoints(TRUE, "heartbeat");
}

// Check to see if we should be playing default animations
// - make sure we don't have any current targets
else if ( !GetIsObjectValid(GetAttemptedAttackTarget())
&& !GetIsObjectValid(GetAttemptedSpellTarget())
// && !GetIsPostOrWalking())
&& !GetIsObjectValid(GetNearestSeenEnemy()))
{
DoDebug(" I'm gonna look at playing some animations.");
if (GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) || GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE) ||
GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
{
// This handles special attacking/fleeing behavior
// for omnivores & herbivores.
DoDebug("I'm gonna do something special!");
DetermineSpecialBehavior();
}
else if (!IsInConversation(OBJECT_SELF))
{
if (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
|| GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN))
//|| GetIsEncounterCreature())
{
DoDebug("I'm gonna play some ambient animations!");
//SpawnScriptDebugger();
PlayMobileAmbientAnimations();
}
else if (GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
{
DoDebug("I'm gonna play some immobile ambient animations!");
PlayImmobileAmbientAnimations();
}
else
{
DoDebug("I don't have any flags telling me to play animations.");
}
}
else
{
DoDebug("I must be in a conversation!");
}
}

// Send the user-defined event signal if specified
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
{
SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_HEARTBEAT));
}

//Recuperar o valor do contador global
int iContador = GetLocalInt(GetModule(), "i_hbCounter");

//Se o valor do contador é divisível por 20...
if ((iContador % 20) == 0 || GetLocalInt(OBJECT_SELF, "iWalking") == 0)
{
//Se a criatura não está em combate...
if (!GetIsInCombat(OBJECT_SELF))
{
//Recuperar a posição atual da criatura, incrementá-lo e
//procurar um Waypoint com essa numeração
int iAtual = GetLocalInt(OBJECT_SELF, "CurrWP");
iAtual = iAtual + 1;

string sLocal;

if (iAtual < 10)
{
sLocal = "WP_" + GetTag(OBJECT_SELF) + "_0" + IntToString(iAtual);
}
else
{
sLocal = "WP_" + GetTag(OBJECT_SELF) + "_" + IntToString(iAtual);
}

SendMessageToPC(GetFirstPC(), sLocal);
object oLocal = GetWaypointByTag(sLocal);

//Se não existe esse Waypoint e não é o primeiro,
//então procurar o primeiro Waypoint
if (oLocal == OBJECT_INVALID && iAtual != 1)
{
iAtual = 1;
sLocal = "WP_" + GetTag(OBJECT_SELF) + "_0" + IntToString(iAtual);
SendMessageToPC(GetFirstPC(), sLocal);
oLocal = GetWaypointByTag(sLocal);
}

//Se o local procurado é válido então...
if (oLocal != OBJECT_INVALID)
{
SendMessageToPC(GetFirstPC(), "oLocal != OBJECT_INVALID");
//Carregar o Waypoint
location lLocal = GetLocation(oLocal);

//Parar o que está fazendo
ClearAllActions();
//Ir até o Waypoint
//ActionMoveToLocation(lLocal);
ActionMoveToObject(oLocal);
//Mover-se aleatoriamente próximo ao Waypoint
ActionRandomWalk();

//Atualizar a posição atual
SetLocalInt(OBJECT_SELF, "CurrWP", iAtual);
}
//Senão, andar aleatoriamente no local
else
{
SendMessageToPC(GetFirstPC(), "oLocal == OBJECT_INVALID");
ActionRandomWalk();
}
}

SetLocalInt(OBJECT_SELF, "iWalking", 1);
}

}

Claro que o que eu realmente criei está comentado em português. Mas enfim, eu criei um contador no OnHeartBeat do módulo, para definir quando o código no OnHeartBeat da criatura será executado, no código acima, a cada 20 HeartBeat do módulo, eu executo o código no OnHeartBeat da criatura e com isso não fico fazendo os mesmos comandos a cada 6 segundos. Eu também criei duas variáveis na criatura, uma para armazenar em qual WayPoint ela está (CurrWP) e outra para indicar que a criatura já esta em movimento (iWalking). A CurrWP grava o numero do WayPoint em que a criatura está no momento, quando a criatura é criada, ela começa com valor 1 e eu então crio a tag "WP_Tag_01" e vou modificando apenas esse numero final para indicar pra onde a criatura está indo. Quando não eu não mais encontrar uma tag na sequência (Digamos que tenha criado 5 WayPoints e o programa procure o WP_tag_06) ele volta para o 1.
Como esse evento apenas ocorre a cada 20 HeartBeat do módulo, a criatura ficava estática logo depois do seu respawn, eu criei então a variável iWalking que começa com valor 0 e assim, mesmo que não tenha passado os 20 HeartBeat, se a criatura ainda não esta andando, o script executa os comandos e muda o valor de iWalking para 1, indicando que a criatura agora está andando normalmente pelo mapa. Porém, quando ele anda para outro WayPoint e executa o comando ActionRandomWalk, a criatura volta para o primeiro WayPoint e só então começa a andar aleatoriamente. Estranho... Mas pelo menos não ficou como uma estátua como antes. Depois vou tentar descobrir como resolver isso.

E pra finalizar esse post, está o script do OnHeartBeat do módulo:

// sh_m_heartbeat
/*
Script para o evento OnHeartBeat do modulo.

*/
//:://////////////////////////////////////////////////
//:: Copyright (c) 2008 SubHeaven World
//:: Created By: SubHeaven
//:: Created On: 06/28/2008
//:://////////////////////////////////////////////////

void main()
{
//Inclementar o contador de heartbeat. Esse contador serve para evitar
//que rotinas ligadas ao evento heartbeat de outros objetos sejam executadas
//a cada 6 segundos.
int iModuleCont = GetLocalInt(GetModule(), "i_hbCounter");

if (iModuleCont == 100)
iModuleCont = 1;
else
iModuleCont = iModuleCont + 1;

SetLocalInt(GetModule(), "i_hbCounter", iModuleCont);

//SendMessageToPC(GetFirstPC(), "HeartBeat " + IntToString(iModuleCont));
}

Nenhum comentário:

BlogBlogs.Com.Br