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.

325 lines
9.4 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/>.
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"
#include "plStatusLog/plStatusLog.h"
#include "plArmatureEffects.h"
#include "pfMessage/plArmatureEffectMsg.h"
#include "plMessage/plAnimCmdMsg.h"
#include "plMessage/plAvatarMsg.h"
#include "plArmatureMod.h"
#include "pnSceneObject/plAudioInterface.h"
#include "plAudio/plSound.h"
#include "plAudio/plAudioSystem.h"
#include "pfAudio/plRandomSoundMod.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
const char *plArmatureEffectsMgr::SurfaceStrings[] =
{
"Dirt",
"Puddle",
"Water",
"Tile",
"Metal",
"WoodBridge",
"RopeLadder",
"Grass",
"Brush",
"HardWood",
"Rug",
"Stone",
"Mud",
"MetalLadder",
"WoodLadder",
"DeepWater",
"Maintainer(Glass)",
"Maintainer(Stone)",
"Swimming",
"(none)" // Keep this one last
};
void plArmatureEffectsMgr::Read(hsStream *s, hsResMgr *mgr)
{
hsKeyedObject::Read(s, mgr);
int numEffects = s->ReadSwap32();
while (numEffects > 0)
{
plRefMsg *msg = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, -1);
hsgResMgr::ResMgr()->ReadKeyNotifyMe(s, msg, plRefFlags::kActiveRef);
numEffects--;
}
plgDispatch::Dispatch()->RegisterForExactType(plAvatarStealthModeMsg::Index(), GetKey());
}
void plArmatureEffectsMgr::Write(hsStream *s, hsResMgr *mgr)
{
hsKeyedObject::Write(s, mgr);
s->WriteSwap32(fEffects.GetCount());
int i;
for (i = 0; i < fEffects.GetCount(); i++)
mgr->WriteKey(s, fEffects[i]->GetKey());
}
hsBool plArmatureEffectsMgr::MsgReceive(plMessage* msg)
{
plEventCallbackInterceptMsg *iMsg = plEventCallbackInterceptMsg::ConvertNoRef(msg);
if (iMsg)
{
if (fEnabled)
iMsg->SendMessage();
}
plArmatureEffectMsg *eMsg = plArmatureEffectMsg::ConvertNoRef(msg);
plArmatureEffectStateMsg *sMsg = plArmatureEffectStateMsg::ConvertNoRef(msg);
if (eMsg || sMsg)
{
// Always handle state messages, but only trigger actual effects if we're enabled
if (sMsg || fEnabled)
{
int i;
for (i = 0; i < fEffects.GetCount(); i++)
fEffects[i]->HandleTrigger(msg);
}
return true;
}
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef(msg);
if (refMsg)
{
plArmatureEffect *effect = plArmatureEffect::ConvertNoRef(refMsg->GetRef());
if (effect)
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
fEffects.Append(effect);
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
fEffects.RemoveItem(effect);
return true;
}
}
plAvatarStealthModeMsg *stealthMsg = plAvatarStealthModeMsg::ConvertNoRef(msg);
if (stealthMsg && stealthMsg->GetSender() == fArmature->GetTarget(0)->GetKey())
{
if (stealthMsg->fMode == plAvatarStealthModeMsg::kStealthCloaked)
fEnabled = false;
else
fEnabled = true;
return true;
}
return hsKeyedObject::MsgReceive(msg);
}
UInt32 plArmatureEffectsMgr::GetNumEffects()
{
return fEffects.GetCount();
}
plArmatureEffect *plArmatureEffectsMgr::GetEffect(UInt32 num)
{
return fEffects[num];
}
void plArmatureEffectsMgr::ResetEffects()
{
int i;
for (i = 0; i < fEffects.GetCount(); i++)
fEffects[i]->Reset();
}
/////////////////////////////////////////////////////////////////////////////
//
// Actual Effects
//
/////////////////////////////////////////////////////////////////////////////
plArmatureEffectFootSound::plArmatureEffectFootSound()
{
plArmatureEffectFootSurface *surface = TRACKED_NEW plArmatureEffectFootSurface;
surface->fID = plArmatureEffectsMgr::kFootNoSurface;
surface->fTrigger = nil;
fSurfaces.Append(surface);
int i;
for (i = 0; i < plArmatureEffectsMgr::kMaxSurface; i++)
{
fMods[i] = nil;
}
SetFootType(kFootTypeShoe);
}
plArmatureEffectFootSound::~plArmatureEffectFootSound()
{
int i;
for (i = 0; i < fSurfaces.GetCount(); i++)
delete fSurfaces[i];
}
void plArmatureEffectFootSound::Read(hsStream* s, hsResMgr* mgr)
{
plArmatureEffect::Read(s, mgr);
int count = s->ReadByte();
int i;
for (i = 0; i < count; i++)
{
plGenRefMsg *msg = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, i, -1);
mgr->ReadKeyNotifyMe(s, msg, plRefFlags::kActiveRef);
}
}
UInt32 plArmatureEffectFootSound::IFindSurfaceByTrigger(plKey trigger)
{
UInt32 i;
// Skip index 0. It's the special "NoSurface" that should always be at the stack bottom
for (i = 1; i < fSurfaces.GetCount(); i++)
{
if (fSurfaces[i]->fTrigger == trigger)
return i;
}
return -1;
}
void plArmatureEffectFootSound::Write(hsStream* s, hsResMgr* mgr)
{
plArmatureEffect::Write(s, mgr);
s->WriteByte(plArmatureEffectsMgr::kMaxSurface);
int i;
for (i = 0; i < plArmatureEffectsMgr::kMaxSurface; i++)
mgr->WriteKey(s, (fMods[i] ? fMods[i]->GetKey() : nil));
}
hsBool plArmatureEffectFootSound::MsgReceive(plMessage* msg)
{
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef(msg);
if (refMsg)
{
plRandomSoundMod *rsMod = plRandomSoundMod::ConvertNoRef(refMsg->GetRef());
if (rsMod)
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
fMods[refMsg->fWhich] = rsMod;
}
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
fMods[refMsg->fWhich] = nil;
return true;
}
}
return plArmatureEffect::MsgReceive(msg);
}
hsBool plArmatureEffectFootSound::HandleTrigger(plMessage* msg)
{
plArmatureEffectMsg *eMsg = plArmatureEffectMsg::ConvertNoRef(msg);
if (eMsg)
{
UInt32 curSurfaceIndex = fSurfaces[fSurfaces.GetCount() - 1]->fID;
if (curSurfaceIndex < plArmatureEffectsMgr::kMaxSurface && fMods[curSurfaceIndex] != nil)
{
if (plgAudioSys::Active() && fActiveSurfaces.IsBitSet(curSurfaceIndex))
{
fMods[curSurfaceIndex]->SetCurrentGroup(eMsg->fTriggerIdx);
plAnimCmdMsg *animMsg = TRACKED_NEW plAnimCmdMsg;
animMsg->AddReceiver(fMods[curSurfaceIndex]->GetKey());
animMsg->SetCmd(plAnimCmdMsg::kContinue);
plgDispatch::MsgSend(animMsg);
}
}
return true;
}
plArmatureEffectStateMsg *sMsg = plArmatureEffectStateMsg::ConvertNoRef(msg);
if (sMsg)
{
// It doesn't matter if we're adding or removing a surface, our load/unload is the same:
// unload the old surface and load the new one
if (sMsg->fAddSurface)
{
if (IFindSurfaceByTrigger(sMsg->GetSender()) == -1) // Check that it's not a repeat msg
{
plStatusLog::AddLineS("audio.log", "FTSP: Switching to surface - %s",
plArmatureEffectsMgr::SurfaceStrings[sMsg->fSurface]);
plArmatureEffectFootSurface *surface = TRACKED_NEW plArmatureEffectFootSurface;
surface->fID = sMsg->fSurface;
surface->fTrigger = sMsg->GetSender();
fSurfaces.Append(surface);
}
}
else
{
UInt32 index = IFindSurfaceByTrigger(sMsg->GetSender());
if (index != -1)
{
if (index == fSurfaces.GetCount() - 1) // It's the top on the stack
plStatusLog::AddLineS("audio.log", "FTSP: Switching to surface - %s",
plArmatureEffectsMgr::SurfaceStrings[fSurfaces[index - 1]->fID]);
delete fSurfaces[index];
fSurfaces.Remove(index);
}
}
return true;
}
return false;
}
void plArmatureEffectFootSound::Reset()
{
while (fSurfaces.GetCount() > 1)
delete fSurfaces.Pop();
}
void plArmatureEffectFootSound::SetFootType(UInt8 type)
{
if (type == kFootTypeBare)
{
fActiveSurfaces.Clear();
fActiveSurfaces.SetBit(plArmatureEffectsMgr::kFootDeepWater);
fActiveSurfaces.SetBit(plArmatureEffectsMgr::kFootPuddle);
fActiveSurfaces.SetBit(plArmatureEffectsMgr::kFootWater);
fActiveSurfaces.SetBit(plArmatureEffectsMgr::kFootSwimming);
}
else
{
fActiveSurfaces.Set(plArmatureEffectsMgr::kMaxSurface);
}
}