You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
958 lines
25 KiB
958 lines
25 KiB
14 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||
|
or by snail mail at:
|
||
|
Cyan Worlds, Inc.
|
||
|
14617 N Newport Hwy
|
||
|
Mead, WA 99021
|
||
|
|
||
|
*==LICENSE==*/
|
||
|
#include "plAvCallbackAction.h" // havok-contaminated file: must go first
|
||
|
|
||
|
// singular
|
||
|
#include "plAvBrainGeneric.h"
|
||
|
|
||
|
// local
|
||
|
#include "plAnimStage.h"
|
||
|
#include "plArmatureMod.h"
|
||
|
// #include "plAvatarTasks.h"
|
||
|
#include "plAvTask.h"
|
||
|
#include "plAvTaskBrain.h"
|
||
|
#include "plAvBrainHuman.h"
|
||
|
#include "plAGAnimInstance.h"
|
||
|
#include "plMatrixChannel.h"
|
||
|
|
||
|
// global
|
||
|
#include "hsTimer.h"
|
||
|
#include "plgDispatch.h"
|
||
|
|
||
|
// other
|
||
14 years ago
|
#include "pnNetCommon/plSDLTypes.h"
|
||
|
#include "pnMessage/plCameraMsg.h"
|
||
|
#include "pnMessage/plNotifyMsg.h"
|
||
|
#include "plMessage/plAvatarMsg.h"
|
||
|
#include "plMessage/plInputEventMsg.h"
|
||
|
#include "plMessage/plSimStateMsg.h"
|
||
|
#include "plMessage/plConsoleMsg.h"
|
||
|
#include "plPipeline/plDebugText.h"
|
||
|
#include "plInputCore/plAvatarInputInterface.h"
|
||
|
#include "plMessage/plInputIfaceMgrMsg.h"
|
||
14 years ago
|
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
#include "plAvatarMgr.h"
|
||
14 years ago
|
#include "plStatusLog/plStatusLog.h"
|
||
14 years ago
|
#endif
|
||
|
|
||
|
hsBool plAvBrainGeneric::fForce3rdPerson = true;
|
||
|
const hsScalar plAvBrainGeneric::kDefaultFadeIn = 6.f; // 1/6th of a second to fade in
|
||
|
const hsScalar plAvBrainGeneric::kDefaultFadeOut = 0.f; // instant fade out.
|
||
|
|
||
|
// plAvBrainGeneric ----------------
|
||
|
// -----------------
|
||
|
plAvBrainGeneric::plAvBrainGeneric()
|
||
|
: fRecipient(nil),
|
||
|
fStages(TRACKED_NEW plAnimStageVec),
|
||
|
fCurStage(0),
|
||
|
fType(kGeneric),
|
||
|
fExitFlags(kExitNormal),
|
||
|
fMode(kEntering),
|
||
|
fForward(true),
|
||
|
fStartMessage(nil),
|
||
|
fEndMessage(nil),
|
||
|
fFadeIn(0.0f),
|
||
|
fFadeOut(0.0f),
|
||
|
fMoveMode(kMoveRelative),
|
||
|
fCallbackAction(nil),
|
||
|
fBodyUsage(plAGAnim::kBodyUnknown)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// plAvBrainGeneric --------------------------------------
|
||
|
// -----------------
|
||
|
plAvBrainGeneric::plAvBrainGeneric(plAnimStageVec *stages,
|
||
|
plMessage *startMessage,
|
||
|
plMessage *endMessage,
|
||
|
plKey recipient,
|
||
|
UInt32 exitFlags,
|
||
|
float fadeIn,
|
||
|
float fadeOut,
|
||
|
MoveMode moveMode)
|
||
|
: plArmatureBrain(),
|
||
|
fRecipient(recipient),
|
||
|
fStages(stages),
|
||
|
fCurStage(0),
|
||
|
fType(kGeneric),
|
||
|
fExitFlags(exitFlags),
|
||
|
fMode(kEntering),
|
||
|
fForward(true),
|
||
|
fStartMessage(startMessage),
|
||
|
fEndMessage(endMessage),
|
||
|
fFadeIn(fadeIn),
|
||
|
fFadeOut(fadeOut),
|
||
|
fMoveMode(moveMode),
|
||
|
fCallbackAction(nil),
|
||
|
fBodyUsage(plAGAnim::kBodyUnknown)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// plAvBrainGeneric
|
||
|
plAvBrainGeneric::plAvBrainGeneric(UInt32 exitFlags, float fadeIn, float fadeOut, MoveMode moveMode)
|
||
|
: fRecipient(nil),
|
||
|
fStages(nil),
|
||
|
fCurStage(0),
|
||
|
fType(kGeneric),
|
||
|
fExitFlags(exitFlags),
|
||
|
fMode(kEntering),
|
||
|
fForward(true),
|
||
|
fStartMessage(nil),
|
||
|
fEndMessage(nil),
|
||
|
fFadeIn(fadeIn),
|
||
|
fFadeOut(fadeOut),
|
||
|
fMoveMode(moveMode),
|
||
|
fCallbackAction(nil),
|
||
|
fBodyUsage(plAGAnim::kBodyUnknown)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// ~plAvBrainGeneric ----------------
|
||
|
// ------------------
|
||
|
plAvBrainGeneric::~plAvBrainGeneric()
|
||
|
{
|
||
|
int fNumStages = fStages->size();
|
||
|
|
||
|
for(int i = 0; i < fNumStages; i++)
|
||
|
{
|
||
|
plAnimStage *stage = (*fStages)[i];
|
||
|
(*fStages)[i] = nil;
|
||
|
stage->Detach(fAvMod);
|
||
|
delete stage;
|
||
|
}
|
||
|
delete fStages;
|
||
|
}
|
||
|
|
||
|
// Activate -------------------------------------------
|
||
|
// ---------
|
||
|
void plAvBrainGeneric::Activate(plArmatureModBase *avMod)
|
||
|
{
|
||
|
plArmatureBrain::Activate(avMod);
|
||
|
|
||
|
if ((GetType() == kEmote || GetType() == kAFK || GetType() == kSitOnGround) && fAvMod->IsLocalAvatar())
|
||
|
{
|
||
|
plInputIfaceMgrMsg* msg = TRACKED_NEW plInputIfaceMgrMsg(plInputIfaceMgrMsg::kDisableClickables );
|
||
|
plgDispatch::MsgSend(msg);
|
||
|
}
|
||
|
|
||
|
int numStages = fStages->size();
|
||
|
if (!numStages)
|
||
|
return;
|
||
|
plAnimStage *stage = (*fStages)[fCurStage];
|
||
|
|
||
|
bool useFadeIn = fFadeIn > 0.0f;
|
||
|
float initialBlend = useFadeIn ? 0.0f : 1.0f;
|
||
|
|
||
|
if (GetType() == kEmote)
|
||
|
((plArmatureMod*)avMod)->SendBehaviorNotify(plHBehavior::kBehaviorTypeEmote,true);
|
||
|
double worldTime = hsTimer::GetSysSeconds();
|
||
|
|
||
|
if (fMoveMode == kMoveRelative || fMoveMode == kMoveAbsolute)
|
||
|
{
|
||
|
// enable kinematic... ignore outside forces... but still collide with detector regions
|
||
|
fAvMod->EnablePhysicsKinematic( true );
|
||
|
}
|
||
|
else if(fMoveMode == kMoveStandstill)
|
||
|
{
|
||
|
// Avatar stands still automatically now, so we do nothing here
|
||
|
}
|
||
|
if (stage->Attach(fAvMod, this, initialBlend, worldTime))
|
||
|
{
|
||
|
if(fStartMessage)
|
||
|
{
|
||
|
fStartMessage->Send();
|
||
|
fStartMessage = nil;
|
||
|
}
|
||
|
|
||
|
if (plAvBrainGeneric::fForce3rdPerson && fAvMod->IsLocalAvatar())
|
||
|
{
|
||
|
// create message to force 3rd person mode
|
||
|
plCameraMsg* pMsg = TRACKED_NEW plCameraMsg;
|
||
|
pMsg->SetBCastFlag(plMessage::kBCastByExactType);
|
||
|
pMsg->SetCmd(plCameraMsg::kResponderSetThirdPerson);
|
||
|
pMsg->SetBCastFlag(plMessage::kNetPropagate, false);
|
||
|
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (fType == kLadder && fAvMod->IsLocalAvatar())
|
||
|
plAvatarInputInterface::GetInstance()->SetLadderMode();
|
||
|
|
||
|
if (fReverseFBControlsOnRelease)
|
||
|
fAvMod->SetReverseFBOnIdle(true);
|
||
|
}
|
||
|
|
||
|
hsBool plAvBrainGeneric::IsRunningTask()
|
||
|
{
|
||
|
if ( fStages->size() > 0 )
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool plAvBrainGeneric::MatchAnimNames(const char *names[], int count)
|
||
|
{
|
||
|
if (count != GetStageCount())
|
||
|
return false;
|
||
|
|
||
|
int i;
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
if (strcmp(names[i], GetStage(i)->GetAnimName()))
|
||
|
return false; // different names.
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Apply ----------------------------------------------------
|
||
|
// ------
|
||
|
hsBool plAvBrainGeneric::Apply(double time, hsScalar elapsed)
|
||
|
{
|
||
|
hsBool result = false;
|
||
|
|
||
|
switch(fMode)
|
||
|
{
|
||
|
case kAbort:
|
||
|
break;
|
||
|
case kEntering:
|
||
|
case kFadingIn:
|
||
|
result = IProcessFadeIn(time, elapsed);
|
||
|
break;
|
||
|
case kExit:
|
||
|
case kFadingOut:
|
||
|
// go through the fade logic whether or not we actually need a fade;
|
||
|
// centralizes some exit conditions.
|
||
|
result = IProcessFadeOut(time, elapsed);
|
||
|
break;
|
||
|
case kNormal:
|
||
|
result = IProcessNormal(time, elapsed);
|
||
|
break;
|
||
|
}
|
||
|
plArmatureBrain::Apply(time, elapsed);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Deactivate -----------------------
|
||
|
// -----------
|
||
|
void plAvBrainGeneric::Deactivate()
|
||
|
{
|
||
|
if (fEndMessage)
|
||
|
{
|
||
|
fEndMessage->Send();
|
||
|
fEndMessage = nil;
|
||
|
}
|
||
|
if (fMode != kAbort) // we're being forcibly removed...
|
||
|
IExitMoveMode();
|
||
|
|
||
|
if (fMoveMode == kMoveRelative || fMoveMode == kMoveAbsolute)
|
||
|
{
|
||
|
// re-enable normal physics... outside forces affect us
|
||
|
fAvMod->EnablePhysicsKinematic( false );
|
||
|
}
|
||
|
else if (fMoveMode == kMoveStandstill)
|
||
|
{
|
||
|
// Avatar stands still automaticaly now, so we do nothing here
|
||
|
}
|
||
|
|
||
|
if (fType == plAvBrainGeneric::kLadder && fAvMod->IsLocalAvatar())
|
||
|
{
|
||
|
plAvatarInputInterface::GetInstance()->ClearLadderMode();
|
||
|
}
|
||
|
|
||
|
if (fReverseFBControlsOnRelease)
|
||
|
fAvMod->SetReverseFBOnIdle(false);
|
||
|
|
||
|
if (plAvBrainGeneric::fForce3rdPerson && fAvMod->IsLocalAvatar())
|
||
|
{
|
||
|
// create message to force 3rd person mode
|
||
|
plCameraMsg* pMsg = TRACKED_NEW plCameraMsg;
|
||
|
pMsg->SetBCastFlag(plMessage::kBCastByExactType);
|
||
|
pMsg->SetBCastFlag(plMessage::kNetPropagate, false);
|
||
|
pMsg->SetCmd(plCameraMsg::kResponderUndoThirdPerson);
|
||
|
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes
|
||
|
}
|
||
|
|
||
|
plArmatureBrain::Deactivate();
|
||
|
|
||
|
if ((GetType() == kEmote || GetType() == kAFK || GetType() == kSitOnGround) && fAvMod->IsLocalAvatar())
|
||
|
{
|
||
|
plInputIfaceMgrMsg* msg = TRACKED_NEW plInputIfaceMgrMsg(plInputIfaceMgrMsg::kEnableClickables );
|
||
|
plgDispatch::MsgSend(msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// GETRECIPIENT
|
||
|
plKey plAvBrainGeneric::GetRecipient()
|
||
|
{
|
||
|
return fRecipient;
|
||
|
}
|
||
|
|
||
|
// SETRECIPIENT
|
||
|
void plAvBrainGeneric::SetRecipient(const plKey &recipient)
|
||
|
{
|
||
|
fRecipient = recipient;
|
||
|
}
|
||
|
|
||
|
// RELAYNOTIFYMSG
|
||
|
bool plAvBrainGeneric::RelayNotifyMsg(plNotifyMsg *msg)
|
||
|
{
|
||
|
if(fRecipient)
|
||
|
{
|
||
|
msg->AddReceiver(fRecipient);
|
||
|
msg->Send();
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// IGetAnimDelta ------------------------------------------------
|
||
|
// --------------
|
||
|
float plAvBrainGeneric::IGetAnimDelta(double time, float elapsed)
|
||
|
{
|
||
|
float delta = 0.0f;
|
||
|
plAnimStage *curStage = (*fStages)[fCurStage];
|
||
|
plAnimStage::ForwardType forward = curStage->GetForwardType();
|
||
|
plAnimStage::BackType back = curStage->GetBackType();
|
||
|
bool fwdIsDown = (fReverseFBControlsOnRelease && fAvMod->IsFBReversed()) ? fAvMod->BackwardKeyDown() : fAvMod->ForwardKeyDown();
|
||
|
hsBool backIsDown = (fReverseFBControlsOnRelease && fAvMod->IsFBReversed()) ? fAvMod->ForwardKeyDown() : fAvMod->BackwardKeyDown();
|
||
|
|
||
|
// forward with a key down gets top priority
|
||
|
if(forward == plAnimStage::kForwardKey && fwdIsDown)
|
||
|
{
|
||
|
// key drive forward, forward key is down
|
||
|
delta = elapsed;
|
||
|
fForward = true;
|
||
|
} else if(back == plAnimStage::kBackKey && backIsDown)
|
||
|
{
|
||
|
// key drive back, back key is down
|
||
|
delta = -elapsed;
|
||
|
fForward = false;
|
||
|
} else if (forward == plAnimStage::kForwardAuto && fForward)
|
||
|
{
|
||
|
// auto drive forward
|
||
|
delta = elapsed;
|
||
|
} else if (back == plAnimStage::kBackAuto && ! fForward)
|
||
|
{
|
||
|
// auto drive backward
|
||
|
delta = -elapsed;
|
||
|
}
|
||
|
return delta;
|
||
|
}
|
||
|
|
||
|
// IProcessNormal -------------------------------------------------
|
||
|
// ---------------
|
||
|
hsBool plAvBrainGeneric::IProcessNormal(double time, float elapsed)
|
||
|
{
|
||
|
plAnimStage *curStage = (*fStages)[fCurStage];
|
||
|
if(curStage)
|
||
|
{
|
||
|
float animDelta = IGetAnimDelta(time, elapsed); // how far to move the anim (may be negative)
|
||
|
float overage;
|
||
|
hsBool done = curStage->MoveRelative(time, animDelta, overage, fAvMod);
|
||
|
|
||
|
if(done)
|
||
|
{
|
||
|
bool forward = animDelta > 0.0f;
|
||
|
int nextStage = forward ? curStage->GetNextStage(fCurStage) : curStage->GetPrevStage(fCurStage);
|
||
|
|
||
|
if((nextStage == -1) || (nextStage >= fStages->size()))
|
||
|
{
|
||
|
// ran off one end; we're done.
|
||
|
fMode = kExit;
|
||
|
} else {
|
||
|
ISwitchStages(fCurStage, nextStage, overage, false, 0.0f, 1.0f, -1.0f, time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
} else {
|
||
|
// current stage is missing; abort
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// IProcessFadeIn -------------------------------------------------
|
||
|
// ---------------
|
||
|
hsBool plAvBrainGeneric::IProcessFadeIn(double time, float elapsed)
|
||
|
{
|
||
|
plAnimStage *curStage = (*fStages)[fCurStage];
|
||
|
|
||
|
if(fMode != kFadingIn)
|
||
|
{
|
||
|
bool needFade = fFadeIn != 0.0f;
|
||
|
|
||
|
if(fFadeIn == 0.0f)
|
||
|
{
|
||
|
IEnterMoveMode(time); // if fadeIn's not zero, we have to wait until fade's done
|
||
|
// before animating
|
||
|
} else {
|
||
|
curStage->GetAnimInstance()->Fade(1.0f, fFadeIn);
|
||
|
}
|
||
|
fMode = kFadingIn;
|
||
|
} else {
|
||
|
float curBlend = curStage->GetAnimInstance()->GetBlend();
|
||
|
if(curBlend == 1.0f)
|
||
|
{
|
||
|
IEnterMoveMode(time);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// IProcessFadeOut -------------------------------------------------
|
||
|
// ----------------
|
||
|
hsBool plAvBrainGeneric::IProcessFadeOut(double time, float elapsed)
|
||
|
{
|
||
|
plAnimStage *curStage = (*fStages)[fCurStage];
|
||
|
|
||
|
if(fMode != kFadingOut)
|
||
|
{
|
||
|
// haven't actually started fading; see if we need to
|
||
|
if(fFadeOut > 0.0f)
|
||
|
{
|
||
|
plAGAnimInstance *curAnim = curStage->GetAnimInstance();
|
||
|
if(curAnim)
|
||
|
{
|
||
|
curStage->GetAnimInstance()->Fade(0.0f, fFadeOut);
|
||
|
IExitMoveMode();
|
||
|
fMode = kFadingOut;
|
||
|
} else {
|
||
|
fMode = kAbort;
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
curStage->Detach(fAvMod);
|
||
|
IExitMoveMode();
|
||
|
fMode = kAbort;
|
||
|
}
|
||
|
} else {
|
||
|
// already fading; just keeping looking for the anim to zero out.
|
||
|
float curBlend = curStage->GetAnimInstance()->GetBlend();
|
||
|
if(curBlend == 0.0f)
|
||
|
{
|
||
|
curStage->Detach(fAvMod);
|
||
|
fMode = kAbort;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// ISwitchStages ---------------------------------------------------------------------------------------------------
|
||
|
// --------------
|
||
|
hsBool plAvBrainGeneric::ISwitchStages(int oldStageNum, int newStageNum, float delta, hsBool setTime, float newTime,
|
||
|
float fadeNew, hsScalar fadeOld, double worldTime)
|
||
|
{
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
char sbuf[256];
|
||
|
sprintf(sbuf,"ISwitchStage - old=%d new=%d (fCurStage=%d)",oldStageNum,newStageNum,fCurStage);
|
||
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf);
|
||
|
#endif
|
||
|
if(oldStageNum != newStageNum) {
|
||
|
plAnimStage *newStage = fStages->at(newStageNum);
|
||
|
plAnimStage *oldStage = fStages->at(oldStageNum);
|
||
|
if(setTime)
|
||
|
newStage->SetLocalTime(newTime);
|
||
|
|
||
|
hsAssert(oldStageNum < fStages->size(), "PLAVBRAINGENERIC: Stage out of range.");
|
||
|
|
||
|
oldStage->Detach(fAvMod);
|
||
|
newStage->Attach(fAvMod, this, 1.0f, worldTime);
|
||
|
|
||
|
fCurStage = newStageNum;
|
||
|
fAvMod->DirtySynchState(kSDLAvatar, 0); // write our new stage to the server
|
||
|
}
|
||
|
if(setTime) {
|
||
|
plAnimStage *curStage = fStages->at(fCurStage);
|
||
|
curStage->SetLocalTime(newTime);
|
||
|
}
|
||
|
|
||
|
if(fMoveMode == kMoveRelative)
|
||
|
fAvMod->GetRootAnimator()->Reset(worldTime);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void plAvBrainGeneric::IEnterMoveMode(double time)
|
||
|
{
|
||
|
if(fMoveMode == kMoveRelative)
|
||
|
{
|
||
|
fAvMod->GetRootAnimator()->Enable(true);
|
||
|
fAvMod->GetRootAnimator()->Reset(time);
|
||
|
}
|
||
|
fMode = kNormal;
|
||
|
}
|
||
|
|
||
|
void plAvBrainGeneric::IExitMoveMode()
|
||
|
{
|
||
|
if(fAvMod)
|
||
|
{
|
||
|
if(fMoveMode == kMoveRelative)
|
||
|
{
|
||
|
if(fAvMod->GetRootAnimator())
|
||
|
fAvMod->GetRootAnimator()->Enable(false);
|
||
|
}
|
||
|
|
||
|
if (fFadeOut == 0.f)
|
||
|
{
|
||
|
// if we're exiting instantly (no fade out) then the end of the animation expects to line up with
|
||
|
// the first frame of the idle animation, so we need to reset it.
|
||
|
plAvBrainHuman *brain = plAvBrainHuman::ConvertNoRef(fAvMod->FindBrainByClass(plAvBrainHuman::Index()));
|
||
|
if (brain)
|
||
|
brain->ResetIdle();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// MESSAGE HANDLING
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// MsgReceive -------------------------------------
|
||
|
// -----------
|
||
|
hsBool plAvBrainGeneric::MsgReceive(plMessage *msg)
|
||
|
{
|
||
|
hsBool result = false;
|
||
|
|
||
|
plAvBrainGenericMsg *genMsg = plAvBrainGenericMsg::ConvertNoRef(msg);
|
||
|
//plAvExitModeMsg *exitMsg = plAvExitModeMsg::ConvertNoRef(msg);
|
||
|
plAvTaskMsg *taskMsg = plAvTaskMsg::ConvertNoRef(msg);
|
||
|
plControlEventMsg *ctrlMsg = plControlEventMsg::ConvertNoRef(msg);
|
||
|
|
||
|
|
||
|
if(genMsg)
|
||
|
{
|
||
|
result = IHandleGenBrainMsg(genMsg);
|
||
|
}
|
||
|
// else if(exitMsg) {
|
||
|
// fMode = kExit;
|
||
|
// result = true;
|
||
|
// }
|
||
|
else if (taskMsg) {
|
||
|
result = IHandleTaskMsg(taskMsg);
|
||
|
}
|
||
|
else if (ctrlMsg && (fExitFlags & kExitAnyInput) ) {
|
||
|
fMode = kExit;
|
||
|
}
|
||
|
|
||
|
if(result == false) // if still haven't handled msg
|
||
|
{
|
||
|
if(fMode == kExit) // if we're exiting
|
||
|
{
|
||
|
result = fAvMod->GetNextBrain(this)->MsgReceive(msg); // pass msg to next brain
|
||
|
} else { // otherwise
|
||
|
result = plArmatureBrain::MsgReceive(msg); // pass msg to base class
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// IHandleGenBrainMsg -----------------------------------------------------
|
||
|
// -------------------
|
||
|
hsBool plAvBrainGeneric::IHandleGenBrainMsg(const plAvBrainGenericMsg *msg)
|
||
|
{
|
||
|
hsBool setTime = msg->fSetTime;
|
||
|
float newTime = msg->fNewTime;
|
||
|
hsBool setDirection = msg->fSetDirection;
|
||
|
bool newDirection = msg->fNewDirection ? true : false;
|
||
|
double worldTime = hsTimer::GetSysSeconds();
|
||
|
|
||
|
switch(msg->fType)
|
||
|
{
|
||
|
case plAvBrainGenericMsg::kGotoStage:
|
||
|
{
|
||
|
int wantStage = msg->fWhichStage;
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
char sbuf[256];
|
||
|
sprintf(sbuf,"GenericMsg - Goto Stage %d (oldstage %d)",wantStage,fCurStage);
|
||
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf);
|
||
|
#endif
|
||
|
if(wantStage == -1) {
|
||
|
fMode = kExit;
|
||
|
} else {
|
||
|
int count = fStages->size();
|
||
|
if(wantStage < count && wantStage >= 0)
|
||
|
{
|
||
|
ISwitchStages(fCurStage, wantStage, 0.0f, setTime, newTime, 1.0f, -1.0f, worldTime);
|
||
|
// direction is set within the brain, not the stage
|
||
|
if(setDirection)
|
||
|
fForward = newDirection;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case plAvBrainGenericMsg::kNextStage:
|
||
|
{
|
||
|
int wantStage = fCurStage + 1;
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
char sbuf[256];
|
||
|
sprintf(sbuf,"GenericMsg - Next Stage %d (oldstage %d)",wantStage,fCurStage);
|
||
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf);
|
||
|
#endif
|
||
|
if(wantStage == fStages->size())
|
||
|
{
|
||
|
fMode = kExit; // walked off the end of the brain
|
||
|
} else {
|
||
|
ISwitchStages(fCurStage, wantStage, 0.0f, setTime, newTime, 1.0f, -1.0f, worldTime);
|
||
|
if(setDirection)
|
||
|
fForward = newDirection;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case plAvBrainGenericMsg::kPrevStage:
|
||
|
{
|
||
|
int wantStage = fCurStage - 1;
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
char sbuf[256];
|
||
|
sprintf(sbuf,"GenericMsg - PrevStage %d (oldstage %d)",wantStage,fCurStage);
|
||
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf);
|
||
|
#endif
|
||
|
if(wantStage < 0)
|
||
|
{
|
||
|
fMode = kExit; // walked off the beginning of the brain
|
||
|
} else {
|
||
|
ISwitchStages(fCurStage, wantStage, 0.0f, setTime, 0.0f, 1.0f, -1.0f, worldTime);
|
||
|
if(setDirection)
|
||
|
fForward = newDirection;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
#ifdef DEBUG_MULTISTAGE
|
||
|
default:
|
||
|
{
|
||
|
char sbuf[256];
|
||
|
sprintf(sbuf,"GenericMsg - Unknown command %d ",msg->fType);
|
||
|
plAvatarMgr::GetInstance()->GetLog()->AddLine(sbuf);
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
hsBool plAvBrainGeneric::IHandleTaskMsg(plAvTaskMsg *msg)
|
||
|
{
|
||
|
plAvTask *task = msg->GetTask();
|
||
|
plAvTaskBrain *brainTask = plAvTaskBrain::ConvertNoRef(task);
|
||
|
|
||
|
if(brainTask)
|
||
|
{
|
||
|
plArmatureBrain * brain = brainTask->GetBrain();
|
||
|
|
||
|
if(brain)
|
||
|
{
|
||
|
if(fExitFlags & kExitNewBrain)
|
||
|
{
|
||
|
// RULE 1: if kExitNewBrain, exit on any new brain
|
||
|
fMode = kExit;
|
||
|
return false; // we didn't consume the message
|
||
|
} else {
|
||
|
plAvBrainGeneric * gBrain = plAvBrainGeneric::ConvertNoRef(brain);
|
||
|
|
||
|
if(gBrain && IBrainIsCompatible(gBrain))
|
||
|
{
|
||
|
// RULE 2: if not kExitNewBrain and brain is compatible, apply it
|
||
|
QueueTask(brainTask);
|
||
|
return true;
|
||
|
} else {
|
||
|
if(fMode == kExit || fMode == kFadingOut)
|
||
|
{
|
||
|
// RULE 3: if brain is incompatible and we're exiting anyway,
|
||
|
// queue it to be next
|
||
|
fAvMod->GetNextBrain(this)->QueueTask(brainTask);
|
||
|
return true;
|
||
|
}
|
||
|
// RULE 4: if brain is incompatible and we're still running, ignore.
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// no brain; it's an exit task, exit and CONSUME it.
|
||
|
fMode = kExit;
|
||
|
return true;
|
||
|
}
|
||
|
} else {
|
||
|
// note that this check has to come after the brain task check; if it's a brain
|
||
|
// task we need to examine it so we can say whether we consumed it or not.
|
||
|
// popbrain messages get consumed, even if we exit on any task.
|
||
|
if(fExitFlags & kExitAnyTask)
|
||
|
{
|
||
|
// RULE 4: if kExitAnyTask, exit on any task (but if it was an exit brain task,
|
||
|
// make sure to consume it )
|
||
|
fMode = kExit;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RULE 4: if brain is incompatible and we're still running, ignore.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool plAvBrainGeneric::IBrainIsCompatible(plAvBrainGeneric *otherBrain)
|
||
|
{
|
||
|
plAGAnim::BodyUsage otherUsage = otherBrain->GetBodyUsage();
|
||
|
|
||
|
switch(fBodyUsage)
|
||
|
{
|
||
|
case plAGAnim::kBodyUnknown:
|
||
|
return false;
|
||
|
break;
|
||
|
case plAGAnim::kBodyFull:
|
||
|
return false;
|
||
|
break;
|
||
|
case plAGAnim::kBodyUpper:
|
||
|
if(otherUsage == plAGAnim::kBodyLower)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
break;
|
||
|
case plAGAnim::kBodyLower:
|
||
|
if(otherUsage == plAGAnim::kBodyUpper)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
break;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// READ/WRITE
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Write ----------------------------------------------------
|
||
|
// ------
|
||
|
void plAvBrainGeneric::Write(hsStream *stream, hsResMgr *mgr)
|
||
|
{
|
||
|
plArmatureBrain::Write(stream, mgr);
|
||
|
int numStages = fStages->size();
|
||
|
stream->WriteSwap32(numStages);
|
||
|
|
||
|
for(int i = 0; i < numStages; i++)
|
||
|
{
|
||
|
plAnimStage *stage = (*fStages)[i];
|
||
|
plCreatable *cre = reinterpret_cast<plCreatable *>(stage);
|
||
|
mgr->WriteCreatable(stream, cre); // save base state
|
||
|
// ** replace this with Write(..)
|
||
|
stage->SaveAux(stream, mgr); // save ephemeral state
|
||
|
}
|
||
|
|
||
|
stream->WriteSwap32(fCurStage);
|
||
|
stream->WriteSwap32(fType);
|
||
|
stream->WriteSwap32(fExitFlags);
|
||
|
stream->WriteByte(fMode);
|
||
|
stream->Writebool(fForward);
|
||
|
|
||
|
if(fStartMessage) {
|
||
|
stream->WriteBool(true);
|
||
|
mgr->WriteCreatable(stream, fStartMessage);
|
||
|
} else {
|
||
|
stream->WriteBool(false);
|
||
|
}
|
||
|
|
||
|
if(fEndMessage) {
|
||
|
stream->WriteBool(true);
|
||
|
mgr->WriteCreatable(stream, fEndMessage);
|
||
|
} else {
|
||
|
stream->WriteBool(false);
|
||
|
}
|
||
|
|
||
|
stream->WriteSwapScalar(fFadeIn);
|
||
|
stream->WriteSwapScalar(fFadeOut);
|
||
|
stream->WriteByte(fMoveMode);
|
||
|
stream->WriteByte(fBodyUsage);
|
||
|
mgr->WriteKey(stream, fRecipient);
|
||
|
}
|
||
|
|
||
|
// Read ----------------------------------------------------
|
||
|
// -----
|
||
|
void plAvBrainGeneric::Read(hsStream *stream, hsResMgr *mgr)
|
||
|
{
|
||
|
plArmatureBrain::Read(stream, mgr);
|
||
|
int numStages = stream->ReadSwap32();
|
||
|
|
||
|
for(int i = 0; i < numStages; i++)
|
||
|
{
|
||
|
plCreatable *created = mgr->ReadCreatable(stream); // load base state
|
||
|
plAnimStage *stage = reinterpret_cast<plAnimStage *>(created);
|
||
|
// Replace this with Read(..)
|
||
|
stage->LoadAux(stream, mgr, 0.0); // load ephemeral state
|
||
|
|
||
|
fStages->push_back(stage);
|
||
|
}
|
||
|
|
||
|
fCurStage = stream->ReadSwap32();
|
||
|
fType = static_cast<plAvBrainGeneric::BrainType>(stream->ReadSwap32());
|
||
|
fExitFlags = stream->ReadSwap32();
|
||
|
fMode = static_cast<Mode>(stream->ReadByte());
|
||
|
fForward = stream->Readbool();
|
||
|
|
||
|
if(stream->ReadBool()) {
|
||
|
fStartMessage = plMessage::ConvertNoRef(mgr->ReadCreatable(stream));
|
||
|
} else {
|
||
|
fStartMessage = nil;
|
||
|
}
|
||
|
if(stream->ReadBool()) {
|
||
|
fEndMessage = plMessage::ConvertNoRef(mgr->ReadCreatable(stream));
|
||
|
} else {
|
||
|
fEndMessage = nil;
|
||
|
}
|
||
|
|
||
|
fFadeIn = stream->ReadSwapScalar();
|
||
|
fFadeOut = stream->ReadSwapScalar();
|
||
|
fMoveMode = static_cast<MoveMode>(stream->ReadByte());
|
||
|
fBodyUsage = static_cast<plAGAnim::BodyUsage>(stream->ReadByte());
|
||
|
fRecipient = mgr->ReadKey(stream);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// MINOR FNs / GETTERS & SETTERS
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// LeaveAge ---------------------
|
||
|
// ---------
|
||
|
hsBool plAvBrainGeneric::LeaveAge()
|
||
|
{
|
||
|
IExitMoveMode();
|
||
|
|
||
|
fMode = kAbort;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// AddStage --------------------------------------
|
||
|
// ---------
|
||
|
int plAvBrainGeneric::AddStage(plAnimStage *stage)
|
||
|
{
|
||
|
if(!fStages)
|
||
|
fStages = TRACKED_NEW plAnimStageVec;
|
||
|
fStages->push_back(stage);
|
||
|
return fStages->size() - 1;
|
||
|
}
|
||
|
|
||
|
// GetStageNum --------------------------------------
|
||
|
// ------------
|
||
|
int plAvBrainGeneric::GetStageNum(plAnimStage *stage)
|
||
|
{
|
||
|
int count = fStages->size();
|
||
|
for(int i = 0; i < count; i++)
|
||
|
{
|
||
|
plAnimStage *any = (*fStages)[i];
|
||
|
if(any == stage)
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// GetCurStageNum --------------------
|
||
|
// ---------------
|
||
|
int plAvBrainGeneric::GetCurStageNum()
|
||
|
{
|
||
|
return fCurStage;
|
||
|
}
|
||
|
|
||
|
// GetStageCount --------------------
|
||
|
// --------------
|
||
|
int plAvBrainGeneric::GetStageCount()
|
||
|
{
|
||
|
return fStages->size();
|
||
|
}
|
||
|
|
||
|
// GetStage ---------------------------------------
|
||
|
// ---------
|
||
|
plAnimStage * plAvBrainGeneric::GetStage(int which)
|
||
|
{
|
||
|
return fStages->at(which);
|
||
|
}
|
||
|
|
||
|
// GetCurStage ------------------------------
|
||
|
// ------------
|
||
|
plAnimStage * plAvBrainGeneric::GetCurStage()
|
||
|
{
|
||
|
return fStages->at(fCurStage);
|
||
|
}
|
||
|
|
||
|
// SetType -------------------------------------------------------------------------------
|
||
|
// --------
|
||
|
plAvBrainGeneric::BrainType plAvBrainGeneric::SetType(plAvBrainGeneric::BrainType newType)
|
||
|
{
|
||
|
BrainType oldType = fType;
|
||
|
fType = newType;
|
||
|
return oldType;
|
||
|
}
|
||
|
|
||
|
// GetType --------------------------------------------
|
||
|
// --------
|
||
|
plAvBrainGeneric::BrainType plAvBrainGeneric::GetType()
|
||
|
{
|
||
|
return fType;
|
||
|
}
|
||
|
|
||
|
plAGAnim::BodyUsage plAvBrainGeneric::GetBodyUsage()
|
||
|
{
|
||
|
return fBodyUsage;
|
||
|
}
|
||
|
|
||
|
void plAvBrainGeneric::SetBodyUsage(plAGAnim::BodyUsage bodyUsage)
|
||
|
{
|
||
|
fBodyUsage = bodyUsage;
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// DEBUGGING
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// DumpToDebugDisplay ----------------------------------------------------------------------------------------
|
||
|
// -------------------
|
||
|
void plAvBrainGeneric::DumpToDebugDisplay(int &x, int &y, int lineHeight, char *strBuf, plDebugText &debugTxt)
|
||
|
{
|
||
|
debugTxt.DrawString(x, y, "Brain type: Generic AKA Multistage");
|
||
|
y += lineHeight;
|
||
|
|
||
|
int stageCount = fStages->size();
|
||
|
for(int i = 0; i < stageCount; i++)
|
||
|
{
|
||
|
plAnimStage *stage = (*fStages)[i];
|
||
|
stage->DumpDebug(i == fCurStage, x, y, lineHeight, strBuf, debugTxt);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|