Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
536 lines
19 KiB
C++
536 lines
19 KiB
C++
//===========================================================================//
|
|
// File: falltool.cpp
|
|
// Project: MechWarrior 4
|
|
// Contents: Plugin to modify mech falling animations
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 05/26/99 jkyle Initial coding,
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1999, Fasa Interactive, Inc.
|
|
// All Rights reserved worldwide
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
|
|
//===========================================================================//
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifdef STRICT // Already defined by stdafx,
|
|
#undef STRICT // so we avoid warning linking msg
|
|
#endif
|
|
#ifdef _MBCS // The same as above
|
|
#undef _MBCS
|
|
#endif
|
|
|
|
|
|
#include "FallTool.hpp"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// ProtoTypes
|
|
int NegateKeys(Control *pControl,int key_number = 0);
|
|
int SwapKeys(Control *pCtrl1,Control *pCtrl2,int key_number = 0);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Global Variables
|
|
FallToolPanel g_fallToolPanel;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// FallToolPanel Dialog Procedure to handle User and System Interactions
|
|
static BOOL CALLBACK FallToolPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
switch (msg) {
|
|
case WM_INITDIALOG: //Panel's extra initialization
|
|
g_fallToolPanel.Init(hWnd);
|
|
break;
|
|
case WM_DESTROY: //Panel's extra destruction
|
|
g_fallToolPanel.Destroy(hWnd);
|
|
break;
|
|
case WM_COMMAND :
|
|
switch (LOWORD(wParam)) { //Handle Panel's controls
|
|
case IDC_ABOUT: {
|
|
CAbout dlg;
|
|
dlg.DoModal();
|
|
break;}
|
|
case IDC_FALLTOOL_FALLLEFT:
|
|
{
|
|
// Spec is reversed
|
|
g_fallToolPanel.m_iFallType = FallToolPanel::FALL_RIGHT;
|
|
break;
|
|
}
|
|
case IDC_FALLTOOL_FALLRIGHT:
|
|
{
|
|
g_fallToolPanel.m_iFallType = FallToolPanel::FALL_LEFT;
|
|
break;
|
|
}
|
|
case IDC_FALLTOOL_FALLBACK:
|
|
{
|
|
g_fallToolPanel.m_iFallType = FallToolPanel::FALL_BACK;
|
|
break;
|
|
}
|
|
case IDC_FALLTOOL_EXECUTE:
|
|
{
|
|
g_fallToolPanel.ExecuteFallTool();
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//The following lines are not necessary for MAX2 Plugins
|
|
case WM_LBUTTONDOWN:
|
|
case WM_LBUTTONUP:
|
|
case WM_MOUSEMOVE:
|
|
g_fallToolPanel.m_ip->RollupMouseMessage(hWnd, msg, wParam, lParam);
|
|
break;
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Display the Plugin's Panel
|
|
void FallToolPanel::BeginEditParams(Interface* ip, IUtil* iu)
|
|
{
|
|
m_ip = ip; //Get the Plugin's Interface
|
|
m_iu = iu; //Get the Utility Plugin's Interface
|
|
|
|
//Display the plugin's Rollup Dialog
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
HINSTANCE loc_hInstance = AfxGetResourceHandle ();
|
|
|
|
m_hPanel = m_ip->AddRollupPage(loc_hInstance, MAKEINTRESOURCE(IDD_FALLTOOL_PANEL),
|
|
FallToolPanelProc, GetString(IDS_FALLTOOL_NAME),0);
|
|
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Free the Plugins' Panel
|
|
void FallToolPanel::EndEditParams(Interface *ip, IUtil *iu)
|
|
{
|
|
m_iu = NULL;
|
|
m_ip = NULL;
|
|
|
|
//Remove the Rollup Dialog
|
|
ip->DeleteRollupPage(m_hPanel);
|
|
m_hPanel = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Panel Initialization callback
|
|
void FallToolPanel::Init(HWND hWnd)
|
|
{
|
|
SendDlgItemMessage(hWnd, IDC_FALLTOOL_FALLLEFT, BM_SETCHECK, (WPARAM)BST_CHECKED, 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Panel Destruction callback
|
|
void FallToolPanel::Destroy(HWND hWnd)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Execute the fall tool
|
|
int FallToolPanel::ExecuteFallTool()
|
|
{
|
|
INode *pjoint_VEL = m_ip->GetINodeByName("joint_VEL");
|
|
INode *pjoint_ROOT = m_ip->GetINodeByName("joint_ROOT");
|
|
INode *phandle_lfoot = m_ip->GetINodeByName("handle_lfoot");
|
|
INode *phandle_rfoot = m_ip->GetINodeByName("handle_rfoot");
|
|
// Make sure we have all of these nodes, or else the model will mess up pretty bad
|
|
if (pjoint_VEL && pjoint_ROOT && phandle_lfoot && phandle_rfoot)
|
|
{
|
|
// Adjust pjoint_VEL
|
|
if (TRUE)
|
|
{
|
|
// Adjust the joint_VEL node
|
|
if (Control *pControl = pjoint_VEL->GetTMController())
|
|
{
|
|
// Adjust the position controllers
|
|
if (Control *pPosControl = pControl->GetPositionController())
|
|
{
|
|
// Adjust the XPosition Controller
|
|
Control *pXControl = NULL;
|
|
|
|
if (pXControl = pPosControl->GetXController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pXControl))
|
|
{
|
|
if (pKeyControl->GetNumKeys()<1)
|
|
return -1;
|
|
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_LEFT:
|
|
{
|
|
break;
|
|
}
|
|
case FALL_RIGHT:
|
|
{
|
|
break;
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
NegateKeys(pXControl);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adjust the YPosition Controller
|
|
if (Control *pYControl = pPosControl->GetYController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pYControl))
|
|
{
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_RIGHT:
|
|
{
|
|
SwapKeys(pYControl,pXControl);
|
|
NegateKeys(pXControl);
|
|
NegateKeys(pYControl);
|
|
break;
|
|
}
|
|
case FALL_LEFT:
|
|
{
|
|
SwapKeys(pYControl,pXControl);
|
|
// Fall through to negate key
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
NegateKeys(pYControl);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adjust the rotation controllers
|
|
if (Control *pRotControl = pControl->GetRotationController())
|
|
{
|
|
// Adjust the ZRotation Controller
|
|
if (Control *pZControl = pRotControl->GetZController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pZControl))
|
|
{
|
|
float rot = (float)M_PI;
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_RIGHT:
|
|
{
|
|
rot *= -1.0;
|
|
}
|
|
case FALL_LEFT:
|
|
{
|
|
rot /= -2.0;
|
|
// Fall through to FALL_BACK
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
IBezFloatKey key;
|
|
key.time = 0;
|
|
//key.flags = IKEY_ZSEL;
|
|
key.val = 0;
|
|
key.intan = 0;
|
|
key.outtan = 0;
|
|
pKeyControl->AppendKey(&key);
|
|
Interval iv = m_ip->GetAnimRange();
|
|
key.time = iv.End();
|
|
key.val = rot;
|
|
pKeyControl->AppendKey(&key);
|
|
pKeyControl->SortKeys();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adjust the foot nodes - same for both feet
|
|
if (TRUE)
|
|
{
|
|
int foot = 2;
|
|
do
|
|
{
|
|
foot--;
|
|
Control *pControl= NULL;
|
|
if (1==foot)
|
|
pControl = phandle_lfoot->GetTMController();
|
|
else
|
|
pControl = phandle_rfoot->GetTMController();
|
|
|
|
if (pControl)
|
|
{
|
|
if (Control *pPosControl = pControl->GetPositionController())
|
|
{
|
|
//Adjust the XPosition
|
|
Control *pXControl;
|
|
if (pXControl = pPosControl->GetXController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pXControl))
|
|
{
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_LEFT:
|
|
{
|
|
break;
|
|
}
|
|
case FALL_RIGHT:
|
|
{
|
|
break;
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
NegateKeys(pXControl,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//Adjust the YPosition
|
|
if (Control *pYControl = pPosControl->GetYController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pYControl))
|
|
{
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_RIGHT:
|
|
{
|
|
NegateKeys(pYControl,1);
|
|
}
|
|
case FALL_LEFT:
|
|
{
|
|
// Fall through to negate Y in FALL_BACK
|
|
SwapKeys(pYControl,pXControl,1);
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
if (m_iFallType != FALL_RIGHT)
|
|
NegateKeys(pYControl,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Control *pRotControl = pControl->GetRotationController())
|
|
{
|
|
//Adjust the ZRotation Controller
|
|
if (Control *pZControl = pRotControl->GetZController())
|
|
{
|
|
if (IKeyControl *pKeyControl = GetKeyControlInterface(pZControl))
|
|
{
|
|
float rot = (float)M_PI;
|
|
switch (m_iFallType)
|
|
{
|
|
case FALL_LEFT:
|
|
{
|
|
rot *= -1.0;
|
|
}
|
|
case FALL_RIGHT:
|
|
{
|
|
rot /= 2.0;
|
|
// Fall through to FALL_BACK
|
|
}
|
|
case FALL_BACK:
|
|
{
|
|
IBezFloatKey key;
|
|
int i;
|
|
pKeyControl->GetKey(i = (pKeyControl->GetNumKeys()-1),&key);
|
|
key.val += rot;
|
|
pKeyControl->SetKey(i,&key);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} while (foot);
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
int NegateKeys(Control *pControl,int key_number)
|
|
{
|
|
int MaxKeys;
|
|
IKeyControl *ikc = GetKeyControlInterface(pControl);
|
|
Class_ID id = pControl->ClassID();
|
|
|
|
MaxKeys=ikc->GetNumKeys();
|
|
|
|
for(;key_number<MaxKeys;key_number++)
|
|
{
|
|
if (id == Class_ID(LININTERP_FLOAT_CLASS_ID,0))
|
|
{
|
|
ILinFloatKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val=key.val*-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
|
|
{
|
|
IBezFloatKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val*=-1;
|
|
key.intan*=-1;
|
|
key.outtan*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))
|
|
{
|
|
ITCBFloatKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(LININTERP_POSITION_CLASS_ID,0))
|
|
{
|
|
ILinPoint3Key key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.x*=-1;
|
|
key.val.y*=-1;
|
|
key.val.z*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(HYBRIDINTERP_POSITION_CLASS_ID,0))
|
|
{
|
|
IBezPoint3Key key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.x*=-1;
|
|
key.intan.x*=-1;
|
|
key.outtan.x*=-1;
|
|
key.val.y*=-1;
|
|
key.intan.y*=-1;
|
|
key.outtan.y*=-1;
|
|
key.val.z*=-1;
|
|
key.intan.z*=-1;
|
|
key.outtan.z*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(TCBINTERP_POSITION_CLASS_ID,0))
|
|
{
|
|
ITCBPoint3Key key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.x*=-1;
|
|
key.val.y*=-1;
|
|
key.val.z*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(LININTERP_ROTATION_CLASS_ID,0))
|
|
{
|
|
ILinRotKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.w*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0))
|
|
{
|
|
IBezQuatKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.w*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(TCBINTERP_ROTATION_CLASS_ID,0))
|
|
{
|
|
ITCBRotKey key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.angle*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(HYBRIDINTERP_POINT3_CLASS_ID,0))
|
|
{
|
|
IBezPoint3Key key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.x*=-1;
|
|
key.val.y*=-1;
|
|
key.val.z*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
else if (id == Class_ID(TCBINTERP_POINT3_CLASS_ID,0))
|
|
{
|
|
ITCBPoint3Key key;
|
|
ikc->GetKey(key_number, &key);
|
|
key.val.x*=-1;
|
|
key.val.y*=-1;
|
|
key.val.z*=-1;
|
|
ikc->SetKey(key_number, &key);
|
|
}
|
|
} // end of for i
|
|
|
|
return MaxKeys;
|
|
}
|
|
|
|
static int SwapKeys(Control *pCtrl1,Control *pCtrl2,int key_number)
|
|
{
|
|
if (!(pCtrl1 && pCtrl2))
|
|
{
|
|
return 0;
|
|
}
|
|
// Only swap same IDs
|
|
Class_ID id;
|
|
if ((id = pCtrl1->ClassID()) != pCtrl2->ClassID())
|
|
return 1;
|
|
IKeyControl *pKey1 = GetKeyControlInterface(pCtrl1);
|
|
IKeyControl *pKey2 = GetKeyControlInterface(pCtrl2);
|
|
int MaxKeys1 = pKey1->GetNumKeys();
|
|
int MaxKeys2 = pKey2->GetNumKeys();
|
|
|
|
// First copy all the keys, then delete them from both controls, then append them back
|
|
if (id == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))
|
|
{
|
|
|
|
IBezFloatKey *keyarr = new IBezFloatKey[MaxKeys1-key_number];
|
|
for (int i=key_number;i<MaxKeys1;i++)
|
|
{
|
|
IBezFloatKey key;
|
|
pKey1->GetKey(i,&keyarr[i-key_number]);
|
|
}
|
|
pKey1->SetNumKeys(key_number);
|
|
for (i=key_number;i<MaxKeys2;i++)
|
|
{
|
|
IBezFloatKey key;
|
|
pKey2->GetKey(i,&key);
|
|
pKey1->AppendKey(&key);
|
|
}
|
|
pKey2->SetNumKeys(key_number);
|
|
for (i=0;i<(MaxKeys1-key_number);i++)
|
|
{
|
|
IBezFloatKey key;
|
|
pKey2->AppendKey(&keyarr[i]);
|
|
}
|
|
|
|
delete keyarr;
|
|
pKey1->SortKeys();
|
|
pKey2->SortKeys();
|
|
}
|
|
return 0;
|
|
}
|