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.
2026 lines
67 KiB
2026 lines
67 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 <Python.h> |
|
#include "plgDispatch.h" |
|
#include "pyKey.h" |
|
#include "plPhysical.h" |
|
#pragma hdrstop |
|
|
|
#include "cyAvatar.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 "pySceneObject.h" |
|
#include "pyColor.h" |
|
#include "pyImage.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 "plMessage/plSimStateMsg.h" |
|
|
|
#include "plVault/plVault.h" |
|
|
|
#include "plDrawable/plSharedMesh.h" |
|
|
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "pnSceneObject/plCoordinateInterface.h" |
|
#include "plDrawable/plMorphSequence.h" |
|
#include "pnNetCommon/plNetApp.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::SetSenderKey(pyKey& pKey) |
|
{ |
|
plKey k = pKey.getKey(); |
|
SetSender(k); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// 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, bool usePhysics, |
|
const plString &animName, bool drivable, bool reversible) |
|
{ |
|
if ( fRecvr.Count() > 0 ) |
|
{ |
|
// create message |
|
plAvOneShotMsg* pMsg = new plAvOneShotMsg( |
|
(plKey )fSender, |
|
nil, |
|
seekKey.getKey(), // Mark D told me to do it ...paulg |
|
duration, |
|
usePhysics, |
|
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, bool netForce, bool 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 = 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 = 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, bool netForce, bool 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 = 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, float transTime, bool setTime, float newTime, |
|
bool setDirection, bool isForward, bool 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 = new plAvBrainGenericMsg((plKey)fSender, avKey, |
|
plAvBrainGenericMsg::kNextStage, 0, setTime, newTime, |
|
setDirection, 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, float transTime, bool setTime, float newTime, |
|
bool setDirection, bool isForward, bool 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 = new plAvBrainGenericMsg((plKey)fSender, avKey, |
|
plAvBrainGenericMsg::kPrevStage, 0, setTime, newTime, |
|
setDirection, 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_t stage, float transTime, bool setTime, float newTime, |
|
bool setDirection, bool isForward, bool 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 = 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_t stage, int32_t loopCount, bool netForce) |
|
{ |
|
// if it is a Multistage guy |
|
if ( plMultistageBehMod::ConvertNoRef(behKey.getKey()->GetObjectPtr()) != nil ) |
|
{ |
|
plMultistageModMsg* pMsg = new plMultistageModMsg((plKey)nil, behKey.getKey()); |
|
pMsg->SetCommand(plMultistageModMsg::kSetLoopCount); |
|
pMsg->fStageNum = (uint8_t)stage; |
|
pMsg->fNumLoops = (uint8_t)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, bool usePhysics) |
|
{ |
|
// must have a receiver! |
|
if ( fRecvr.Count() > 0 ) |
|
{ |
|
// create message |
|
plAvSeekMsg* pMsg = 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_t 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_t 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_t 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_t 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 |
|
// |
|
bool 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 |
|
// |
|
bool 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 |
|
// |
|
bool 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 |
|
// |
|
bool cyAvatar::TintClothingItemLayer(const char* clothing_name, pyColor& tint, uint8_t 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 |
|
// |
|
bool cyAvatar::WearClothingItemU(const char* clothing_name, bool 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 |
|
// |
|
bool cyAvatar::RemoveClothingItemU(const char* clothing_name, bool 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 |
|
// |
|
bool cyAvatar::TintClothingItemU(const char* clothing_name, pyColor& tint, bool 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 |
|
// |
|
bool cyAvatar::TintClothingItemLayerU(const char* clothing_name, pyColor& tint, uint8_t layer, bool 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_t 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); |
|
} |
|
} |
|
} |
|
|
|
plString errmsg = plString::Format("Cannot find clothing item %s to find out what tint it is", clothing_name); |
|
PyErr_SetString(PyExc_KeyError, errmsg.c_str()); |
|
// 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, bool 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); |
|
} |
|
} |
|
|
|
PyErr_SetString(PyExc_KeyError, "Cannot find the skin of the player. Whatever that means!"); |
|
// 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_t 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_t 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_t 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_t 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 = 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 = 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 plString& 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 : SaveClothingToFile |
|
// PARAMETERS : filename - file to save to |
|
// |
|
// PURPOSE : Save the avatar's clothing to a file. If only a filename is |
|
// given, it will write to UserData/Avatars. |
|
// |
|
bool cyAvatar::SaveClothingToFile(plFileName filename) |
|
{ |
|
if (fRecvr.Count() > 0) { |
|
plArmatureMod* avatar = plAvatarMgr::FindAvatar(fRecvr[0]); |
|
if (avatar) { |
|
plClothingOutfit* cl = avatar->GetClothingOutfit(); |
|
if (cl) { |
|
// Save file in UserData/Avatars if only a filename is given |
|
if (!filename.StripFileName().IsValid()) { |
|
plFileName path = plFileName::Join(plFileSystem::GetUserDataPath(), "Avatars"); |
|
plFileSystem::CreateDir(path, true); |
|
filename = plFileName::Join(path, filename); |
|
} |
|
return cl->WriteToFile(filename); |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : LoadClothingFromFile |
|
// PARAMETERS : filename - file to load from |
|
// |
|
// PURPOSE : Load the avatar's clothing from a file. If only a filename is |
|
// given, it will read from UserData/Avatars. |
|
// |
|
bool cyAvatar::LoadClothingFromFile(plFileName filename) |
|
{ |
|
if (fRecvr.Count() > 0) { |
|
plArmatureMod* avatar = plAvatarMgr::FindAvatar(fRecvr[0]); |
|
if (avatar) { |
|
plClothingOutfit* cl = avatar->GetClothingOutfit(); |
|
if (cl) { |
|
// Search for file in UserData/Avatars if only a filename is given |
|
if (!filename.StripFileName().IsValid()) |
|
filename = plFileName::Join(plFileSystem::GetUserDataPath(), "Avatars", filename); |
|
cl->SetClothingFile(filename); |
|
return cl->ReadClothing(); |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// 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_t 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_t 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(float val) |
|
{ |
|
plArmatureMod::SetMouseTurnSensitivity(val); |
|
} |
|
|
|
float 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 = 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 |
|
// |
|
bool cyAvatar::IsCurrentBrainHuman() |
|
{ |
|
plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar(); |
|
if (avatar) |
|
{ |
|
plArmatureBrain *brain = avatar->GetCurrentBrain(); |
|
plAvBrainHuman *human = plAvBrainHuman::ConvertNoRef(brain); |
|
if (human) |
|
return true; |
|
} |
|
return false; |
|
}
|
|
|