/*==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 .
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
#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"
#ifdef DEBUG_MULTISTAGE
#include "plAvatarMgr.h"
#include "plStatusLog/plStatusLog.h"
#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(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(created);
// Replace this with Read(..)
stage->LoadAux(stream, mgr, 0.0); // load ephemeral state
fStages->push_back(stage);
}
fCurStage = stream->ReadSwap32();
fType = static_cast(stream->ReadSwap32());
fExitFlags = stream->ReadSwap32();
fMode = static_cast(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(stream->ReadByte());
fBodyUsage = static_cast(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);
}
}