Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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;
}