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.
 
 
 
 
 

1964 lines
58 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 "cyAvatar.h"
#include "plgDispatch.h"
#include "plAvatar/plAvatarMgr.h"
#include "plMessage/plAvatarMsg.h"
#include "plMessage/plLinkToAgeMsg.h"
#include "plMessage/plOneShotCallbacks.h"
#include "plMessage/plOneShotMsg.h"
#include "plMessage/plMultistageMsg.h"
#include "pnMessage/plNotifyMsg.h"
#include "pnKeyedObject/plFixedKey.h"
#include "plGImage/plMipmap.h"
#include "pyKey.h"
#include "pySceneObject.h"
#include "pyColor.h"
#include "pyImage.h"
#include "cyPythonInterface.h"
#include "cyMisc.h"
#include "plAvatar/plOneShotMod.h"
#include "plAvatar/plMultistageBehMod.h"
#include "plAvatar/plAvatarClothing.h"
#include "plAvatar/plClothingLayout.h"
#include "plAvatar/plArmatureMod.h"
#include "plAvatar/plAvBrainHuman.h" // needed to call the emote
#include "plAvatar/plAGAnim.h" // to get the BodyUsage enum
#include "plInputCore/plAvatarInputInterface.h"
#include "plPhysical.h"
#include "plMessage/plSimStateMsg.h"
#include "pnNetCommon/plNetApp.h"
#include "plVault/plVault.h"
#include "plDrawable/plSharedMesh.h"
#include "pnSceneObject/plSceneObject.h"
#include "pnSceneObject/plCoordinateInterface.h"
#include "plDrawable/plMorphSequence.h"
///////////////////////////////////////////////////////////////////////////
//
// LOCAL FORWARD DECLs
//
///////////////////////////////////////////////////////////////////////////
bool IEnterGenericMode(const char *enterAnim, const char *idleAnim, const char *exitAnim, bool autoExit, plAGAnim::BodyUsage bodyUsage,
plAvBrainGeneric::BrainType = plAvBrainGeneric::kGeneric);
bool IExitTopmostGenericMode();
cyAvatar::cyAvatar(plKey sender, plKey recvr)
{
SetSender(sender);
AddRecvr(recvr);
fNetForce = false;
}
// setters
void cyAvatar::SetSender(plKey &sender)
{
fSender = sender;
}
void cyAvatar::AddRecvr(plKey &recvr)
{
if ( recvr != nil )
fRecvr.Append(recvr);
}
void cyAvatar::SetNetForce(hsBool state)
{
// set our flag
fNetForce = state;
}
void cyAvatar::SetSenderKey(pyKey& pKey)
{
SetSender(pKey.getKey());
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : IFindArmatureModKey
// PARAMETERS : avObj - avatar sceneobject
//
// PURPOSE : find the armature mod for this sceneoabject (if its an avatar)
//
const plArmatureMod* cyAvatar::IFindArmatureMod(plKey avKey)
{
plSceneObject* avObj = plSceneObject::ConvertNoRef(avKey->ObjectIsLoaded());
if ( avObj )
{
// search through its modifiers to see if one of them is an avatar modifier
int i;
for ( i=0; i<avObj->GetNumModifiers(); i++ )
{
const plModifier* mod = avObj->GetModifier(i);
// see if it is an avatar mod base class
const plArmatureMod* avmod = plArmatureMod::ConvertNoRef(mod);
if ( avmod )
return avmod;
}
}
// otherwise we didn't find anything
return nil;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : IFindArmatureModKey
// PARAMETERS : avObj - avatar sceneobject
//
// PURPOSE : find the armature mod for this sceneoabject (if its an avatar)
//
plKey cyAvatar::IFindArmatureModKey(plKey avKey)
{
const plArmatureMod* avatar = IFindArmatureMod(avKey);
if ( avatar )
return avatar->GetKey();
// otherwise we didn't find anything
return nil;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : oneShot
// PARAMETERS :
//
// PURPOSE : oneShot Avatar (must already be there)
//
void cyAvatar::OneShot(pyKey &seekKey, float duration, hsBool usePhysics,
const char *animName, hsBool drivable, hsBool reversible)
{
if ( fRecvr.Count() > 0 )
{
// create message
plAvOneShotMsg* pMsg = TRACKED_NEW plAvOneShotMsg(
(plKey )fSender,
nil,
seekKey.getKey(), // Mark D told me to do it ...paulg
duration,
usePhysics,
animName, // Constructor will do a copy. -mf- hsStrcpy(animName),
drivable,
reversible);
// check if this needs to be network forced to all clients
if (fNetForce )
{
// set the network propagate flag to make sure it gets to the other clients
pMsg->SetBCastFlag(plMessage::kNetPropagate);
pMsg->SetBCastFlag(plMessage::kNetForce);
}
// must have a receiver!
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
// add all our receivers to the message receiver list
int i;
for ( i=0; i<fRecvr.Count(); i++ )
{
pMsg->AddReceiver(fRecvr[i]);
}
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RunBehavior
// PARAMETERS :
//
// PURPOSE : Run Behavior, could be single or multi-stage shot
//
void cyAvatar::RunBehavior(pyKey &behKey, hsBool netForce, hsBool netProp)
{
// first there is someone to send to and make sure that we an avatar to send this to
if ( behKey.getKey() != nil && fRecvr.Count() > 0)
{
// must determine if the behKey is pointing to Single or Multi Shot behavior
if ( plOneShotMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
// create a message OneShotMessage
plOneShotMsg* pMsg = TRACKED_NEW plOneShotMsg;
// check if this needs to be network forced to all clients
if (netProp)
{
pMsg->SetBCastFlag(plMessage::kNetPropagate);
}
else
{
pMsg->SetBCastFlag(plMessage::kNetPropagate, false);
}
if (netForce)
{
// set the network propagate flag to make sure it gets to the other clients
pMsg->SetBCastFlag(plMessage::kNetPropagate);
pMsg->SetBCastFlag(plMessage::kNetForce);
}
else
{
pMsg->SetBCastFlag(plMessage::kNetForce, false);
}
pMsg->SetSender(fSender);
pMsg->AddReceiver(behKey.getKey());
int i;
for ( i=0; i<fRecvr.Count(); i++ )
{
// make sure there is an avatar to set
if ( fRecvr[i] != nil )
{
pMsg->fPlayerKey = (plKey)fRecvr[i];
plgDispatch::MsgSend( pMsg ); // send off command for each valid avatar we find
// ... really, should only be one... though
}
}
}
// else if it is a Multistage guy
else if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
// its a multistage thingy... need to send it a plNotifyMsg
// create new notify message to do the actual send with
plNotifyMsg* pNMsg = TRACKED_NEW plNotifyMsg;
// set whether this should be forced over the network (ignoring net-cascading)
if (netProp)
{
pNMsg->SetBCastFlag(plMessage::kNetPropagate);
}
else
{
pNMsg->SetBCastFlag(plMessage::kNetPropagate, false);
}
if ( netForce )
{
pNMsg->SetBCastFlag(plMessage::kNetPropagate);
pNMsg->SetBCastFlag(plMessage::kNetForce);
}
else
{
pNMsg->SetBCastFlag(plMessage::kNetForce, false);
}
// copy data and event records to new NotifyMsg
pNMsg->fState = 1.0;
// need to recreate all the events in the new message by Adding them
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
pNMsg->AddPickEvent( (plKey)fRecvr[0], nil, true, hsPoint3(0,0,0) );
}
// add receivers
// loop though adding the ones that want to be notified of the change
pNMsg->AddReceiver(behKey.getKey());
pNMsg->SetSender(fSender);
plgDispatch::MsgSend( pNMsg );
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RunBehaviorAndReply
// PARAMETERS :
//
// PURPOSE : Run Behavior, multistage only, reply to specified key'd object
//
void cyAvatar::RunBehaviorAndReply(pyKey& behKey, pyKey& replyKey, hsBool netForce, hsBool netProp)
{
plMultistageBehMod* pMod = plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr());
if ( pMod )
{
// its a multistage thingy... need to send it a plNotifyMsg
// create new notify message to do the actual send with
plNotifyMsg* pNMsg = TRACKED_NEW plNotifyMsg;
// set whether this should be forced over the network (ignoring net-cascading)
if (netProp)
{
pNMsg->SetBCastFlag(plMessage::kNetPropagate);
}
else
{
pNMsg->SetBCastFlag(plMessage::kNetPropagate, false);
}
if (netForce)
{
// set the network propagate flag to make sure it gets to the other clients
pNMsg->SetBCastFlag(plMessage::kNetPropagate);
pNMsg->SetBCastFlag(plMessage::kNetForce);
}
else
{
pNMsg->SetBCastFlag(plMessage::kNetForce, false);
}
// copy data and event records to new NotifyMsg
pNMsg->fState = 1.0;
// need to recreate all the events in the new message by Adding them
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
pNMsg->AddPickEvent( (plKey)fRecvr[0], nil, true, hsPoint3(0,0,0) );
}
// add receivers
// loop though adding the ones that want to be notified of the change
pNMsg->AddReceiver(behKey.getKey());
pNMsg->SetSender(replyKey.getKey());
plgDispatch::MsgSend( pNMsg );
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : NextStage
// PARAMETERS : behKey - behavior pyKey
// : transTime - the transition time to the next stage
// (optional): rewind - whether to rewind to the front of the next stage
//
// PURPOSE : Go to the next stage in a multi-stage behavior
//
// NOTE: only works with multi-stage behaviors
//
void cyAvatar::NextStage(pyKey &behKey, hsScalar transTime, hsBool setTime, hsScalar newTime,
hsBool setDirection, bool isForward, hsBool netForce)
{
// first there is someone to send to and make sure that we an avatar to send this to
if ( behKey.getKey() != nil && fRecvr.Count() > 0)
{
// if it is a Multistage guy
if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
plKey avKey = IFindArmatureModKey( (plKey)fRecvr[0] );
if ( avKey )
{
// create the message
plAvBrainGenericMsg* pMsg = TRACKED_NEW plAvBrainGenericMsg((plKey)fSender, avKey,
plAvBrainGenericMsg::kNextStage, 0, setTime, newTime,
setDirection, (bool)isForward, transTime);
if ( netForce )
pMsg->SetBCastFlag(plMessage::kNetForce | plMessage::kNetPropagate);
plgDispatch::MsgSend( pMsg );
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : PreviousStage
// PARAMETERS : behKey - behavior pyKey
// : transTime - the transition time to the next stage
// (optional): rewind - whether to rewind to the front of the next stage
//
// PURPOSE : Go to the previous stage in a multi-stage behavior
//
// NOTE: only works with multi-stage behaviors
//
void cyAvatar::PreviousStage(pyKey &behKey, hsScalar transTime, hsBool setTime, hsScalar newTime,
hsBool setDirection, bool isForward, hsBool netForce)
{
// first there is someone to send to and make sure that we an avatar to send this to
if ( behKey.getKey() != nil && fRecvr.Count() > 0)
{
// if it is a Multistage guy
if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
plKey avKey = IFindArmatureModKey( (plKey)fRecvr[0] );
if ( avKey )
{
// create the message
plAvBrainGenericMsg* pMsg = TRACKED_NEW plAvBrainGenericMsg((plKey)fSender, avKey,
plAvBrainGenericMsg::kPrevStage, 0, setTime, newTime,
setDirection, (bool)isForward, transTime);
if ( netForce )
pMsg->SetBCastFlag(plMessage::kNetForce | plMessage::kNetPropagate);
plgDispatch::MsgSend( pMsg );
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GotoStage
// PARAMETERS : behKey - behavior pyKey
// : stage - stage number to go to
// : transTime - the transition time to the next stage
// (optional): rewind - whether to rewind to the front of the next stage
//
// PURPOSE : Go to a particular stage in a multi-stage behavior
//
// NOTE: only works with multi-stage behaviors
//
void cyAvatar::GoToStage(pyKey &behKey, Int32 stage, hsScalar transTime, hsBool setTime, hsScalar newTime,
hsBool setDirection, bool isForward, hsBool netForce)
{
// first there is someone to send to and make sure that we an avatar to send this to
if ( behKey.getKey() != nil && fRecvr.Count() > 0)
{
// if it is a Multistage guy
if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
plKey avKey = IFindArmatureModKey( (plKey)fRecvr[0] );
if ( avKey )
{
// create the message
plAvBrainGenericMsg* pMsg = TRACKED_NEW plAvBrainGenericMsg((plKey)fSender, avKey,
plAvBrainGenericMsg::kGotoStage, stage, setTime, newTime,
setDirection, isForward, transTime);
if ( netForce )
pMsg->SetBCastFlag(plMessage::kNetForce | plMessage::kNetPropagate);
plgDispatch::MsgSend( pMsg );
}
}
}
}
void cyAvatar::SetLoopCount(pyKey &behKey, Int32 stage, Int32 loopCount, hsBool netForce)
{
// if it is a Multistage guy
if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil )
{
plMultistageModMsg* pMsg = TRACKED_NEW plMultistageModMsg((plKey)nil, behKey.getKey());
pMsg->SetCommand(plMultistageModMsg::kSetLoopCount);
pMsg->fStageNum = (UInt8)stage;
pMsg->fNumLoops = (UInt8)loopCount;
if ( netForce )
pMsg->SetBCastFlag(plMessage::kNetForce | plMessage::kNetPropagate);
plgDispatch::MsgSend( pMsg );
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : seek
// PARAMETERS :
//
// PURPOSE : seek Avatar (must already be there)
//
/* Unsupported. Ask Bob if you want it back.
void cyAvatar::Seek(pyKey &seekKey, float duration, hsBool usePhysics)
{
// must have a receiver!
if ( fRecvr.Count() > 0 )
{
// create message
plAvSeekMsg* pMsg = TRACKED_NEW plAvSeekMsg(
(plKey)fSender,nil, seekKey.getKey(),duration,usePhysics);
// check if this needs to be network forced to all clients
if (fNetForce )
{
// set the network propagate flag to make sure it gets to the other clients
pMsg->SetBCastFlag(plMessage::kNetPropagate);
pMsg->SetBCastFlag(plMessage::kNetForce);
}
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
// add all our receivers to the message receiver list
int i;
for ( i=0; i<fRecvr.Count(); i++ )
{
pMsg->AddReceiver(fRecvr[i]);
}
plgDispatch::MsgSend( pMsg ); // whoosh... off it goes
}
}
*/
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetAvatarClothingGroup
// PARAMETERS :
//
// PURPOSE : Return what clothing group the avatar is in
//
Int32 cyAvatar::GetAvatarClothingGroup()
{
// find the avatar's armature modifier
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if ( avMod )
{
return avMod->GetClothingOutfit()->fGroup;
}
}
}
return -1;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetClosetClothingList
// PARAMETERS :
//
// PURPOSE : Return a list of the wearable items for this avatar of that clothing_type
//
std::vector<std::string> cyAvatar::GetEntireClothingList(Int32 clothing_type)
{
// Currently, just all the clothing available will be returned
hsTArray<plClothingItem*> clothingList = plClothingMgr::GetClothingMgr()->GetItemList();
int numItems = clothingList.GetCount();
// create the string list to send to python...
std::vector<std::string> retVal;
for (int i = 0; i < numItems; i++)
retVal.push_back(clothingList[i]->GetName());
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetClosetClothingList
// PARAMETERS :
//
// PURPOSE : Return a list of the wearable items for this avatar of that clothing_type
//
std::vector<PyObject*> cyAvatar::GetClosetClothingList(Int32 clothing_type)
{
std::vector<PyObject*> retVal;
// find the avatar's armature modifier
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if ( avMod )
{
// Get all the clothes that we can wear
hsTArray<plClothingItem*> clothingList;
plClothingMgr::GetClothingMgr()->GetItemsByGroup(avMod->GetClothingOutfit()->fGroup, clothingList);
int numItems = clothingList.GetCount();
// create the string list to send to python... as a python object
int i;
for ( i=0; i<numItems; i++ )
{
plClothingItem* item = clothingList[i];
if ( clothing_type == -1 || item->fType == clothing_type )
{
// add this event record to the main event list (lists within a list)
// create list
PyObject* clothingItem = PyList_New(5);
// [0] = clothing name
PyList_SetItem(clothingItem, 0, PyString_FromString(item->GetName()));
// [1] = clothing type
PyList_SetItem(clothingItem, 1, PyInt_FromLong(item->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( item->fDescription != nil )
description = item->fDescription;
PyList_SetItem(clothingItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( item->fThumbnail != nil )
// create a ptImage
PyList_SetItem(clothingItem, 3, pyImage::New(item->fThumbnail->GetKey()));
else
PyList_SetItem(clothingItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( item->fCustomText != nil )
custom = item->fCustomText;
PyList_SetItem(clothingItem, 4, PyString_FromString(custom));
retVal.push_back(clothingItem);
}
}
}
}
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetAvatarClothingList
// PARAMETERS :
//
// PURPOSE : Return a list of the wearable items for this avatar of that clothing_type
//
std::vector<PyObject*> cyAvatar::GetAvatarClothingList()
{
std::vector<PyObject*> retVal;
// find the avatar's armature modifier
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if ( avMod )
{
// Currently, just all the clothing available will be returned
hsTArray<plClothingItem*> clothingList = avMod->GetClothingOutfit()->GetItemList();
int numItems = clothingList.GetCount();
// create the string list to send to python... as a python object
int i;
for ( i=0; i<numItems; i++ )
{
// add this event record to the main event list (lists within a list)
// create list
PyObject* clothingItem = PyList_New(5);
plClothingItem* item = clothingList[i];
// [0] = clothing name
PyList_SetItem(clothingItem, 0, PyString_FromString(item->GetName()));
// [1] = clothing type
PyList_SetItem(clothingItem, 1, PyInt_FromLong(item->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( item->fDescription != nil )
description = item->fDescription;
PyList_SetItem(clothingItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( item->fThumbnail != nil )
// create a ptImage
PyList_SetItem(clothingItem, 3, pyImage::New(item->fThumbnail->GetKey()));
else
PyList_SetItem(clothingItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( item->fCustomText != nil )
custom = item->fCustomText;
PyList_SetItem(clothingItem, 4, PyString_FromString(custom));
retVal.push_back(clothingItem);
}
}
}
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetWardrobeClothingList
// PARAMETERS :
//
// PURPOSE : Return a list of items that are in the avatars closet
//
std::vector<PyObject*> cyAvatar::GetWardrobeClothingList()
{
std::vector<PyObject*> retVal;
hsTArray<plClosetItem> closetList;
plClothingMgr::GetClothingMgr()->GetClosetItems(closetList);
int numItems = closetList.GetCount();
// create the string list to send to python... as a python object
int i;
for ( i=0; i<numItems; i++ )
{
// add this event record to the main event list (lists within a list)
// create list
PyObject* closetItem = PyList_New(7);
// [0] = clothing name
PyList_SetItem(closetItem, 0, PyString_FromString(closetList[i].fItem->GetName()));
// [1] = clothing type
PyList_SetItem(closetItem, 1, PyInt_FromLong(closetList[i].fItem->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( closetList[i].fItem->fDescription != nil )
description = closetList[i].fItem->fDescription;
PyList_SetItem(closetItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( closetList[i].fItem->fThumbnail != nil )
// create a ptImage
PyList_SetItem(closetItem, 3, pyImage::New(closetList[i].fItem->fThumbnail->GetKey()));
else
PyList_SetItem(closetItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( closetList[i].fItem->fCustomText != nil )
custom = closetList[i].fItem->fCustomText;
PyList_SetItem(closetItem, 4, PyString_FromString(custom));
// [5] = fTint1
PyList_SetItem(closetItem, 5, pyColor::New(closetList[i].fOptions.fTint1));
// [6] = fTint2
PyList_SetItem(closetItem, 6, pyColor::New(closetList[i].fOptions.fTint2));
retVal.push_back(closetItem);
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : AddWardrobeClothingItem
// PARAMETERS : clothing_name - the name of the clothing item to add to your wardrobe
// : tint1 - layer one color
// : tint2 - layer two color
//
// PURPOSE : To add a clothing item to the avatar's wardrobe (closet)
//
void cyAvatar::AddWardrobeClothingItem(const char* clothing_name,pyColor& tint1,pyColor& tint2)
{
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if ( item )
{
hsTArray<plClosetItem> items;
items.SetCount(1);
items[0].fItem = item;
items[0].fOptions.fTint1.Set(tint1.getRed(), tint1.getGreen(), tint1.getBlue(), 1.f);
items[0].fOptions.fTint2.Set(tint2.getRed(), tint2.getGreen(), tint2.getBlue(), 1.f);
plClothingMgr::GetClothingMgr()->AddItemsToCloset(items);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetUniqueMeshList
// PARAMETERS : clothing_type - the type of clothing to get
//
// PURPOSE : Return a list of unique clothing items (each has a different mesh)
// : that belong to the specific type
//
std::vector<PyObject*> cyAvatar::GetUniqueMeshList(Int32 clothing_type)
{
std::vector<PyObject*> retVal;
// find the avatar's armature modifier
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if ( avMod )
{
// Get all the clothes that we can wear
hsTArray<plClothingItem*> clothingList;
plClothingMgr::GetClothingMgr()->GetItemsByGroup(avMod->GetClothingOutfit()->fGroup, clothingList);
plClothingMgr::GetClothingMgr()->FilterUniqueMeshes(clothingList); // filter all redundant meshes
int numItems = clothingList.GetCount();
// create the string list to send to python... as a python object
int i;
for ( i=0; i<numItems; i++ )
{
plClothingItem* item = clothingList[i];
if ( clothing_type == -1 || item->fType == clothing_type )
{
// add this event record to the main event list (lists within a list)
// create list
PyObject* clothingItem = PyList_New(5);
// [0] = clothing name
PyList_SetItem(clothingItem, 0, PyString_FromString(item->GetName()));
// [1] = clothing type
PyList_SetItem(clothingItem, 1, PyInt_FromLong(item->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( item->fDescription != nil )
description = item->fDescription;
PyList_SetItem(clothingItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( item->fThumbnail != nil )
// create a ptImage
PyList_SetItem(clothingItem, 3, pyImage::New(item->fThumbnail->GetKey()));
else
PyList_SetItem(clothingItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( item->fCustomText != nil )
custom = item->fCustomText;
PyList_SetItem(clothingItem, 4, PyString_FromString(custom));
retVal.push_back(clothingItem);
}
}
}
}
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetAllWithSameMesh
// PARAMETERS : clothing_name - the name of the mesh to get the textures of
//
// PURPOSE : Return a list of clothing items that have the same mesh as
// : the item passed in
//
std::vector<PyObject*> cyAvatar::GetAllWithSameMesh(const char* clothing_name)
{
std::vector<PyObject*> retVal;
// find the avatar's armature modifier
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if ( avMod )
{
// Get all clothes with the same mesh as the one passed in
hsTArray<plClothingItem*> clothingList;
plClothingMgr::GetClothingMgr()->GetAllWithSameMesh(plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name), clothingList);
int numItems = clothingList.GetCount();
// create the string list to send to python... as a python object
int i;
for ( i=0; i<numItems; i++ )
{
// add this event record to the main event list (lists within a list)
// create list
PyObject* clothingItem = PyList_New(5);
plClothingItem* item = clothingList[i];
// [0] = clothing name
PyList_SetItem(clothingItem, 0, PyString_FromString(item->GetName()));
// [1] = clothing type
PyList_SetItem(clothingItem, 1, PyInt_FromLong(item->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( item->fDescription != nil )
description = item->fDescription;
PyList_SetItem(clothingItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( item->fThumbnail != nil )
// create a ptImage
PyList_SetItem(clothingItem, 3, pyImage::New(item->fThumbnail->GetKey()));
else
PyList_SetItem(clothingItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( item->fCustomText != nil )
custom = item->fCustomText;
PyList_SetItem(clothingItem, 4, PyString_FromString(custom));
retVal.push_back(clothingItem);
}
}
}
}
return retVal;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetMatchingClothingItem
// PARAMETERS :
//
// PURPOSE : Return the clothing item that matches this one
// : If no match then returns the number 0
//
PyObject* cyAvatar::GetMatchingClothingItem(const char* clothing_name)
{
// Get all the clothes that we can wear
hsTArray<plClothingItem*> clothingList;
plClothingItem* match = plClothingMgr::GetClothingMgr()->GetLRMatch(plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name));
if ( match )
{
// create list
PyObject* clothingItem = PyList_New(5);
// [0] = clothing name
PyList_SetItem(clothingItem, 0, PyString_FromString(match->GetName()));
// [1] = clothing type
PyList_SetItem(clothingItem, 1, PyInt_FromLong(match->fType));
// [2] = description
const char* description = ""; // assume an empty string
if ( match->fDescription != nil )
description = match->fDescription;
PyList_SetItem(clothingItem, 2, PyString_FromString(description));
// [3] = ptImage of icon
if ( match->fThumbnail != nil )
// create a ptImage
PyList_SetItem(clothingItem, 3, pyImage::New(match->fThumbnail->GetKey()));
else
PyList_SetItem(clothingItem, 3, PyInt_FromLong(0));
// [4] = fCustomText
const char* custom = ""; // assume an empty string
if ( match->fCustomText != nil )
custom = match->fCustomText;
PyList_SetItem(clothingItem, 4, PyString_FromString(custom));
return clothingItem;
}
else
return PyInt_FromLong(0);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : WearClothingItem
// PARAMETERS :
//
// PURPOSE : Wear a particular piece of clothing based on name of clothing item
// : returns 0, if clothing item was not found
//
hsBool cyAvatar::WearClothingItem(const char* clothing_name)
{
return WearClothingItemU(clothing_name,true);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RemoveClothingItem
// PARAMETERS :
//
// PURPOSE : Wear a particular piece of clothing based on name of clothing item
// : returns false, if clothing item was not found
//
hsBool cyAvatar::RemoveClothingItem(const char* clothing_name)
{
return RemoveClothingItemU(clothing_name,true);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintClothingItem
// PARAMETERS :
//
// PURPOSE : Tint a clothing item, i.e. change the color of it
//
hsBool cyAvatar::TintClothingItem(const char* clothing_name, pyColor& tint)
{
return TintClothingItemU(clothing_name,tint,true);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintClothingItemLayer
// PARAMETERS : clothing_name - name of the clothing item to change the color of
// : tint - what color to change it to
// : layer - which layer to change (1 or 2)
//
// PURPOSE : Tint a clothing item, i.e. change the color of it
//
hsBool cyAvatar::TintClothingItemLayer(const char* clothing_name, pyColor& tint, UInt8 layer)
{
return TintClothingItemLayerU(clothing_name,tint,layer,true);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : WearClothingItem
// PARAMETERS : --- with update flag
//
// PURPOSE : Wear a particular piece of clothing based on name of clothing item
// : returns 0, if clothing item was not found
//
hsBool cyAvatar::WearClothingItemU(const char* clothing_name, hsBool update)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
if ( fNetForce )
avMod->GetClothingOutfit()->AddItem(item, update, true, true);
else
avMod->GetClothingOutfit()->AddItem(item, update);
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RemoveClothingItemU
// PARAMETERS : --- with update flag
//
// PURPOSE : Wear a particular piece of clothing based on name of clothing item
// : returns false, if clothing item was not found
//
hsBool cyAvatar::RemoveClothingItemU(const char* clothing_name, hsBool update)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
if ( fNetForce )
avMod->GetClothingOutfit()->RemoveItem(item,update,true);
else
avMod->GetClothingOutfit()->RemoveItem(item,update);
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintClothingItemU
// PARAMETERS : --- with update flag
//
// PURPOSE : Tint a clothing item, i.e. change the color of it
//
hsBool cyAvatar::TintClothingItemU(const char* clothing_name, pyColor& tint, hsBool update)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
avMod->GetClothingOutfit()->TintItem(item, tint.getRed(),tint.getGreen(),tint.getBlue(),update,true,fNetForce,true,plClothingElement::kLayerTint1);
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintClothingItemLayer
// PARAMETERS : clothing_name - name of the clothing item to change the color of
// : tint - what color to change it to
// : layer - which layer to change (1 or 2)
//
// PURPOSE : Tint a clothing item, i.e. change the color of it
//
hsBool cyAvatar::TintClothingItemLayerU(const char* clothing_name, pyColor& tint, UInt8 layer, hsBool update)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
// Convert Python layer number to clothing code...
if (layer == 2)
layer = plClothingElement::kLayerTint2;
else
layer = plClothingElement::kLayerTint1;
avMod->GetClothingOutfit()->TintItem(item, tint.getRed(),tint.getGreen(),tint.getBlue(),update,true,fNetForce,true,layer);
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetClothingItemParameterString
// PARAMETERS :
//
// PURPOSE : Get the custom parameter string for a clothing item
//
const char* cyAvatar::GetClothingItemParameterString(const char* clothing_name)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
if ( item->fCustomText != nil )
return item->fCustomText;
else
return "";
}
}
}
return "";
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetTintClothingItem
// PARAMETERS :
//
// PURPOSE : Get the tint a clothing item, i.e. change the color of it
//
PyObject* cyAvatar::GetTintClothingItem(const char* clothing_name)
{
return GetTintClothingItemL(clothing_name,1);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetTintClothingItem
// PARAMETERS :
//
// PURPOSE : Get the tint a clothing item, i.e. change the color of it
//
PyObject* cyAvatar::GetTintClothingItemL(const char* clothing_name, UInt8 layer)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName((char*)clothing_name);
if (avMod && item)
{
// Convert Python layer number to clothing code...
if (layer == 2)
layer = plClothingElement::kLayerTint2;
else
layer = plClothingElement::kLayerTint1;
hsColorRGBA tint = avMod->GetClothingOutfit()->GetItemTint(item,layer);
return pyColor::New(tint);
}
}
}
char errmsg[256];
sprintf(errmsg,"Cannot find clothing item %d to find out what tint it is",clothing_name);
PyErr_SetString(PyExc_KeyError, errmsg);
// returning nil means an error occurred
return nil;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintSkin
// PARAMETERS :
//
// PURPOSE : Tint the skin of the player's avatar
//
void cyAvatar::TintSkin(pyColor& tint)
{
TintSkinU(tint,true);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : TintSkinU
// PARAMETERS :
//
// PURPOSE : Tint the skin of the player's avatar with optional update flag
//
void cyAvatar::TintSkinU(pyColor& tint, hsBool update)
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
avMod->GetClothingOutfit()->TintSkin(tint.getRed(),tint.getGreen(),tint.getBlue(),update,true);
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetTintSkin
// PARAMETERS :
//
// PURPOSE : Get the tint of the skin of the player's avatar
//
PyObject* cyAvatar::GetTintSkin()
{
const plArmatureMod *avMod = nil;
// we can really only talk to one avatar, so just get the first one (which is probably the only one)
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
hsColorRGBA tint = avMod->GetClothingOutfit()->fSkinTint;
// now create the ptColor Python object
return pyColor::New(tint);
}
}
char errmsg[256];
sprintf(errmsg,"Cannot find the skin of the player. Whatever that means!");
PyErr_SetString(PyExc_KeyError, errmsg);
// returning nil means an error occurred
return nil;
}
plMorphSequence* cyAvatar::LocalMorphSequence()
{
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (!avMod)
return nil;
const plSceneObject *so = avMod->GetClothingSO(0); // grabbing the high LOD node
if (!so)
return nil;
const plModifier* constSeq = nil;
int i;
for (i = 0; i < so->GetNumModifiers(); i++)
{
constSeq = so->GetModifier(i);
if (constSeq && plMorphSequence::ConvertNoRef(constSeq))
{
return (plMorphSequence*)constSeq; // safe cast, we've already checked type (plus we're const_cast'ing).
}
}
return nil;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : SetMorph
// PARAMETERS : clothing_name - the name of the clothing to morph
// : layer - the layer to affect
// : value - what the new value should be (clipped between -1 and 1)
//
// PURPOSE : Set the morph value of a specific layer of clothing
//
void cyAvatar::SetMorph(const char* clothing_name, UInt8 layer, float value)
{
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName(clothing_name);
if( !item )
{
PyErr_SetString(PyExc_KeyError, "Item not found");
return;
}
float wgtPlus;
float wgtMinus;
if(value > 1.0) value = 1.0;
if(value < -1.0) value = -1.0;
if (value > 0)
{
wgtPlus = value;
wgtMinus = 0;
}
else
{
wgtMinus = -value;
wgtPlus = 0;
}
if ( fRecvr.Count() > 0 && fRecvr[0] != nil )
{
plSceneObject *so = plSceneObject::ConvertNoRef(fRecvr[0]->GetObjectPtr());
if (so != nil)
{
const plArmatureMod *avMod = (plArmatureMod*)so->GetModifierByType(plArmatureMod::Index());
if (avMod && avMod->GetClothingOutfit())
{
avMod->GetClothingOutfit()->MorphItem(item, layer, 0, wgtPlus, true);
avMod->GetClothingOutfit()->MorphItem(item, layer, 1, wgtMinus, true);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetMorph
// PARAMETERS : clothing_name - the name of the clothing to get the value from
// : layer - the layer to get the value from
//
// PURPOSE : Returns the current morph value of the specific layer of clothing
//
float cyAvatar::GetMorph(const char* clothing_name, UInt8 layer)
{
plMorphSequence* seq = LocalMorphSequence();
if( !seq )
{
PyErr_SetString(PyExc_KeyError, "Sequence not found");
return 0;
}
plClothingItem *item = plClothingMgr::GetClothingMgr()->FindItemByName(clothing_name);
if( !item )
{
PyErr_SetString(PyExc_KeyError, "Item not found");
return 0;
}
plKey meshKey = item->fMeshes[0]->GetKey();
if (layer >= seq->GetNumLayers(meshKey))
{
PyErr_SetString(PyExc_KeyError, "Layer index too high");
return 0;
}
float wgtPlus;
float wgtMinus;
wgtPlus = seq->GetWeight(layer,0,meshKey);
wgtMinus = seq->GetWeight(layer,1,meshKey);
if (wgtPlus > 0)
return wgtPlus;
else
return -wgtMinus;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : SetSkinBlend
// PARAMETERS : layer - the layer to affect
// : value - what the new value should be (clipped between 0 and 1)
//
// PURPOSE : Set the skin blend for the specified layer
//
void cyAvatar::SetSkinBlend(UInt8 layer, float value)
{
if (value < 0.0) value = 0.0;
if (value > 1.0) value = 1.0;
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avMod)
{
avMod->GetClothingOutfit()->SetSkinBlend(value, (int)layer + plClothingElement::kLayerSkinBlend1 - 1);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : GetSkinBlend
// PARAMETERS : layer - the layer to get the blend for
//
// PURPOSE : Returns the current layer's skin blend
//
float cyAvatar::GetSkinBlend(UInt8 layer)
{
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avMod)
{
return avMod->GetClothingOutfit()->GetSkinBlend((int)layer + plClothingElement::kLayerSkinBlend1 - 1);
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : SaveClothing
// PARAMETERS :
//
// PURPOSE : Saves the current clothing to the vault (including morphs)
//
void cyAvatar::SaveClothing()
{
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avMod)
avMod->GetClothingOutfit()->SaveCustomizations();
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : EnterSubWorld
// PARAMETERS : object - a sceneobject that is in the subworld
//
// PURPOSE : Place the Avatar into the subworld of the sceneobject specified
//
void cyAvatar::EnterSubWorld(pySceneObject& object)
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
// get the sceneobject that we will use to find the subworld
plKey SOkey = object.getObjKey();
if ( SOkey )
{
plSceneObject *SO = plSceneObject::ConvertNoRef(SOkey->ObjectIsLoaded());
if(SO)
{
plKey subWorldKey = SOkey;
plKey physKey = avatar->GetKey();
plKey nilKey; // sorry
plSubWorldMsg *swMsg = TRACKED_NEW plSubWorldMsg(nilKey, physKey, subWorldKey);
swMsg->Send();
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ExitSubWorld
// PARAMETERS : (none)
//
// PURPOSE : Exit the avatar from the subworld, back into the ... <whatever> world
//
void cyAvatar::ExitSubWorld()
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
plKey subWorldKey; // we're going to the nil subworld
plKey physKey = avatar->GetKey();
plKey nilKey; // sorry
plSubWorldMsg *swMsg = TRACKED_NEW plSubWorldMsg(nilKey, physKey, subWorldKey);
swMsg->Send();
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : PlaySimpleAnimation
// PARAMETERS : object - a sceneobject that is in the subworld
//
// PURPOSE : Place the Avatar into the subworld of the sceneobject specified
//
void cyAvatar::PlaySimpleAnimation(const char* animName)
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
avatar->PlaySimpleAnim(animName);
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ChangeAvatar
// PARAMETERS : gender name - is a string of the name of the gender to go to
//
// PURPOSE : Change the local avatar's gender.
//
// Valid genders:
// Male
// Female
//
void cyAvatar::ChangeAvatar(const char* genderName)
{
#ifndef PLASMA_EXTERNAL_RELEASE
plClothingMgr::ChangeAvatar((char*)genderName);
wchar wStr[MAX_PATH];
StrToUnicode(wStr, genderName, arrsize(wStr));
RelVaultNode * rvnPlr = VaultGetPlayerNodeIncRef();
if (rvnPlr) {
VaultPlayerNode plr(rvnPlr);
plr.SetAvatarShapeName(wStr);
rvnPlr->DecRef();
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ChangePlayerName
// PARAMETERS : name - is a string of the new name for the player
//
// PURPOSE : Change the local player's avatar name
//
void cyAvatar::ChangePlayerName(const char* playerName)
{
wchar wStr[MAX_PATH];
StrToUnicode(wStr, playerName, arrsize(wStr));
RelVaultNode * rvnPlr = VaultGetPlayerNodeIncRef();
if (rvnPlr) {
VaultPlayerNode plr(rvnPlr);
plr.SetPlayerName(wStr);
rvnPlr->DecRef();
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : Emote
// PARAMETERS : emoteName - name of the emote to play on the avatar
//
// PURPOSE : plays an emote on a the local avatar (net propagated)
//
bool cyAvatar::Emote(const char* emoteName)
{
// can we find an emote of this name?
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
return AvatarEmote(avatar, emoteName);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : Sit
// PARAMETERS : none
//
// PURPOSE : Makes the avatar sit down on the ground where they are.
// The avatar will automatically stand when the user tries to move.
//
bool cyAvatar::Sit()
{
return IEnterGenericMode("SitDownGround", "SitIdleGround", "SitStandGround", true, plAGAnim::kBodyLower, plAvBrainGeneric::kSitOnGround);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : EnterKiMode
// PARAMETERS : none
//
// PURPOSE : Makes the avatar appear to be using the ki.
//
bool cyAvatar::EnterKiMode()
{
return IEnterGenericMode("KiBegin", "KiUse", "KiEnd", false, plAGAnim::kBodyFull);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ExitKiMode
// PARAMETERS : none
//
// PURPOSE : Makes the avatar stop appearing to use the ki.
// May cause problems if EnterKiMode() was not called earlier.
//
bool cyAvatar::ExitKiMode()
{
return IExitTopmostGenericMode();
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : EnterAFKMode
// PARAMETERS : none
//
// PURPOSE : Tell the avatar to enter the AFK mode (sitting, head down)
//
bool cyAvatar::EnterAFKMode()
{
return IEnterGenericMode("AFKEnter", "AFKIdle", "AFKExit", true, plAGAnim::kBodyFull, plAvBrainGeneric::kAFK);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ExitAFKMode
// PARAMETERS : none
//
// PURPOSE : Tell the avatar to exit the AFK mode
// May cause problems if EnterKiMode() was not called earlier.
//
bool cyAvatar::ExitAFKMode()
{
return IExitTopmostGenericMode();
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : EnterPBMode
// PARAMETERS : none
//
// PURPOSE : Enter the personal book mode...stay until further notice.
//
bool cyAvatar::EnterPBMode()
{
return IEnterGenericMode("PersonalBookEnter", "PersonalBookIdle", "PersonalBookExit", false, plAGAnim::kBodyFull);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ExitPBMode
// PARAMETERS : none
//
// PURPOSE : Leave the personal book mode. Currently leaves any mode; will become
// : more specific in future version
//
bool cyAvatar::ExitPBMode()
{
return IExitTopmostGenericMode();
}
int cyAvatar::GetCurrentMode()
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
return avatar->GetCurrentGenericType();
}
}
return plAvBrainGeneric::kNonGeneric;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : disable movement controls
// PARAMETERS :
//
// PURPOSE : something tells me python shouldn't do this this way
//
void cyAvatar::DisableMovementControls()
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avatar)
{
if (!avatar->IsInputSuspended())
avatar->SuspendInput();
}
}
void cyAvatar::EnableMovementControls()
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avatar)
{
if (avatar->IsInputSuspended())
avatar->ResumeInput();
}
}
void cyAvatar::DisableMouseMovement()
{
plAvatarInputInterface::GetInstance()->SuspendMouseMovement();
}
void cyAvatar::EnableMouseMovement()
{
plAvatarInputInterface::GetInstance()->EnableMouseMovement();
}
void cyAvatar::EnableAvatarJump()
{
plAvatarInputInterface::GetInstance()->EnableJump(true);
}
void cyAvatar::DisableAvatarJump()
{
plAvatarInputInterface::GetInstance()->EnableJump(false);
}
void cyAvatar::EnableForwardMovement()
{
plAvatarInputInterface::GetInstance()->EnableForwardMovement(true);
}
void cyAvatar::DisableForwardMovement()
{
plAvatarInputInterface::GetInstance()->EnableForwardMovement(false);
}
bool cyAvatar::LocalAvatarRunKeyDown()
{
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avMod)
return avMod->FastKeyDown();
return false;
}
bool cyAvatar::LocalAvatarIsMoving()
{
plArmatureMod *avMod = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avMod)
return avMod->ForwardKeyDown() || avMod->BackwardKeyDown() || avMod->StrafeRightKeyDown() ||
avMod->StrafeLeftKeyDown() || avMod->TurnRightKeyDown() || avMod->TurnLeftKeyDown() ||
avMod->JumpKeyDown();
return false;
}
void cyAvatar::SetMouseTurnSensitivity(hsScalar val)
{
plArmatureMod::SetMouseTurnSensitivity(val);
}
hsScalar cyAvatar::GetMouseTurnSensitivity()
{
return plArmatureMod::GetMouseTurnSensitivity();
}
void cyAvatar::SpawnNext()
{
static int whichSpawn = 0;
plAvatarMgr *mgr = plAvatarMgr::GetInstance();
int max = mgr->NumSpawnPoints();
whichSpawn = ++whichSpawn < max ? whichSpawn : 0;
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
if(avatar)
{
double fakeTime = 0.0f;
avatar->SpawnAt(whichSpawn, fakeTime);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : RegisterForBehaviorNotify()
// PARAMETERS : none
//
// PURPOSE : To register for notifies from the avatar for any kind of behavior notify
//
void cyAvatar::RegisterForBehaviorNotify(pyKey &selfKey)
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
avatar->RegisterForBehaviorNotify(selfKey.getKey());
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : UnRegisterForBehaviorNotify()
// PARAMETERS : none
//
// PURPOSE : To remove the registeration for notifies from the avatar
//
void cyAvatar::UnRegisterForBehaviorNotify(pyKey &selfKey)
{
// make sure that there is atleast one avatar scene object attached (should be)
if ( fRecvr.Count() > 0)
{
// find the armature modifier
plArmatureMod* avatar = (plArmatureMod*)IFindArmatureMod((plKey)fRecvr[0]);
if(avatar)
{
avatar->UnRegisterForBehaviorNotify(selfKey.getKey());
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : IEnterGenericMode
// PARAMETERS : none
//
// PURPOSE : Three-stage multistage animations (sit down, sit, get up) are really common.
// : This does the basic setup.
//
bool IEnterGenericMode(const char *enterAnim, const char *idleAnim, const char *exitAnim, bool autoExit, plAGAnim::BodyUsage bodyUsage,
plAvBrainGeneric::BrainType type /* = kGeneric */)
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
return PushSimpleMultiStage(avatar, enterAnim, idleAnim, exitAnim, true, autoExit, bodyUsage, type);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : IExitTopmostGenericMode
// PARAMETERS : none
//
// PURPOSE : Exits whatever multistage animation you're in. We currently don't discriminate;
// : that will be added later.
//
bool IExitTopmostGenericMode()
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
plAvBrainGenericMsg* pMsg = TRACKED_NEW plAvBrainGenericMsg(nil, avatar->GetKey(),
plAvBrainGenericMsg::kGotoStage, 2, false, 0.0,
false, false, 0.0);
pMsg->SetBCastFlag(plMessage::kNetForce | plMessage::kNetPropagate);
plgDispatch::MsgSend( pMsg );
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : IsCurrentBrainHuman
// PARAMETERS : none
//
// PURPOSE : Returns whether the top most brain is a human brain
//
hsBool cyAvatar::IsCurrentBrainHuman()
{
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar();
if (avatar)
{
plArmatureBrain *brain = avatar->GetCurrentBrain();
plAvBrainHuman *human = plAvBrainHuman::ConvertNoRef(brain);
if (human)
return true;
}
return false;
}