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.
981 lines
29 KiB
981 lines
29 KiB
/*==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/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
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 { |
|
plAGAnimInstance *curAnim = curStage->GetAnimInstance(); |
|
if(curAnim) |
|
curAnim->Fade(1.0f, fFadeIn); |
|
} |
|
fMode = kFadingIn; |
|
} else { |
|
plAGAnimInstance *curAnim = curStage->GetAnimInstance(); |
|
float curBlend = 1.0f; |
|
if(curAnim) |
|
curBlend = curAnim->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) |
|
{ |
|
curAnim->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. |
|
plAGAnimInstance *curAnim = curStage->GetAnimInstance(); |
|
float curBlend = 0.0f; |
|
if(curAnim) |
|
curBlend = curAnim->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); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|