thug/Code/Sk/Components/SkaterFlipAndRotateComponent.cpp
2016-02-14 08:39:12 +11:00

388 lines
14 KiB
C++

//****************************************************************************
//* MODULE: Sk/Components
//* FILENAME: SkaterFlipAndRotateComponent.cpp
//* OWNER: Dan
//* CREATION DATE: 3/31/3
//****************************************************************************
/*
* Encapsulates the dirty, dirty skater flip, skater rotate, and board rotate animation logic.
*
* "Please!" says CSkaterFlipAndRotateComponent, "Deprecate me, and end my torturous existence!"
*/
#include <sk/components/skaterflipandrotatecomponent.h>
#include <sk/components/skatercorephysicscomponent.h>
#include <sk/components/skaterstatecomponent.h>
#include <sk/gamenet/gamenet.h>
#include <gel/object/compositeobject.h>
#include <gel/components/animationcomponent.h>
#include <gel/components/modelcomponent.h>
#include <gel/scripting/checksum.h>
#include <gel/scripting/script.h>
#include <gel/scripting/struct.h>
#include <gel/net/client/netclnt.h>
namespace Obj
{
extern bool DebugSkaterScripts;
/******************************************************************/
/* */
/* */
/******************************************************************/
CBaseComponent* CSkaterFlipAndRotateComponent::s_create()
{
return static_cast< CBaseComponent* >( new CSkaterFlipAndRotateComponent );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CSkaterFlipAndRotateComponent::CSkaterFlipAndRotateComponent() : CBaseComponent()
{
SetType( CRC_SKATERFLIPANDROTATE );
mp_animation_component = NULL;
mp_model_component = NULL;
m_rotate_board = false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CSkaterFlipAndRotateComponent::~CSkaterFlipAndRotateComponent()
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::InitFromStructure( Script::CStruct* pParams )
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::RefreshFromStructure( Script::CStruct* pParams )
{
InitFromStructure(pParams);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::Finalize ( )
{
// Note: Non-local clients have a CSkaterFlipAndRotateComponent, but not a CSkaterCorePhysicsComponent.
mp_core_physics_component = GetSkaterCorePhysicsComponentFromObject(GetObject());
mp_model_component = GetModelComponentFromObject(GetObject());
mp_animation_component = GetAnimationComponentFromObject(GetObject());
Dbg_Assert(mp_model_component);
Dbg_Assert(mp_animation_component);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::Update()
{
Suspend(true);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CBaseComponent::EMemberFunctionResult CSkaterFlipAndRotateComponent::CallMemberFunction( uint32 Checksum, Script::CStruct* pParams, Script::CScript* pScript )
{
switch ( Checksum )
{
// @script | Flip | flip animation
case CRCC(0x65011baa, "Flip"):
ToggleFlipState();
break;
// @script | ResetSwitched | flip if we're switched
case CRCC(0x72289a28, "ResetSwitched"):
Dbg_Assert(mp_core_physics_component);
if (mp_core_physics_component->IsSwitched())
{
ToggleFlipState();
}
break;
// These three just set flags, which will cause the appropriate flip/rotate
// when the next PlayAnim occurs.
// @script | FlipAfter | sets flag, which will cause the appropriate flip/rotate when the next PlayAnim occurs
case CRCC(0xeba11b20, "FlipAfter"):
mFlipAfter = true;
break;
// @script | RotateAfter | sets flag, which will cause the appropriate flip/rotate when the next PlayAnim occurs
case CRCC(0xacac1bad, "RotateAfter"):
mRotateAfter = true;
break;
// @script | BoardRotateAfter | sets flag, which will cause the appropriate flip/rotate when the next PlayAnim occurs
case CRCC(0x63e93f69, "BoardRotateAfter"):
mBoardRotateAfter = true;
break;
// @script | IsFlipAfterSet | returns mFlipAfter
case CRCC(0xa6243daa, "IsFlipAfterSet"):
return mFlipAfter ? CBaseComponent::MF_TRUE : CBaseComponent::MF_FALSE;
// @script | FlipAndRotate | flip Z and X, to rotate 180 degrees about y
case CRCC(0xd9de0c65, "FlipAndRotate"):
{
Dbg_Assert(mp_core_physics_component);
mp_core_physics_component->ReverseFacing();
ToggleFlipState();
break;
}
// @script | BoardRotate |
// @flag normal | put the board back to normal (otherwise just flip)
case CRCC(0xe0f3a644, "BoardRotate"):
{
GameNet::PlayerInfo* player = GameNet::Manager::Instance()->GetPlayerByObjectID(GetObject()->GetID());
Dbg_Assert(player);
Net::Client* client = GameNet::Manager::Instance()->GetClient(player->GetSkaterNumber());
Dbg_Assert(client);
if (pParams->ContainsFlag(CRCD(0xde7a971b, "Normal")))
{
// Put the board back to normal
RotateSkateboard(GetObject()->GetID(), false, client->m_Timestamp, true);
}
else
{
// Otherwise flip it, flip it good.
RotateSkateboard(GetObject()->GetID(), !m_rotate_board, client->m_Timestamp, true);
}
break;
}
// @script | BoardIsRotated |
case CRCC(0x79ee5ccf, "BoardIsRotated"):
return m_rotate_board ? CBaseComponent::MF_TRUE : CBaseComponent::MF_FALSE;
case CRCC(0xb1e7291, "PlayAnim"):
// do any required flips and rotates, and then cascade the member function call
DoAnyFlipRotateOrBoardRotateAfters();
return CBaseComponent::MF_NOT_EXECUTED;
default:
return CBaseComponent::MF_NOT_EXECUTED;
}
return CBaseComponent::MF_TRUE;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::GetDebugInfo(Script::CStruct *p_info)
{
#ifdef __DEBUG_CODE__
Dbg_MsgAssert(p_info,("NULL p_info sent to CSkaterFlipAndRotateComponent::GetDebugInfo"));
if (mp_core_physics_component)
{
p_info->AddChecksum(CRCD(0x8f66b80b, "switched"), mp_core_physics_component->IsSwitched() ? CRCD(0x203b372, "true") : CRCD(0xd43297cf, "false"));
}
p_info->AddChecksum(CRCD(0xc7a712c, "flipped"), GetSkaterStateComponentFromObject(GetObject())->GetFlag(FLIPPED) ? CRCD(0x203b372, "true") : CRCD(0xd43297cf, "false"));
p_info->AddChecksum(CRCD(0xeba11b20, "FlipAfter"), mFlipAfter ? CRCD(0x203b372, "true") : CRCD(0xd43297cf, "false"));
p_info->AddChecksum(CRCD(0xacac1bad, "RotateAfter"), mRotateAfter ? CRCD(0x203b372, "true") : CRCD(0xd43297cf, "false"));
p_info->AddChecksum(CRCD(0x63e93f69, "BoardRotateAfter"), mBoardRotateAfter ? CRCD(0x203b372, "true") : CRCD(0xd43297cf, "false"));
CBaseComponent::GetDebugInfo(p_info);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CSkaterFlipAndRotateComponent::RotateSkateboard ( uint32 objId, bool rotate, uint32 time, bool propagate )
{
if ( propagate )
{
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
GameNet::PlayerInfo* player;
player = gamenet_man->GetPlayerByObjectID( objId );
if( player && player->IsLocalPlayer())
{
Net::Client* client;
GameNet::MsgRotateSkateboard msg;
Net::MsgDesc msg_desc;
client = gamenet_man->GetClient( player->GetSkaterNumber());
Dbg_Assert( client );
msg.m_Rotate = rotate;
msg.m_ObjId = objId;
msg_desc.m_Data = &msg;
msg_desc.m_Id = GameNet::MSG_ID_ROTATE_SKATEBOARD;
msg_desc.m_Length = sizeof( GameNet::MsgRotateSkateboard );
client->EnqueueMessageToServer( &msg_desc );
}
}
bool oldRotation = m_rotate_board;
m_rotate_board = rotate;
#ifdef __NOPT_ASSERT__
if (DebugSkaterScripts && GetObject()->GetType() == SKATE_TYPE_SKATER)
{
printf("%d: Rotating board [rotated = %s]\n", (int) Tmr::GetRenderFrame(), m_rotate_board ? "true" : "false");
}
#endif
return oldRotation;
}
/******************************************************************/
/*
If any of mFlipAfter, mRotateAfter or mBoardRotateAfter are set
this will flip or rotate the skater, or rotate the board, and then
reset those flags.
Quite often the skater needs to be flipped and/or rotated in order to
look correctly oriented, due to the way the animations are done.
For example, the nollie heelflip animation is actually animated backwards,
so to look correct the skater has to be flipped and rotated just for the
duration of that animation.
As soon as any sort of 'event' happens that could result in an animation
change, or requires that the orientation be correct for the physics, then
the skater needs to be flipped and rotated back.
So in the script, when running the nollie heelflip anim, Scott will flip and
rotate the skater first so that he looks correct, then set FlipAfter and RotateAfter.
It used to be that I'd check the flags only in the next call to the PlayAnim script
member function.
However, this is often not early enough. For example, when the player lands whilst
doing a nollie heelflip, the land script will do some checks to see if the player
is facing backwards before doing a playanim, so it will wrongly think the player
is backwards, when he isn't 'really'.
So instead I sprinkled calls to the following function whenever anything happens
that could cause a new script to be executed. In particular, before every SetScript,
and also as soon as a grind gets detected, so that the grind maths won't think the
skater is backwards when landing from a nollie heelflip.
*/
/******************************************************************/
void CSkaterFlipAndRotateComponent::DoAnyFlipRotateOrBoardRotateAfters ( )
{
if (mFlipAfter)
{
ToggleFlipState();
mFlipAfter = false;
}
if (mRotateAfter)
{
Dbg_Assert(mp_core_physics_component);
mp_core_physics_component->ReverseFacing();
mRotateAfter = false;
}
if (mBoardRotateAfter)
{
GameNet::PlayerInfo* player = GameNet::Manager::Instance()->GetPlayerByObjectID(GetObject()->GetID());
Dbg_Assert(player);
Net::Client* client = GameNet::Manager::Instance()->GetClient(player->GetSkaterNumber());
Dbg_Assert(client);
// Rotate the board.
RotateSkateboard(GetObject()->GetID(), !m_rotate_board, client->m_Timestamp, true);
mBoardRotateAfter = false;
}
// This makes the skater display facing the correct way again.
// The mFlipDisplayMatrix is only used when falling back in from a lip trick.
// Since it would be bad if this flag got left on, make sure it is off whenever
// a new anim runs. This function is a good place to put it, since it gets
// run whenever the anim changes.
mp_model_component->mFlipDisplayMatrix = false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::Reset ( )
{
mFlipAfter = false;
mRotateAfter = false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::ToggleFlipState ( )
{
GetSkaterStateComponentFromObject(GetObject())->m_skater_flags[FLIPPED].Toggle();
#ifdef __NOPT_ASSERT__
if (DebugSkaterScripts && GetObject()->GetType() == SKATE_TYPE_SKATER)
{
printf("%d: Flipping skater [flipped = %s]\n", (int) Tmr::GetRenderFrame(), mp_core_physics_component->GetFlag(FLIPPED) ? "true" : "false");
}
#endif
// Flip the animation to the correct orientation Just setting a flag for Dave's code to handle when rendering
ApplyFlipState();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CSkaterFlipAndRotateComponent::ApplyFlipState ( )
{
Net::Client* client = GameNet::Manager::Instance()->GetClient(GetSkater()->GetSkaterNumber());
Dbg_Assert(client);
mp_animation_component->FlipAnimation(GetObject()->GetID(), GetSkaterStateComponentFromObject(GetObject())->GetFlag(FLIPPED), client->m_Timestamp, true);
}
}