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.
610 lines
19 KiB
610 lines
19 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 "hsTypes.h" |
|
#include "pnKeyedObject/plKey.h" |
|
#include "hsTemplates.h" |
|
#include "hsStream.h" |
|
#include "plLinkEffectsMgr.h" |
|
#include "pnMessage/plEventCallbackMsg.h" |
|
#include "pnMessage/plTimeMsg.h" |
|
#include "pnMessage/plPlayerPageMsg.h" |
|
#include "plMessage/plLinkToAgeMsg.h" |
|
#include "plMessage/plTransitionMsg.h" |
|
#include "plgDispatch.h" |
|
#include "hsResMgr.h" |
|
#include "hsTimer.h" |
|
#include "pnNetCommon/plNetApp.h" |
|
#include "plNetClient/plNetClientMgr.h" |
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "plNetTransport/plNetTransportMember.h" |
|
#include "plVault/plVault.h" |
|
#include "plNetClient/plNetLinkingMgr.h" |
|
#include "plAgeLoader/plAgeLoader.h" |
|
#include "pnSceneObject/plCoordinateInterface.h" |
|
#include "pnMessage/plWarpMsg.h" |
|
#include "pnKeyedObject/plFixedKey.h" |
|
|
|
// chronicle var |
|
#define kCleftSolved L"CleftSolved" |
|
|
|
#include "plAvatar/plArmatureMod.h" |
|
#include "plAvatar/plAvatarTasks.h" |
|
#include "plAvatar/plAGAnim.h" |
|
#include "plMessage/plAvatarMsg.h" |
|
#include "plMessage/plLoadAgeMsg.h" |
|
|
|
plLinkEffectsMgr::plLinkEffectsMgr() |
|
{ |
|
} |
|
|
|
plLinkEffectsMgr::~plLinkEffectsMgr() |
|
{ |
|
int i; |
|
for( i = 0; i < fLinks.GetCount(); i++ ) |
|
{ |
|
hsRefCnt_SafeUnRef(fLinks[i]); |
|
} |
|
for( i = 0; i < fWaitlist.GetCount(); i++ ) |
|
{ |
|
hsRefCnt_SafeUnRef(fWaitlist[i]); |
|
} |
|
for( i = 0; i < fDeadlist.GetCount(); i++ ) |
|
{ |
|
hsRefCnt_SafeUnRef(fDeadlist[i]); |
|
} |
|
} |
|
|
|
void plLinkEffectsMgr::Init() |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plPseudoLinkEffectMsg::Index(), GetKey()); |
|
} |
|
|
|
plLinkEffectsTriggerMsg *plLinkEffectsMgr::IFindLinkTriggerMsg(plKey linkKey) |
|
{ |
|
int i; |
|
for (i = 0; i < fLinks.GetCount(); i++) |
|
{ |
|
if (fLinks[i]->GetLinkKey() == linkKey) |
|
return fLinks[i]; |
|
} |
|
return nil; |
|
} |
|
|
|
void plLinkEffectsMgr::IAddLink(plLinkEffectsTriggerMsg *msg) |
|
{ |
|
hsRefCnt_SafeRef(msg); |
|
fLinks.Append(msg); |
|
} |
|
|
|
void plLinkEffectsMgr::IAddWait(plLinkEffectsTriggerMsg *msg) |
|
{ |
|
hsRefCnt_SafeRef(msg); |
|
fWaitlist.Append(msg); |
|
} |
|
|
|
void plLinkEffectsMgr::IAddDead(plLinkEffectsTriggerMsg *msg) |
|
{ |
|
hsRefCnt_SafeRef(msg); |
|
fDeadlist.Append(msg); |
|
} |
|
|
|
void plLinkEffectsMgr::IAddPsuedo(plPseudoLinkEffectMsg *msg) |
|
{ |
|
hsRefCnt_SafeRef(msg); |
|
fPseudolist.Append(msg); |
|
} |
|
|
|
hsBool plLinkEffectsMgr::IHuntWaitlist(plLinkEffectsTriggerMsg *msg) |
|
{ |
|
int i; |
|
hsBool found = false; |
|
for (i = fWaitlist.GetCount() - 1; i >= 0; i--) |
|
{ |
|
if (fWaitlist[i] == msg) |
|
{ |
|
found = true; |
|
hsRefCnt_SafeUnRef(fWaitlist[i]); |
|
fWaitlist.Remove(i); |
|
plNetApp::GetInstance()->DebugMsg("Received backup LinkEffectsTriggerMsg. Never got remote trigger!\n"); |
|
} |
|
} |
|
|
|
return found || IHuntWaitlist(msg->GetLinkKey()); |
|
} |
|
|
|
hsBool plLinkEffectsMgr::IHuntWaitlist(plKey linkKey) |
|
{ |
|
int i; |
|
hsBool found = false; |
|
for (i = fWaitlist.GetCount() - 1; i >= 0; i--) |
|
{ |
|
if (fWaitlist[i]->GetLinkKey() == linkKey) |
|
{ |
|
found = true; |
|
IAddDead(fWaitlist[i]); |
|
|
|
hsRefCnt_SafeUnRef(fWaitlist[i]); |
|
fWaitlist.Remove(i); |
|
plNetApp::GetInstance()->DebugMsg("Received remote LinkEffectsTriggerMsg. Awaiting backup.\n"); |
|
} |
|
} |
|
|
|
return found; |
|
} |
|
|
|
hsBool plLinkEffectsMgr::IHuntDeadlist(plLinkEffectsTriggerMsg *msg) |
|
{ |
|
int i; |
|
hsBool found = false; |
|
for (i = fDeadlist.GetCount() - 1; i >= 0; i--) |
|
{ |
|
if (fDeadlist[i] == msg) |
|
{ |
|
found = true; |
|
hsRefCnt_SafeUnRef(fDeadlist[i]); |
|
fDeadlist.Remove(i); |
|
plNetApp::GetInstance()->DebugMsg("Received backup LinkEffectsTriggerMsg. Cleanly ignoring since we received remote trigger.\n"); |
|
} |
|
} |
|
|
|
return found; |
|
} |
|
|
|
|
|
|
|
void plLinkEffectsMgr::ISendAllReadyCallbacks() |
|
{ |
|
int i; |
|
for (i = fLinks.GetCount() - 1; i >= 0; i--) |
|
{ |
|
if (fLinks[i]->fEffects <= 0) |
|
{ |
|
if (fLinks[i]->IsLeavingAge()) |
|
{ |
|
if (fLinks[i]->GetLinkKey() == plNetClientApp::GetInstance()->GetLocalPlayerKey()) |
|
{ |
|
plLinkOutUnloadMsg* lam = TRACKED_NEW plLinkOutUnloadMsg; // derived from LoadAgeMsg |
|
lam->SetAgeFilename( NetCommGetAge()->ageDatasetName ); |
|
lam->AddReceiver(plNetClientMgr::GetInstance()->GetKey()); |
|
lam->SetPlayerID(plNetClientMgr::GetInstance()->GetPlayerID()); |
|
lam->Send(); |
|
} |
|
} |
|
else |
|
{ |
|
plLinkInDoneMsg* lid = TRACKED_NEW plLinkInDoneMsg; |
|
lid->AddReceiver(fLinks[i]->GetLinkKey()); |
|
lid->SetBCastFlag(plMessage::kPropagateToModifiers); |
|
lid->Send(); |
|
|
|
if (fLinks[i]->GetLinkKey() == plNetClientApp::GetInstance()->GetLocalPlayerKey()) |
|
{ |
|
plLinkInDoneMsg* lid = TRACKED_NEW plLinkInDoneMsg; |
|
lid->AddReceiver(plNetClientMgr::GetInstance()->GetKey()); |
|
lid->Send(); |
|
} |
|
} |
|
|
|
hsRefCnt_SafeUnRef(fLinks[i]); |
|
fLinks.Remove(i); |
|
|
|
hsStatusMessage("Done - removing link FX msg\n"); |
|
} |
|
} |
|
} |
|
|
|
hsBool plLinkEffectsMgr::MsgReceive(plMessage *msg) |
|
{ |
|
plNetClientMgr* nc = plNetClientMgr::GetInstance(); |
|
plNetLinkingMgr* lm = plNetLinkingMgr::GetInstance(); |
|
|
|
plPseudoLinkEffectMsg* pSeudoMsg = plPseudoLinkEffectMsg::ConvertNoRef(msg); |
|
if (pSeudoMsg) |
|
{ |
|
// verify valid avatar and "link" objects |
|
if (!pSeudoMsg->fAvatarKey) |
|
return true; |
|
if (!pSeudoMsg->fLinkObjKey) |
|
return true; |
|
if (!pSeudoMsg->fLinkObjKey->ObjectIsLoaded()) |
|
return true; |
|
if (!plNetClientMgr::GetInstance()->IsAPlayerKey(pSeudoMsg->fAvatarKey)) |
|
return true; |
|
// send the trigger message to the avatar... |
|
plPseudoLinkAnimTriggerMsg* pMsg = TRACKED_NEW plPseudoLinkAnimTriggerMsg(true, pSeudoMsg->fAvatarKey); |
|
pMsg->SetSender(GetKey()); |
|
pMsg->Send(); |
|
IAddPsuedo(pSeudoMsg); |
|
} |
|
|
|
plPseudoLinkAnimCallbackMsg* pSeudoCallback = plPseudoLinkAnimCallbackMsg::ConvertNoRef(msg); |
|
if (pSeudoCallback) |
|
{ |
|
// warp the avatar to his new position |
|
plPseudoLinkEffectMsg* pMsg = IFindPseudo(pSeudoCallback->fAvatarKey); |
|
if (pMsg) |
|
{ |
|
plSceneObject* pObj = plSceneObject::ConvertNoRef(pMsg->fLinkObjKey->ObjectIsLoaded()); |
|
if (pObj && pObj->GetCoordinateInterface()) |
|
{ |
|
hsMatrix44 mat = pObj->GetCoordinateInterface()->GetLocalToWorld(); |
|
// create message |
|
plWarpMsg* pMsg = TRACKED_NEW plWarpMsg(mat); |
|
pMsg->SetWarpFlags(plWarpMsg::kFlushTransform); |
|
pMsg->AddReceiver(pSeudoCallback->fAvatarKey); |
|
plUoid U(kVirtualCamera1_KEY); |
|
plKey pCamKey = hsgResMgr::ResMgr()->FindKey(U); |
|
if (pCamKey) |
|
{ |
|
pMsg->AddReceiver(pCamKey); |
|
} |
|
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes |
|
// now make him re-appear |
|
plPseudoLinkAnimTriggerMsg* pTrigMsg = TRACKED_NEW plPseudoLinkAnimTriggerMsg(false, pSeudoCallback->fAvatarKey); |
|
pTrigMsg->SetSender(GetKey()); |
|
pTrigMsg->Send(); |
|
IRemovePseudo(pSeudoCallback->fAvatarKey); |
|
|
|
} |
|
} |
|
} |
|
plLinkEffectsTriggerPrepMsg *tpMsg = plLinkEffectsTriggerPrepMsg::ConvertNoRef(msg); |
|
if (tpMsg) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Received LinkEffectsTriggerPREPMsg\n"); |
|
IAddWait(tpMsg->GetTrigger()); |
|
plLinkEffectPrepBCMsg *bcpMsg = TRACKED_NEW plLinkEffectPrepBCMsg; |
|
bcpMsg->fLeavingAge = tpMsg->fLeavingAge; |
|
bcpMsg->fLinkKey = tpMsg->fLinkKey; |
|
bcpMsg->Send(); |
|
|
|
return true; |
|
} |
|
|
|
plLinkEffectsTriggerMsg* pTriggerMsg = plLinkEffectsTriggerMsg::ConvertNoRef(msg); |
|
if (pTriggerMsg) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Received LinkEffectsTriggerMsg, local=%d, linkingIn=%d, stealth=%d", |
|
!msg->HasBCastFlag(plMessage::kNetNonLocal), |
|
!pTriggerMsg->IsLeavingAge(), pTriggerMsg->GetInvisLevel()); |
|
|
|
plKey linkKey = pTriggerMsg->GetLinkKey(); |
|
if (linkKey == nil) |
|
return true; |
|
|
|
if ((linkKey != nc->GetLocalPlayerKey()) && |
|
(!pTriggerMsg->IsLeavingAge())) |
|
{ |
|
if (IHuntDeadlist(pTriggerMsg)) // Just an obselete safety trigger |
|
return true; |
|
|
|
if (!IHuntWaitlist(pTriggerMsg)) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Unexpected linkEffectsTriggerMsg. Ignoring\n"); |
|
return true; |
|
} |
|
} |
|
|
|
plSceneObject *avatar = plSceneObject::ConvertNoRef(linkKey->ObjectIsLoaded()); |
|
if (avatar == nil) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Can't find avatar, mod=%s\n", linkKey->GetName()); |
|
return true; |
|
} |
|
|
|
// This is not the right place to catch this problem. |
|
// if (IFindLinkTriggerMsg(linkKey) != nil) |
|
// { |
|
// hsAssert(false, "Trying to link an Avatar already in the process of linking."); |
|
// return true; |
|
// } |
|
|
|
if (pTriggerMsg->GetInvisLevel() && linkKey != nc->GetLocalPlayerKey()) |
|
{ |
|
#ifdef PLASMA_EXTERNAL_RELEASE |
|
// Verify that the server told us that the invisible avatar is a CCR |
|
plNetTransportMember* mbr=nc->TransportMgr().GetMember(nc->TransportMgr().FindMember(linkKey)); |
|
if (!mbr || mbr->GetCCRLevel()<pTriggerMsg->GetInvisLevel()) |
|
{ |
|
plNetApp::StaticErrorMsg("Remote Avatar trying to be stealthy - REJECTING since he's not a CCR"); |
|
} |
|
else |
|
#endif |
|
{ |
|
plNetApp::StaticDebugMsg("Remote Avatar is in stealth mode - making invisible"); |
|
nc->MakeCCRInvisible(pTriggerMsg->GetLinkKey(), pTriggerMsg->GetInvisLevel()); |
|
} |
|
} |
|
|
|
if (pTriggerMsg->IsLeavingAge()) |
|
hsStatusMessage("Starting LinkOut FX\n"); |
|
else |
|
hsStatusMessage("Starting LinkIn FX\n"); |
|
|
|
plLinkEffectBCMsg *BCMsg = TRACKED_NEW plLinkEffectBCMsg(); |
|
BCMsg->fLinkKey = linkKey; |
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kLeavingAge, pTriggerMsg->IsLeavingAge()); |
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kSendCallback, true); |
|
|
|
// Check if you have a Yeesha book, and mute sound if you don't. |
|
// 'CleftSolved' gets set when you click on the linking panel in the cleft, |
|
// so we use that instead of checking KILevel. |
|
// Also, check if you're going to/from the ACA, or through the fissure, and mute sound if you are. |
|
if (linkKey == nc->GetLocalPlayerKey()) |
|
{ |
|
if(lm) { |
|
const char *ageName = lm->GetAgeLink()->GetAgeInfo()->GetAgeFilename(); |
|
const char *prevAgeName = lm->GetPrevAgeLink()->GetAgeInfo()->GetAgeFilename(); |
|
|
|
bool linkToStartup = ageName && !stricmp(ageName, kStartUpAgeFilename ); // To Startup |
|
bool linkFromStartup = prevAgeName && !stricmp(prevAgeName, kStartUpAgeFilename); // Leaving Startup |
|
|
|
bool cleftSolved = VaultHasChronicleEntry( kCleftSolved ); |
|
|
|
bool linkToACA = ageName && !stricmp(ageName, kAvCustomizationFilename); |
|
bool linkFromACA = prevAgeName && !stricmp(prevAgeName, kAvCustomizationFilename); |
|
|
|
bool linkToFissureDrop = lm && |
|
lm->GetAgeLink()->HasSpawnPt() && |
|
lm->GetAgeLink()->SpawnPoint().GetName() && |
|
!stricmp(lm->GetAgeLink()->SpawnPoint().GetName(), kCleftAgeLinkInPointFissureDrop); |
|
bool linkToDsntFromShell = lm && |
|
lm->GetAgeLink()->HasSpawnPt() && |
|
lm->GetAgeLink()->SpawnPoint().GetTitle() && |
|
!stricmp(lm->GetAgeLink()->SpawnPoint().GetTitle(), kDescentLinkFromShell); |
|
if ( linkToACA || linkFromACA || linkToStartup || linkFromStartup || linkToFissureDrop || linkToDsntFromShell) |
|
{ |
|
BCMsg->SetLinkFlag(plLinkEffectBCMsg::kMute); |
|
} |
|
} |
|
} |
|
|
|
BCMsg->SetSender(GetKey()); |
|
if (msg->HasBCastFlag(plMessage::kNetNonLocal)) |
|
// terminate the remote cascade and start a new (local) cascade, since the rcvr is localOnly and will reject remote msgs |
|
BCMsg->SetBCastFlag(plMessage::kNetStartCascade); |
|
plgDispatch::MsgSend(BCMsg); |
|
|
|
if (!pTriggerMsg->IsLeavingAge()) // Avatar is currently entering a new age |
|
{ |
|
plATCAnim *linkInAnim = nil; |
|
plKey linkInAnimKey = nil; |
|
const plArmatureMod *avMod = plArmatureMod::ConvertNoRef(avatar->GetModifierByType(plArmatureMod::Index())); |
|
if (pTriggerMsg->HasBCastFlag(plMessage::kNetNonLocal)) |
|
{ |
|
// Remote trigger, they should tell us how they linked in. |
|
linkInAnimKey = pTriggerMsg->GetLinkInAnimKey(); |
|
} |
|
else |
|
{ |
|
// this is our backup trigger we send ourselves. We've already received the remote player's SDL. |
|
linkInAnimKey = avMod ? avMod->GetLinkInAnimKey() : nil; |
|
} |
|
linkInAnim = plATCAnim::ConvertNoRef(linkInAnimKey ? linkInAnimKey->ObjectIsLoaded() : nil); |
|
|
|
if (avMod && linkInAnim) |
|
{ |
|
plAvOneShotTask *task = TRACKED_NEW plAvOneShotTask(linkInAnim->GetName(), false, false, nil); |
|
task->fBackwards = true; |
|
task->fDisableLooping = true; |
|
task->fDisablePhysics = false; |
|
(TRACKED_NEW plAvTaskMsg(GetKey(), avMod->GetKey(), task))->Send(); |
|
} |
|
|
|
} |
|
|
|
IAddLink(pTriggerMsg); // refs the avatarMod |
|
|
|
// Dummy msg sent after the broadcast. This guarantees we have a callback to actually trigger the |
|
// link, plus we know any effect broadcast messages will have processed before this (and therefore |
|
// have told us to wait for them.) |
|
pTriggerMsg->fEffects++; |
|
plLinkCallbackMsg *dummyMsg = TRACKED_NEW plLinkCallbackMsg(); |
|
dummyMsg->AddReceiver(GetKey()); |
|
dummyMsg->fLinkKey = linkKey; |
|
plgDispatch::MsgSend(dummyMsg); |
|
|
|
return true; |
|
} |
|
|
|
// callbacks from linkout events |
|
plLinkCallbackMsg* pLinkCallbackMsg = plLinkCallbackMsg::ConvertNoRef(msg); |
|
if (pLinkCallbackMsg) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Received pLinkCallbackMsg, localmsg=%d\n", |
|
!msg->HasBCastFlag(plMessage::kNetNonLocal)); |
|
|
|
static char str[ 128 ]; |
|
plLinkEffectsTriggerMsg *pTriggerMsg = IFindLinkTriggerMsg(pLinkCallbackMsg->fLinkKey); |
|
if (pTriggerMsg == nil) |
|
{ |
|
hsAssert(true, "Received a callback for an avatar that isn't linking."); |
|
return true; |
|
} |
|
|
|
if (--pTriggerMsg->fEffects == 0) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("All link callbacks received.\n" ); |
|
plgDispatch::Dispatch()->RegisterForExactType(plTimeMsg::Index(), GetKey()); |
|
} |
|
else if (pTriggerMsg->fEffects < 0 ) |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("Too many link callbacks received for avatar %s. Ignoring extras.\n", |
|
pTriggerMsg->GetLinkKey()->GetName()); |
|
} |
|
else |
|
{ |
|
plNetApp::GetInstance()->DebugMsg("%d link callbacks left until avatar %s links...\n", |
|
pTriggerMsg->fEffects, pTriggerMsg->GetLinkKey()->GetName()); |
|
} |
|
return true; |
|
} |
|
|
|
plTimeMsg *time = plTimeMsg::ConvertNoRef(msg); |
|
if (time) // This is how we know we're out of the render function, and it's safe to pageIn/Out nodes |
|
{ |
|
plgDispatch::Dispatch()->UnRegisterForExactType(plTimeMsg::Index(), GetKey()); |
|
ISendAllReadyCallbacks(); |
|
|
|
return true; |
|
} |
|
|
|
plPlayerPageMsg *pageMsg = plPlayerPageMsg::ConvertNoRef(msg); |
|
if (pageMsg) |
|
{ |
|
if (pageMsg->fUnload) |
|
{ |
|
IHuntWaitlist(pageMsg->fPlayer); |
|
return true; |
|
} |
|
|
|
const hsScalar kMaxTimeForLinkTrigger = 30.f; |
|
|
|
// If we're not loading state, we're in the age. So this avatar coming in must be linking in. |
|
// If the player is us, no prep is necessary. |
|
if (!plNetClientApp::GetInstance()->IsLoadingInitialAgeState() && |
|
(pageMsg->fPlayer != nc->GetLocalPlayerKey())) |
|
{ |
|
plLinkEffectsTriggerMsg *trigMsg = TRACKED_NEW plLinkEffectsTriggerMsg; |
|
trigMsg->SetLeavingAge(false); |
|
trigMsg->SetLinkKey(pageMsg->fPlayer); |
|
|
|
// Send off the prep message right away |
|
plLinkEffectsTriggerPrepMsg *trigPrepMsg = TRACKED_NEW plLinkEffectsTriggerPrepMsg; |
|
trigPrepMsg->fLinkKey = pageMsg->fPlayer; |
|
trigPrepMsg->SetTrigger(trigMsg); |
|
trigPrepMsg->Send(GetKey()); |
|
|
|
// Send off a delayed safety trigger. If things are going along properly, |
|
// we'll get a trigger from the player linking in before this message is |
|
// received, and we'll ignore it. |
|
double timeToDeliver = hsTimer::GetSysSeconds() + kMaxTimeForLinkTrigger; |
|
trigMsg->SetTimeStamp(timeToDeliver); |
|
trigMsg->Send(GetKey()); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return hsKeyedObject::MsgReceive(msg); |
|
} |
|
|
|
void plLinkEffectsMgr::WaitForEffect(plKey linkKey, hsScalar time) |
|
{ |
|
plLinkEffectsTriggerMsg *msg = IFindLinkTriggerMsg(linkKey); |
|
if (msg == nil) |
|
{ |
|
hsAssert(true, "Request to wait on an effect for an avatar that isn't linking."); |
|
return; |
|
} |
|
|
|
msg->fEffects++; |
|
plLinkCallbackMsg *callback = TRACKED_NEW plLinkCallbackMsg(); |
|
callback->fEvent = kStop; |
|
callback->fRepeats = 0; |
|
callback->fLinkKey = linkKey; |
|
double timeToDeliver = hsTimer::GetSysSeconds() + time; |
|
callback->SetTimeStamp( timeToDeliver ); |
|
callback->Send( GetKey() ); |
|
} |
|
|
|
plMessage *plLinkEffectsMgr::WaitForEffect(plKey linkKey) |
|
{ |
|
plLinkEffectsTriggerMsg *msg = IFindLinkTriggerMsg(linkKey); |
|
if (msg == nil) |
|
{ |
|
hsAssert(true, "Request to wait on an effect for an avatar that isn't linking."); |
|
return nil; |
|
} |
|
|
|
msg->fEffects++; |
|
|
|
plLinkCallbackMsg *callback = TRACKED_NEW plLinkCallbackMsg(); |
|
callback->fEvent = kStop; |
|
callback->fRepeats = 0; |
|
callback->fLinkKey = linkKey; |
|
callback->AddReceiver( GetKey() ); |
|
return callback; |
|
} |
|
|
|
void plLinkEffectsMgr::WaitForPseudoEffect(plKey linkKey, hsScalar time) |
|
{ |
|
plPseudoLinkEffectMsg* msg = IFindPseudo(linkKey); |
|
if (msg == nil) |
|
{ |
|
hsAssert(true, "Request to wait on an fake effect for an avatar that isn't fake linking."); |
|
return; |
|
} |
|
|
|
plPseudoLinkAnimCallbackMsg* callback = TRACKED_NEW plPseudoLinkAnimCallbackMsg(); |
|
callback->fAvatarKey = linkKey; |
|
double timeToDeliver = hsTimer::GetSysSeconds() + time; |
|
callback->SetTimeStamp( timeToDeliver ); |
|
callback->Send( GetKey() ); |
|
} |
|
|
|
plPseudoLinkEffectMsg* plLinkEffectsMgr::IFindPseudo(plKey avatarKey) |
|
{ |
|
int i; |
|
for (i = 0; i < fPseudolist.GetCount(); i++) |
|
{ |
|
if (fPseudolist[i]->fAvatarKey == avatarKey) |
|
return fPseudolist[i]; |
|
} |
|
return nil; |
|
|
|
} |
|
|
|
void plLinkEffectsMgr::IRemovePseudo(plKey avatarKey) |
|
{ |
|
int i; |
|
for (i = 0; i < fPseudolist.GetCount(); i++) |
|
{ |
|
if (fPseudolist[i]->fAvatarKey == avatarKey) |
|
{ |
|
fPseudolist.Remove(i); |
|
return; |
|
} |
|
} |
|
|
|
} |