diff --git a/Sources/Plasma/FeatureLib/pfPython/cyAvatar.cpp b/Sources/Plasma/FeatureLib/pfPython/cyAvatar.cpp index a4e00c5c..94add76f 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyAvatar.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/cyAvatar.cpp @@ -356,6 +356,69 @@ void cyAvatar::RunBehaviorAndReply(pyKey& behKey, pyKey& replyKey, bool netForce } +///////////////////////////////////////////////////////////////////////////// +// +// Function : RunCoopAnim +// PARAMETERS : targetKey - target avatar pyKey +// activeAvatarAnim - animation name +// targetAvatarAnim - animation name +// range - how far away are we allowed to be? (default in glue: 6) +// dist - how close shall the avatar move? (default in glue: 3) +// move - shall he move at all? (default in glue: true) +// +// PURPOSE : Seek near another avatar and run animations on both +// +bool cyAvatar::RunCoopAnim(pyKey& targetKey, plString activeAvatarAnim, plString targetAvatarAnim, float range, float dist, bool move) +{ + if (fRecvr.Count() > 0 && fRecvr[0]) { + // get the participating avatars + plArmatureMod* activeAv = plAvatarMgr::FindAvatar(fRecvr[0]); + plArmatureMod* targetAv = plAvatarMgr::FindAvatar(targetKey.getKey()); + activeAvatarAnim = activeAv->MakeAnimationName(activeAvatarAnim); + targetAvatarAnim = targetAv->MakeAnimationName(targetAvatarAnim); + + if (activeAv && targetAv) { + // set seek position and rotation of the avatars + hsPoint3 avPos, targetPos; + activeAv->GetPositionAndRotationSim(&avPos, nullptr); + targetAv->GetPositionAndRotationSim(&targetPos, nullptr); + hsVector3 av2target(&targetPos, &avPos); //targetPos - avPos + if (av2target.Magnitude() > range) + return false; + av2target.Normalize(); + if (move) + avPos = targetPos - dist * av2target; + + // create the messages and let one task queue the next + const int bcastToNetMods = plMessage::kNetPropagate | plMessage::kNetForce | plMessage::kPropagateToModifiers; + plAvOneShotMsg *avAnim = new plAvOneShotMsg(nullptr, fRecvr[0], fRecvr[0], 0.f, true, activeAvatarAnim, false, false); + avAnim->SetBCastFlag(bcastToNetMods); + + plAvOneShotMsg *targetAnim = new plAvOneShotMsg(nullptr, targetKey.getKey(), targetKey.getKey(), 0.f, true, targetAvatarAnim, false, false); + targetAnim->SetBCastFlag(bcastToNetMods); + targetAnim->fFinishMsg = avAnim; + + plAvSeekMsg *targetSeek = new plAvSeekMsg(nullptr, targetKey.getKey(), nullptr, 0.f, true); + targetSeek->SetBCastFlag(bcastToNetMods); + targetSeek->fTargetPos = targetPos; + targetSeek->fTargetLookAt = avPos; + targetSeek->fFinishMsg = targetAnim; + + plAvSeekMsg *avSeek = new plAvSeekMsg(nullptr, fRecvr[0], nullptr, 0.f, true); + avSeek->SetBCastFlag(bcastToNetMods); + avSeek->fTargetPos = avPos; + avSeek->fTargetLookAt = targetPos; + avSeek->fFinishMsg = targetSeek; + + // start the circus, messages are processed "backwards" + avSeek->Send(); + return true; + } + } + return false; +} + + ///////////////////////////////////////////////////////////////////////////// // // Function : NextStage diff --git a/Sources/Plasma/FeatureLib/pfPython/cyAvatar.h b/Sources/Plasma/FeatureLib/pfPython/cyAvatar.h index fa7973df..2db1369e 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyAvatar.h +++ b/Sources/Plasma/FeatureLib/pfPython/cyAvatar.h @@ -105,6 +105,7 @@ public: // oneShot Avatar virtual void RunBehavior(pyKey &behKey, bool netForce, bool netProp); virtual void RunBehaviorAndReply(pyKey& behKey, pyKey& replyKey, bool netForce, bool netProp); + virtual bool RunCoopAnim(pyKey& targetKey, plString activeAvatarAnim, plString targetAvatarAnim, float range, float dist, bool move); // for the multistage behaviors virtual void NextStage(pyKey &behKey, float transTime, bool setTime, float newTime, diff --git a/Sources/Plasma/FeatureLib/pfPython/cyAvatarGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/cyAvatarGlue.cpp index 605eb562..bd7b09e0 100644 --- a/Sources/Plasma/FeatureLib/pfPython/cyAvatarGlue.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/cyAvatarGlue.cpp @@ -139,6 +139,27 @@ PYTHON_METHOD_DEFINITION(ptAvatar, runBehaviorSetNotify, args) PYTHON_RETURN_NONE; } +PYTHON_METHOD_DEFINITION(ptAvatar, runCoopAnim, args) +{ + PyObject* keyObj; + PyObject* animAv1; + PyObject* animAv2; + float range = 6; + float dist = 3; + bool move = true; + if (!PyArg_ParseTuple(args, "OOO|ffb", &keyObj, &animAv1, &animAv2, &range, &dist, &move) || !pyKey::Check(keyObj) || + !PyString_CheckEx(animAv1) || !PyString_CheckEx(animAv2)) + { + PyErr_SetString(PyExc_TypeError, "runCoopAnim expects a ptkey and two strings and an optional float and boolean"); + PYTHON_RETURN_ERROR; + } + + pyKey* key = pyKey::ConvertFrom(keyObj); + const plString& animName1 = PyString_AsStringEx(animAv1); + const plString& animName2 = PyString_AsStringEx(animAv2); + PYTHON_RETURN_BOOL(self->fThis->RunCoopAnim(*key, animName1, animName2, range, dist, move)); +} + PYTHON_METHOD_DEFINITION(ptAvatar, nextStage, args) { PyObject* keyObj = NULL; @@ -629,6 +650,7 @@ PYTHON_START_METHODS_TABLE(ptAvatar) PYTHON_METHOD(ptAvatar, oneShot, "Params: seekKey,duration,usePhysicsFlag,animationName,drivableFlag,reversibleFlag\nPlays a one-shot animation on the avatar"), PYTHON_METHOD(ptAvatar, runBehavior, "Params: behaviorKey,netForceFlag\nRuns a behavior on the avatar. Can be a single or multi-stage behavior."), PYTHON_METHOD(ptAvatar, runBehaviorSetNotify, "Params: behaviorKey,replyKey,netForceFlag\nSame as runBehavior, except send notifications to specified keyed object"), + PYTHON_METHOD(ptAvatar, runCoopAnim, "Params: targetKey,activeAvatarAnim,targetAvatarAnim,dist,move\nSeek near another avatar and run animations on both."), PYTHON_METHOD(ptAvatar, nextStage, "Params: behaviorKey,transitionTime,setTimeFlag,newTime,SetDirectionFlag,isForward,netForce\nTells a multistage behavior to go to the next stage (Why does Matt like so many parameters?)"), PYTHON_METHOD(ptAvatar, previousStage, "Params: behaviorKey,transitionTime,setTimeFlag,newTime,SetDirectionFlag,isForward,netForce\nTells a multistage behavior to go to the previous stage"), PYTHON_METHOD(ptAvatar, gotoStage, "Params: behaviorKey,stage,transitionTime,setTimeFlag,newTime,SetDirectionFlag,isForward,netForce\nTells a multistage behavior to go to a particular stage"),