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.

2000 lines
70 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/>.
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 "HeadSpin.h"
// singular
#include "plPhysicalComponents.h"
// local
#include "plComponentReg.h"
#include "resource.h"
// global
#include "hsResMgr.h"
// other
#include "../plPhysical/plSimDefs.h"
#include "plPhysicsGroups.h"
#include "../MaxMain/plMaxNode.h"
#include "../MaxMain/plPhysicalProps.h"
#include "../MaxMain/plPlasmaRefMsgs.h"
#include "../plPhysical/plCollisionDetector.h"
#include "../pnMessage/plObjRefMsg.h"
#include "../plMessage/plSwimMsg.h"
#include "../plAvatar/plSwimRegion.h"
#include "../plMessage/plRideAnimatedPhysMsg.h"
/////////////////////////////////////////////////////////////////
//
// THE DUMMY
//
/////////////////////////////////////////////////////////////////
// Necessary to keep the compiler from throwing away this file.
void DummyCodeIncludeFuncPhys()
{
}
/////////////////////////////////////////////////////////////////
//
// plPhysicCoreComponent
//
/////////////////////////////////////////////////////////////////
// SetupProperties -----------------------------------------------------------------
// ----------------
hsBool plPhysicCoreComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
return true;
}
// PreConvert ----------------------------------------------------------------
// -----------
hsBool plPhysicCoreComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
// IFixBounds --------------------------
// -----------
void plPhysicCoreComponent::IFixBounds()
{
if (fCompPB->GetInt(kBoundCondRadio) == 0)
{
// zero is a bad value left over from an old version of the GUI: upgrade in place
fCompPB->Reset(kBoundCondRadio); // reset to default
}
}
// IGetProxy ----------------------------------------------------------------
// ----------
hsBool plPhysicCoreComponent::IGetProxy(plMaxNode *node, plErrorMsg *pErrMsg)
{
if (fCompPB->GetInt(kCustomBoundField))
{
plMaxNode *boundNode = (plMaxNode*)fCompPB->GetINode(kCustomBoundListStuff);
if (boundNode && boundNode->CanConvert())
return node->GetPhysicalProps()->SetProxyNode(boundNode, node, pErrMsg);
}
return true;
}
// Convert ----------------------------------------------------------------
// --------
hsBool plPhysicCoreComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
//! Global Accessor Class, used in ParamBlock2 processing.
/*!
When one of our parameters that is a ref changes, send out the component ref
changed message. Normally, messages from component refs are ignored since
they pass along all the messages of the ref, which generates a lot of false
converts.
*/
class plPhysCoreAccessor : public PBAccessor
{
public:
void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t)
{
if (id == plPhysicCoreComponent::kCustomBoundListStuff)
{
plComponentBase *comp = (plComponentBase*)owner;
comp->NotifyDependents(FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED);
}
}
};
plPhysCoreAccessor gPhysCoreAccessor;
/*
//! Physics Debug Component Class
class plPhysDebugComponent : public plPhysicCoreComponent
{
public:
plPhysDebugComponent();
hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables);
};
*/
OBSOLETE_CLASS(plPhysDebugComponent, gPhysDebugDesc, "Physics Debug", "PhysDebug", COMP_TYPE_PHYSICAL, PHYSICS_DEBUG_CID)
enum
{
kPhysMain,
kPhysMember,
kPhysBounce,
kPhysReport,
};
/*
ParamBlockDesc2 gPhysicalBk
(
plComponent::kBlkComp, _T("physicsDebug"), 0, &gPhysDebugDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
4,
kPhysMain, IDD_COMP_PHYSICAL, IDS_COMP_PHYS_DEBUG, 0, 0, NULL,
kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
kPhysReport, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_REPORT, 0, APPENDROLL_CLOSED, &gReportGroupProc,
// params
plPhysicCoreComponent::kMass, _T("Mass"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 500.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYSICAL_EDIT1, IDC_COMP_PHYSICAL_SPIN1, 1.0,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYSICAL_EDIT2, IDC_COMP_PHYSICAL_SPIN2, 0.1,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYSICAL_EDIT3, IDC_COMP_PHYSICAL_SPIN3, 0.1,
end,
plPhysicCoreComponent::kStartForceX, _T("StartForceX"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3SF_EDIT1,IDC_COMP_PHYSICAL_P3SF_SPIN1, 0.1f,
end,
plPhysicCoreComponent::kStartForceY, _T("StartForceY"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3SF_EDIT2,IDC_COMP_PHYSICAL_P3SF_SPIN2, 0.1f,
end,
plPhysicCoreComponent::kStartForceZ, _T("StartForceZ"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3SF_EDIT3,IDC_COMP_PHYSICAL_P3SF_SPIN3, 0.1f,
end,
plPhysicCoreComponent::kStartTorqueX, _T("StartTorqueX"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3ST_EDIT1,IDC_COMP_PHYSICAL_P3ST_SPIN1, 0.1f,
end,
plPhysicCoreComponent::kStartTorqueY, _T("StartTorqueY"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3ST_EDIT2,IDC_COMP_PHYSICAL_P3ST_SPIN2, 0.1f,
end,
plPhysicCoreComponent::kStartTorqueZ, _T("StartTorqueZ"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0f,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_PHYSICAL_P3ST_EDIT3,IDC_COMP_PHYSICAL_P3ST_SPIN3, 0.1f,
end,
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kCustomBoundListStuff, _T("UserBoundChoice"), TYPE_INODE, 0, 0,
p_ui, kPhysMain, TYPE_PICKNODEBUTTON, IDC_COMP_PHYS_PICKSTATE_BASE,
p_sclassID, GEOMOBJECT_CLASS_ID,
p_prompt, IDS_COMP_PHYS_CHOSEN_BASE,
p_accessor, &gPhysCoreAccessor,
end,
plPhysicCoreComponent::kCustomBoundField, _T("UserBoundCheckBx"), TYPE_BOOL, 0, 0,
p_default, false,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_CUSTOMCHK,
p_enable_ctrls, 1, plPhysicCoreComponent::kCustomBoundListStuff,
end,
plPhysicCoreComponent::kLOSChkBx, _T("LOSChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_CHECK_LOS,
end,
plPhysicCoreComponent::kAlignProxyShape, _T("AlignShapeChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_ALIGN_SHAPE_BOOL,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kReportGroups, _T("memberGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kGroup, _T("group"), TYPE_INT, 0,0,
end,
end
);
plPhysDebugComponent::plPhysDebugComponent()
{
fClassDesc = &gPhysDebugDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
void plPhysDebugComponent::CollectNonDrawables(INodeTab& nonDrawables)
{
if (fCompPB->GetInt(kCustomBoundField))
{
INode* boundsNode = fCompPB->GetINode(kCustomBoundListStuff);
if( boundsNode )
nonDrawables.Append(1, &boundsNode);
}
}
hsBool plPhysDebugComponent::SetupProperties(plMaxNode *node, plErrorMsg *errMsg)
{
IFixBounds();
plPhysicalProps *physProps = node->GetPhysicalProps();
physProps->SetMass(fCompPB->GetFloat(kMass), node, errMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), node, errMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), node, errMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), node, errMsg);
if(fCompPB->GetInt(kLOSChkBx))
physProps->SetLOSBlockCamera(true, node, errMsg); // *** we really need to have four check boxes now....
physProps->SetPinned(false, node, errMsg);
physProps->SetAlignToOwner(fCompPB->GetInt(kAlignProxyShape) != 0, node, errMsg);
physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD), node, errMsg);
physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups_DEAD), node, errMsg);
physProps->SetReportGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kReportGroups), node, errMsg);
return IGetProxy(node, errMsg);
}
*/
/////////////////////////////////////////////////////////////////////////////////////////
//
// plPhysTerrainComponent
//
/////////////////////////////////////////////////////////////////////////////////////////
class plPhysTerrainComponent : public plPhysicCoreComponent
{
public:
plPhysTerrainComponent();
hsBool SetupProperties(plMaxNode* node,plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables);
};
CLASS_DESC(plPhysTerrainComponent, gPhysTerrainDesc, "Terrain", "Terrain", COMP_TYPE_PHYSICAL, PHYSICS_TERRAIN_CID)
ParamBlockDesc2 gPhysTerrainBk
(
plComponent::kBlkComp, _T("Terrain"), 0, &gPhysTerrainDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_TERRAIN, IDS_COMP_PHYS_TERRAIN, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT2, IDC_COMP_PHYS_TERRAIN_SPIN2, 0.0001f,
end,
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kCustomBoundListStuff, _T("UserBoundChoice"), TYPE_INODE, 0, 0,
p_ui, kPhysMain, TYPE_PICKNODEBUTTON, IDC_COMP_PHYS_PICKSTATE_TERRAIN,
p_sclassID, GEOMOBJECT_CLASS_ID,
p_prompt, IDS_COMP_PHYS_CHOSEN_TERRAIN,
p_accessor, &gPhysCoreAccessor,
end,
plPhysicCoreComponent::kCustomBoundField, _T("UserBoundCheckBx"), TYPE_BOOL, 0, 0,
p_default, false,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_CUSTOMCHK,
p_enable_ctrls, 1, plPhysicCoreComponent::kCustomBoundListStuff,
end,
plPhysicCoreComponent::kAlignProxyShape, _T("AlignShapeChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_ALIGN_SHAPE_BOOL,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plPhysTerrainComponent::plPhysTerrainComponent()
{
fClassDesc = &gPhysTerrainDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
void plPhysTerrainComponent::CollectNonDrawables(INodeTab& nonDrawables)
{
if (fCompPB->GetInt(kCustomBoundField))
{
INode* boundsNode = fCompPB->GetINode(kCustomBoundListStuff);
if( boundsNode )
nonDrawables.Append(1, &boundsNode);
}
}
void ValidateGroups(IParamBlock2* pb, int memberID, int bounceID, plComponent* comp, plErrorMsg* pErrMsg)
{
UInt32 defMember = pb->GetParamDef(memberID).def.i;
UInt32 member = pb->GetInt(memberID);
UInt32 defCollide = pb->GetParamDef(bounceID).def.i;
UInt32 collide = pb->GetInt(bounceID);
if (defMember != member || defCollide != collide)
{
pErrMsg->Set(true,
"Physics Conflict",
"The legacy physical component \"%s\" has non-default member or collide groups.\nPlease recreate it.",
comp->GetINode()->GetName()).Show();
pErrMsg->Set(false);
}
}
hsBool plPhysTerrainComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), pNode, pErrMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), pNode, pErrMsg);
physProps->SetAlignToOwner(fCompPB->GetInt(kAlignProxyShape) != 0, pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupStatic, pNode, pErrMsg);
physProps->SetLOSBlockCamera(true, pNode, pErrMsg);
physProps->SetLOSBlockUI(true, pNode, pErrMsg);
physProps->SetLOSAvatarWalkable(true, pNode, pErrMsg);
return IGetProxy(pNode, pErrMsg);
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plProxyTerrainComponent
//
/////////////////////////////////////////////////////////////////////////////////////////
class plProxyTerrainComponent : public plPhysicCoreComponent
{
public:
plProxyTerrainComponent();
hsBool SetupProperties(plMaxNode* node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plProxyTerrainComponent, gProxyTerrainDesc, "Proxy Terrain", "ProxyTerrain", COMP_TYPE_PHYSICAL, PHYSICS_INVISIBLE_CID)
ParamBlockDesc2 gPhysInvisibleBk
(
plComponent::kBlkComp, _T("ProxyTerrain"), 0, &gProxyTerrainDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_PROXY_TERRAIN, IDS_COMP_PHYS_PROXY_TERRAIN, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kUILOSChkBx, _T("UILOSChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_CHECK_LOS,
end,
plPhysicCoreComponent::kCamLOSChkBx, _T("CamLOSChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_CHECK_LOS2,
end,
plPhysicCoreComponent::kCamAvoidChkBx, _T("CamLOSChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_CHECK_LOS3,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_INVIS_BOUNCE_EDIT, IDC_COMP_PHYS_INVIS_BOUNCE_SPIN, 0.0001f,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plProxyTerrainComponent::plProxyTerrainComponent()
{
fClassDesc = &gProxyTerrainDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plProxyTerrainComponent::SetupProperties(plMaxNode *node, plErrorMsg *errMsg)
{
IFixBounds();
node->SetDrawable(false);
plPhysicalProps *physProps = node->GetPhysicalProps();
physProps->SetMass(0, node, errMsg);
if (fCompPB->GetInt(kUILOSChkBx) || fCompPB->GetInt(kCamLOSChkBx))
{
// XXX physProps->SetAllowLOS(false, pNode, pErrMsg);
if (fCompPB->GetInt(kUILOSChkBx))
physProps->SetLOSBlockUI(true, node, errMsg);
if (fCompPB->GetInt(kCamLOSChkBx))
physProps->SetLOSBlockCamera(true, node, errMsg);
if (fCompPB->GetInt(kCamAvoidChkBx))
physProps->SetCameraAvoidFlag(true, node, errMsg);
}
physProps->SetLOSAvatarWalkable(true, node, errMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), node, errMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), node, errMsg);
physProps->SetGroup(plSimDefs::kGroupStatic, node, errMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, errMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), node, errMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), node, errMsg);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plCameraBlockerComponent
//
/////////////////////////////////////////////////////////////////////////////////////////
class plCameraBlockerComponent : public plPhysicCoreComponent
{
public:
plCameraBlockerComponent();
hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plCameraBlockerComponent, gCameraBlockerDesc, "(ex) Camera Blocker", "CameraBlocker", COMP_TYPE_PHYSICAL, PHYS_CAMERA_BLOCK_CID)
ParamBlockDesc2 gCameraOccludeBlock
(
plComponent::kBlkComp, _T("cameraBlocker"), 0, &gCameraBlockerDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_CAMERA_OCCLUDER, IDS_CAMERA_OCCLUDERS, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
plPhysicCoreComponent::kBoundCondRadio, _T("BlockerBounds"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plCameraBlockerComponent::plCameraBlockerComponent()
{
fClassDesc = &gCameraBlockerDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plCameraBlockerComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
physProps->SetFriction(0, pNode, pErrMsg);
// physProps->SetAllowLOS(false, pNode, pErrMsg);
physProps->SetLOSBlockCamera(true, pNode, pErrMsg);
// physProps->SetUILOSFlag(true, pNode, pErrMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupLOSOnly, pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plPhysSimpleComponent
//
/////////////////////////////////////////////////////////////////////////////////////////
class plPhysSimpleComponent : public plPhysicCoreComponent
{
public:
plPhysSimpleComponent();
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables);
};
CLASS_DESC(plPhysSimpleComponent, gPhysSimpleDesc, "Simple", "Simple", COMP_TYPE_PHYSICAL, PHYSICS_SIMPLE_CID)
ParamBlockDesc2 gPhysSimpleBk
(
plComponent::kBlkComp, _T("Simple"), 0, &gPhysSimpleDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_SIMPLE, IDS_COMP_PHYS_SIMPLE, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kMass, _T("Mass"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 1.0,
p_range, 0.001, 500.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_SIMP_EDIT1, IDC_COMP_PHYS_SIMP_SPIN1, 1.0,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_SIMP_EDIT2, IDC_COMP_PHYS_SIMP_SPIN2, 0.1,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_SIMP_EDIT3, IDC_COMP_PHYS_SIMP_SPIN3, 0.1,
end,
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kCustomBoundListStuff, _T("UserBoundChoice"), TYPE_INODE, 0, 0,
p_ui, kPhysMain, TYPE_PICKNODEBUTTON, IDC_COMP_PHYS_PICKSTATE_SIMP,
p_sclassID, GEOMOBJECT_CLASS_ID,
p_prompt, IDS_COMP_PHYS_CHOSEN_SIMP,
p_accessor, &gPhysCoreAccessor,
end,
plPhysicCoreComponent::kCustomBoundField, _T("UserBoundCheckBx"), TYPE_BOOL, 0, 0,
p_default, false,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_CUSTOMCHK,
p_enable_ctrls, 1, plPhysicCoreComponent::kCustomBoundListStuff,
end,
plPhysicCoreComponent::kAlignProxyShape, _T("AlignShapeChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_PHYS_ALIGN_SHAPE_BOOL,
end,
plPhysicCoreComponent::kNoSynchronize, _T("DontSynchronizeChkBx"), TYPE_BOOL, 0, 0,
p_default, false,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_PH_NO_SYNC_CHK,
end,
plPhysicCoreComponent::kStartInactive, _T("StartInactiveChkBx"), TYPE_BOOL, 0, 0,
p_default, true,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_PH_INACTIVE_CHK,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kDynamicSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated |
plPhysicsGroups_DEAD::kDynamicSimulated |
plPhysicsGroups_DEAD::kAnimated,
end,
plPhysicCoreComponent::kAvAnimPushable, _T("AvAnimPushable"), TYPE_BOOL, 0, 0,
p_default, false,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_PH_AVANIMPUSHABLE,
end,
end
);
plPhysSimpleComponent::plPhysSimpleComponent()
{
fClassDesc = &gPhysSimpleDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
void plPhysSimpleComponent::CollectNonDrawables(INodeTab& nonDrawables)
{
if (fCompPB->GetInt(kCustomBoundField))
{
INode* boundsNode = fCompPB->GetINode(kCustomBoundListStuff);
if( boundsNode )
nonDrawables.Append(1, &boundsNode);
}
}
hsBool plPhysSimpleComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(fCompPB->GetFloat(kMass), pNode, pErrMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), pNode, pErrMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), pNode, pErrMsg);
physProps->SetAlignToOwner(fCompPB->GetInt(kAlignProxyShape) != 0, pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupDynamic, pNode, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
physProps->SetNoSynchronize(fCompPB->GetInt(kNoSynchronize));
physProps->SetStartInactive(fCompPB->GetInt(kStartInactive));
physProps->SetAvAnimPushable(fCompPB->GetInt(kAvAnimPushable));
if( !pNode->IsAnimated() )
pNode->SetItinerant(true);
return IGetProxy(pNode, pErrMsg);
}
////////////////////////////////////////////////////////////////////////////////
//! Invisible Blocker Component Class
class plPhysBlockerComponent : public plPhysicCoreComponent
{
public:
plPhysBlockerComponent();
hsBool SetupProperties(plMaxNode* node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plPhysBlockerComponent, gPhysBlockerDesc, "(ex) Invisible Blocker", "InvisBlocker", COMP_TYPE_PHYSICAL, PHYSICS_BLOCKER_CID)
ParamBlockDesc2 gPhysBlockerBk
(
plComponent::kBlkComp, _T("invisibleBlocker"), 0, &gPhysBlockerDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_INVISIBLE, IDS_COMP_PHYS_INVISIBLE, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kLOSChkBx, _T("LOSChkBx"), TYPE_BOOL, P_ANIMATABLE, 0,
p_default, FALSE,
p_ui, kPhysMain, TYPE_SINGLECHEKBOX, IDC_COMP_CHECK_LOS,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_INVIS_BOUNCE_EDIT, IDC_COMP_PHYS_INVIS_BOUNCE_SPIN, 0.0001f,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kGroup, _T("group"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 2, IDC_RADIO_BLOCK_AVATAR, IDC_RADIO_BLOCK_DYNAMIC,
p_vals, plSimDefs::kGroupAvatarBlocker, plSimDefs::kGroupDynamicBlocker,
p_default, plSimDefs::kGroupAvatarBlocker,
end,
end
);
plPhysBlockerComponent::plPhysBlockerComponent()
{
fClassDesc = &gPhysBlockerDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPhysBlockerComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
if(fCompPB->GetInt(kLOSChkBx))
{
physProps->SetLOSBlockUI(true, pNode, pErrMsg);
physProps->SetLOSBlockCamera(true, pNode, pErrMsg);
}
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetGroup(fCompPB->GetInt(kGroup), pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Walkable
class plPhysWalkableComponent : public plPhysicCoreComponent
{
public:
plPhysWalkableComponent();
hsBool SetupProperties(plMaxNode* node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plPhysWalkableComponent, gPhysWalkableDesc, "Walkable", "Walkable", COMP_TYPE_PHYS_TERRAINS, PHYS_WALKABLE_CID)
ParamBlockDesc2 gPhysWalkableBk
(
plComponent::kBlkComp, _T("Walkable"), 0, &gPhysWalkableDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_INVISIBLE, IDS_COMP_PHYS_WALKABLE, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_INVIS_BOUNCE_EDIT, IDC_COMP_PHYS_INVIS_BOUNCE_SPIN, 0.0001f,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plPhysWalkableComponent::plPhysWalkableComponent()
{
fClassDesc = &gPhysWalkableDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPhysWalkableComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupStatic, pNode, pErrMsg);
// physProps->SetReportGroup(1<<plSimDefs::kGroupAvatar, pNode, pErrMsg);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Climable
class plPhysClimbableComponent : public plPhysicCoreComponent
{
public:
plPhysClimbableComponent();
hsBool SetupProperties(plMaxNode* node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plPhysClimbableComponent, gPhysClimbableDesc, "Climbable", "Climbable", COMP_TYPE_PHYS_TERRAINS, PHYS_CLIMBABLE_CID)
ParamBlockDesc2 gPhysClimbableBk
(
plComponent::kBlkComp, _T("Climbable"), 0, &gPhysClimbableDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_CLIMBABLE, IDS_COMP_PHYS_CLIMBABLE, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_INVIS_BOUNCE_EDIT, IDC_COMP_PHYS_INVIS_BOUNCE_SPIN, 0.0001f,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plPhysClimbableComponent::plPhysClimbableComponent()
{
fClassDesc = &gPhysClimbableDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPhysClimbableComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupStatic, pNode, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
// physProps->SetReportGroup(1<<plSimDefs::kAvatars, pNode, pErrMsg);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plSwim2DComponent
//
/////////////////////////////////////////////////////////////////////////////////////////
class Swim2DDlgProc : public ParamMap2UserDlgProc
{
public:
Swim2DDlgProc() {}
~Swim2DDlgProc() {}
void IValidateSpinners(TimeValue t, IParamBlock2 *pb, IParamMap2 *map, UInt32 id)
{
UInt32 minIndex, maxIndex;
hsBool adjustMin;
switch(id)
{
case IDC_SWIM_CURRENT_PULL_NEAR_DIST:
case IDC_SWIM_CURRENT_PULL_NEAR_DIST_SPIN:
minIndex = plPhysicCoreComponent::kSwimCurrentPullNearDist; maxIndex = plPhysicCoreComponent::kSwimCurrentPullFarDist; adjustMin = false;
break;
case IDC_SWIM_CURRENT_PULL_FAR_DIST:
case IDC_SWIM_CURRENT_PULL_FAR_DIST_SPIN:
minIndex = plPhysicCoreComponent::kSwimCurrentPullNearDist; maxIndex = plPhysicCoreComponent::kSwimCurrentPullFarDist; adjustMin = true;
break;
case IDC_SWIM_CURRENT_STRAIGHT_NEAR_DIST:
case IDC_SWIM_CURRENT_STRAIGHT_NEAR_DIST_SPIN:
minIndex = plPhysicCoreComponent::kSwimCurrentStraightNearDist; maxIndex = plPhysicCoreComponent::kSwimCurrentStraightFarDist; adjustMin = false;
break;
case IDC_SWIM_CURRENT_STRAIGHT_FAR_DIST:
case IDC_SWIM_CURRENT_STRAIGHT_FAR_DIST_SPIN:
minIndex = plPhysicCoreComponent::kSwimCurrentStraightNearDist; maxIndex = plPhysicCoreComponent::kSwimCurrentStraightFarDist; adjustMin = true;
break;
default:
return;
}
float min, max;
min = pb->GetFloat(minIndex, t);
max = pb->GetFloat(maxIndex, t);
if (min > max)
{
if (adjustMin)
pb->SetValue(minIndex, t, max);
else
pb->SetValue(maxIndex, t, min);
map->Invalidate(minIndex);
map->Invalidate(maxIndex);
}
}
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int id = LOWORD(wParam);
IParamBlock2 *pb = map->GetParamBlock();
switch (msg)
{
case WM_COMMAND:
case CC_SPINNER_CHANGE:
IValidateSpinners(t, pb, map, id);
return TRUE;
}
return FALSE;
}
void DeleteThis() {}
};
static Swim2DDlgProc gSwim2DDlgProc;
CLASS_DESC(plSwim2DComponent, gPhysSwimSurfaceDesc, "Swim 2D", "Swim 2D", COMP_TYPE_PHYS_TERRAINS, PHYS_SWIMSURFACE_CID)
ParamBlockDesc2 gPhysSwimSurfaceBk
(
plComponent::kBlkComp, _T("Swim 2D"), 0, &gPhysSwimSurfaceDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_SWIMSURF, IDS_COMP_PHYS_SWIMSURF, 0, 0, &gSwim2DDlgProc,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
plPhysicCoreComponent::kSwimCurrentType, _T("CurrentType"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 3, IDC_SWIM_CURRENT_NONE, IDC_SWIM_CURRENT_SPIRAL, IDC_SWIM_CURRENT_STRAIGHT,
p_vals, plSwim2DComponent::kCurrentNone, plSwim2DComponent::kCurrentSpiral, plSwim2DComponent::kCurrentStraight,
p_default, plSwim2DComponent::kCurrentNone,
end,
plPhysicCoreComponent::kSwimCurrentRotation, _T("SwimRotation"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, -100.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_ROTATION, IDC_SWIM_CURRENT_ROTATION_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimDetectorNode, _T("swimDetector"), TYPE_INODE, 0, 0,
p_ui, kPhysMain, TYPE_PICKNODEBUTTON, IDC_SWIM_DETECTOR_NODE,
p_sclassID, GEOMOBJECT_CLASS_ID,
p_prompt, IDS_SWIM_DETECTOR_NODE,
end,
plPhysicCoreComponent::kSwimCurrentNode, _T("swimCurrentNode"), TYPE_INODE, 0, 0,
p_ui, kPhysMain, TYPE_PICKNODEBUTTON, IDC_SWIM_CURRENT_NODE,
//p_sclassID, DUMMY_CLASS_ID,
p_prompt, IDS_SWIM_CURRENT_NODE,
end,
plPhysicCoreComponent::kSwimBuoyancyDown, _T("BuoyancyDown"), TYPE_FLOAT, 0, 0,
p_default, 3.0,
p_range, 0.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_SWIM_BUOYANCY_DOWN, IDC_SWIM_BUOYANCY_DOWN_SPIN, 0.1,
end,
plPhysicCoreComponent::kSwimBuoyancyUp, _T("BuoyancyUp"), TYPE_FLOAT, 0, 0,
p_default, 0.05,
p_range, 0.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_SWIM_BUOYANCY_UP, IDC_SWIM_BUOYANCY_UP_SPIN, 0.1,
end,
plPhysicCoreComponent::kSwimMaxUpVel, _T("MaxUpVel"), TYPE_FLOAT, 0, 0,
p_default, 3.0,
p_range, 0.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_SWIM_MAX_UP_VEL, IDC_SWIM_MAX_UP_VEL_SPIN, 0.1,
end,
plPhysicCoreComponent::kSwimCurrentPullNearDist, _T("PullNearDist"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.0, 10000.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_SWIM_CURRENT_PULL_NEAR_DIST, IDC_SWIM_CURRENT_PULL_NEAR_DIST_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentPullNearVel, _T("PullNearVel"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, -100.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_PULL_NEAR_VEL, IDC_SWIM_CURRENT_PULL_NEAR_VEL_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentPullFarDist, _T("PullFarDist"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, 0.0, 10000.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_SWIM_CURRENT_PULL_FAR_DIST, IDC_SWIM_CURRENT_PULL_FAR_DIST_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentPullFarVel, _T("PullFarVel"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, -100.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_PULL_FAR_VEL, IDC_SWIM_CURRENT_PULL_FAR_VEL_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentStraightNearDist, _T("StraightNearDist"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, -10000.0, 10000.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_STRAIGHT_NEAR_DIST, IDC_SWIM_CURRENT_STRAIGHT_NEAR_DIST_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentStraightNearVel, _T("StraightNearVel"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, -100.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_STRAIGHT_NEAR_VEL, IDC_SWIM_CURRENT_STRAIGHT_NEAR_VEL_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentStraightFarDist, _T("StraightFarDist"), TYPE_FLOAT, 0, 0,
p_default, 1.0,
p_range, -10000.0, 10000.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_STRAIGHT_FAR_DIST, IDC_SWIM_CURRENT_STRAIGHT_FAR_DIST_SPIN, 1.0,
end,
plPhysicCoreComponent::kSwimCurrentStraightFarVel, _T("StraightFarVel"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, -100.0, 100.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_SWIM_CURRENT_STRAIGHT_FAR_VEL, IDC_SWIM_CURRENT_STRAIGHT_FAR_VEL_SPIN, 1.0,
end,
end
);
// plSwim2DComponent -----------------
// ------------------
plSwim2DComponent::plSwim2DComponent()
{
fClassDesc = &gPhysSwimSurfaceDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
// SetUpProperties -----------------------------------------------------------
// ----------------
hsBool plSwim2DComponent::SetupProperties(plMaxNode *node, plErrorMsg *errMsg)
{
IFixBounds();
plPhysicalProps *physProps = nil;
plMaxNode *detectorNode = (plMaxNode *)fCompPB->GetINode(kSwimDetectorNode);
if (detectorNode)
{
detectorNode->SetDrawable(false);
physProps = detectorNode->GetPhysicalProps();
physProps->SetMass(0, detectorNode, errMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, errMsg);
physProps->SetGroup(plSimDefs::kGroupDetector, node, errMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), detectorNode, errMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), detectorNode, errMsg);
physProps->SetReportGroup(1<<plSimDefs::kGroupAvatar, detectorNode, errMsg);
physProps->SetBoundsType(plSimDefs::kBoxBounds, detectorNode, errMsg);
}
physProps = node->GetPhysicalProps();
physProps->SetMass(0, node, errMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), node, errMsg);
physProps->SetLOSSwimRegion(true, node, errMsg);
plMaxNode *currentNode = (plMaxNode *)fCompPB->GetINode(kSwimCurrentNode);
if (currentNode)
currentNode->SetForceLocal(true);
return true;
}
hsBool plSwim2DComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSwimRegionInterface *swimInt = nil;
int type = fCompPB->GetInt(ParamID(kSwimCurrentType));
if (type != kCurrentNone && fCompPB->GetINode(ParamID(kSwimCurrentNode)) == nil)
{
pErrMsg->Set(true, node->GetName(), "No dummy box set to define current. Forcing current to \"none\"").Show();
type = kCurrentNone;
}
switch (type)
{
case kCurrentSpiral:
{
fSwimRegions[node] = TRACKED_NEW plSwimCircularCurrentRegion();
hsgResMgr::ResMgr()->NewKey(node->GetName(), fSwimRegions[node], node->GetLocation(), node->GetLoadMask());
break;
}
case kCurrentStraight:
{
fSwimRegions[node] = TRACKED_NEW plSwimStraightCurrentRegion();
hsgResMgr::ResMgr()->NewKey(node->GetName(), fSwimRegions[node], node->GetLocation(), node->GetLoadMask());
break;
}
default:
{
fSwimRegions[node] = TRACKED_NEW plSwimRegionInterface();
hsgResMgr::ResMgr()->NewKey(node->GetName(), fSwimRegions[node], node->GetLocation(), node->GetLoadMask());
break;
}
}
return true;
}
// Convert ------------------------------------------------------------
// --------
hsBool plSwim2DComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plMaxNode *detectorNode = (plMaxNode *)fCompPB->GetINode(kSwimDetectorNode);
if (detectorNode && detectorNode->GetSceneObject())
{
if (!detectorNode->GetSceneObject()->GetModifierByType(plSwimDetector::Index()))
{
plKey nilKey;
plSwimMsg *enterMsg = TRACKED_NEW plSwimMsg(detectorNode->GetKey(), nilKey, true, nil);
plSwimMsg *exitMsg = TRACKED_NEW plSwimMsg(detectorNode->GetKey(), nilKey, false, nil);
enterMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
exitMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
plSwimDetector *swimMod = TRACKED_NEW plSwimDetector(enterMsg, exitMsg);
detectorNode->AddModifier(swimMod, IGetUniqueName(node));
// the mod doesn't have a valid key until AddModifier is called, so this comes last.
enterMsg->fSwimRegionKey = swimMod->GetKey();
exitMsg->fSwimRegionKey = swimMod->GetKey();
}
}
int type = fCompPB->GetInt(ParamID(kSwimCurrentType));
switch (type)
{
case kCurrentSpiral:
{
plSwimCircularCurrentRegion *circInt = plSwimCircularCurrentRegion::ConvertNoRef(fSwimRegions[node]);
circInt->fRotation = fCompPB->GetFloat(ParamID(kSwimCurrentRotation));
circInt->fPullNearDistSq = fCompPB->GetFloat(ParamID(kSwimCurrentPullNearDist));
circInt->fPullNearDistSq *= circInt->fPullNearDistSq;
circInt->fPullNearVel = fCompPB->GetFloat(ParamID(kSwimCurrentPullNearVel));
circInt->fPullFarDistSq = fCompPB->GetFloat(ParamID(kSwimCurrentPullFarDist));
circInt->fPullFarDistSq *= circInt->fPullFarDistSq;
circInt->fPullFarVel = fCompPB->GetFloat(ParamID(kSwimCurrentPullFarVel));
plMaxNode *currentNode = (plMaxNode *)fCompPB->GetINode(ParamID(kSwimCurrentNode));
if (currentNode)
{
plGenRefMsg *msg= TRACKED_NEW plGenRefMsg(circInt->GetKey(), plRefMsg::kOnCreate, -1, -1);
hsgResMgr::ResMgr()->AddViaNotify(currentNode->GetSceneObject()->GetKey(), msg, plRefFlags::kActiveRef);
}
break;
}
case kCurrentStraight:
{
plSwimStraightCurrentRegion *strInt = plSwimStraightCurrentRegion::ConvertNoRef(fSwimRegions[node]);
strInt->fNearDist = fCompPB->GetFloat(ParamID(kSwimCurrentStraightNearDist));
strInt->fNearVel = fCompPB->GetFloat(ParamID(kSwimCurrentStraightNearVel));
strInt->fFarDist = fCompPB->GetFloat(ParamID(kSwimCurrentStraightFarDist));
strInt->fFarVel = fCompPB->GetFloat(ParamID(kSwimCurrentStraightFarVel));
plMaxNode *currentNode = (plMaxNode *)fCompPB->GetINode(ParamID(kSwimCurrentNode));
if (currentNode)
{
plGenRefMsg *msg= TRACKED_NEW plGenRefMsg(strInt->GetKey(), plRefMsg::kOnCreate, -1, -1);
hsgResMgr::ResMgr()->AddViaNotify(currentNode->GetSceneObject()->GetKey(), msg, plRefFlags::kActiveRef);
}
break;
}
default:
{
// Already done all the work in PreConvert
break;
}
}
fSwimRegions[node]->fDownBuoyancy = fCompPB->GetFloat(ParamID(kSwimBuoyancyDown)) + 1;
fSwimRegions[node]->fUpBuoyancy = fCompPB->GetFloat(ParamID(kSwimBuoyancyUp)) + 1;
fSwimRegions[node]->fMaxUpwardVel = fCompPB->GetFloat(ParamID(kSwimMaxUpVel));
hsgResMgr::ResMgr()->AddViaNotify(fSwimRegions[node]->GetKey(), TRACKED_NEW plObjRefMsg(node->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Swim 3D
class plPhysSwim3DComponent : public plPhysicCoreComponent
{
public:
plPhysSwim3DComponent();
hsBool SetupProperties(plMaxNode* node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plPhysSwim3DComponent, gPhysSwim3DDesc, "Swim 3D", "Swim 3D", COMP_TYPE_PHYS_TERRAINS, PHYS_SWIM3D_CID)
ParamBlockDesc2 gPhysSwim3DBk
(
plComponent::kBlkComp, _T("Swim 3D"), 0, &gPhysSwim3DDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp,
//Roll out
1,
kPhysMain, IDD_COMP_PHYS_SWIM3D, IDS_COMP_PHYS_SWIM3D, 0, 0, NULL,
// kPhysMember, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_MEMBER, 0, APPENDROLL_CLOSED, &gMemberGroupProc,
// kPhysBounce, IDD_COMP_PHYS_CORE_GROUP, IDS_COMP_PHYS_BOUNCE, 0, APPENDROLL_CLOSED, &gBounceGroupProc,
// params
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, kPhysMain, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kProxyBounds,
p_default, plSimDefs::kHullBounds,
end,
plPhysicCoreComponent::kFriction, _T("Friction"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.5,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_TERRAIN_EDIT1, IDC_COMP_PHYS_TERRAIN_SPIN1, 0.0001f,
end,
plPhysicCoreComponent::kBounce, _T("Bounce"), TYPE_FLOAT, P_ANIMATABLE, 0,
p_default, 0.0,
p_range, 0.0, 1.0,
p_ui, kPhysMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_PHYS_INVIS_BOUNCE_EDIT, IDC_COMP_PHYS_INVIS_BOUNCE_SPIN, 0.0001f,
end,
// Event Groups
plPhysicCoreComponent::kMemberGroups_DEAD, _T("memberGroups"), TYPE_INT, 0,0,
p_default, plPhysicsGroups_DEAD::kStaticSimulated,
end,
plPhysicCoreComponent::kBounceGroups_DEAD, _T("bounceGroups"), TYPE_INT, 0,0,
end,
end
);
plPhysSwim3DComponent::plPhysSwim3DComponent()
{
fClassDesc = &gPhysSwim3DDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPhysSwim3DComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
IFixBounds();
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(0, pNode, pErrMsg);
physProps->SetFriction(fCompPB->GetFloat(kFriction), pNode, pErrMsg);
physProps->SetRestitution(fCompPB->GetFloat(kBounce), pNode, pErrMsg);
ValidateGroups(fCompPB, plPhysicCoreComponent::kMemberGroups_DEAD, plPhysicCoreComponent::kBounceGroups_DEAD, this, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupStatic, pNode, pErrMsg);
// physProps->SetMemberGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kMemberGroups), pNode, pErrMsg);
// physProps->SetBounceGroup(plEventGroupProc::GetGroups(fCompPB, plPhysicCoreComponent::kBounceGroups), pNode, pErrMsg);
// physProps->SetReportGroup(plPhysicsGroups_DEAD::kAvatars, pNode, pErrMsg);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// DEAD
//
/////////////////////////////////////////////////////////////////////////////////////////
class plPhysPlayerComponent : public plPhysicCoreComponent
{
public:
plPhysPlayerComponent();
};
OBSOLETE_CLASS_DESC(plPhysPlayerComponent, gPhysPlayerDesc, "Player", "Player", COMP_TYPE_PHYSICAL, PHYSICS_PLAYER_CID)
ParamBlockDesc2 gPhysPlayerBk
(
plComponent::kBlkComp, _T("Player"), 0, &gPhysPlayerDesc, P_AUTO_CONSTRUCT, plComponent::kRefComp,
end
);
plPhysPlayerComponent::plPhysPlayerComponent()
{
fClassDesc = &gPhysPlayerDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
/////
class plPhysBoundBlockerComponent : public plPhysicCoreComponent
{
public:
plPhysBoundBlockerComponent();
};
OBSOLETE_CLASS_DESC(plPhysBoundBlockerComponent, gPhysBoundBlockerDesc, "(ex) Boundary Blocker", "BoundaryBlocker", COMP_TYPE_PHYSICAL, PHYSICS_BOUND_BLOCKER_CID)
ParamBlockDesc2 gPhysBoundBlockerBk
(
plComponent::kBlkComp, _T("(ex)Boundary Blocker"), 0, &gPhysBoundBlockerDesc, P_AUTO_CONSTRUCT, plComponent::kRefComp,
end
);
plPhysBoundBlockerComponent::plPhysBoundBlockerComponent()
{
fClassDesc = &gPhysBoundBlockerDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
/////
class plPhysDetectorComponent : public plPhysicCoreComponent
{
public:
plPhysDetectorComponent();
};
OBSOLETE_CLASS_DESC(plPhysDetectorComponent, gPhysDetectorDesc, "Detector", "Detector", COMP_TYPE_PHYSICAL, PHYSICS_DETECTOR_CID)
ParamBlockDesc2 gPhysDetectorBk
(
plComponent::kBlkComp, _T("Detector"), 0, &gPhysDetectorDesc, P_AUTO_CONSTRUCT, plComponent::kRefComp,
end
);
plPhysDetectorComponent::plPhysDetectorComponent()
{
fClassDesc = &gPhysDetectorDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
////////////////////////////////////////////////////////////////////////////////
//! Physical Simple Component Class
class plPhysSubWorldComponent : public plPhysicCoreComponent
{
public:
plPhysSubWorldComponent();
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg);
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
void IAddChildren(plMaxNode *node, plMaxNode* worldKey);
};
CLASS_DESC(plPhysSubWorldComponent, gPhysSubWorldDesc, "Subworld", "Subworld", COMP_TYPE_PHYSICAL, PHYS_SUBWORLD_CID)
ParamBlockDesc2 gPhysSubWorldBk
(
plComponent::kBlkComp, _T("Subworld "), 0, &gPhysSubWorldDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
//Roll out
IDD_COMP_PHYS_SUBWORLD, IDS_COMP_PHYS_SUBWORLD, 0, 0, NULL,
end
);
plPhysSubWorldComponent::plPhysSubWorldComponent()
{
fClassDesc = &gPhysSubWorldDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPhysSubWorldComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg)
{
IAddChildren(node, node);
node->SetForceLocal(true);
node->SetMovable(true);
return true;
}
hsBool plPhysSubWorldComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
void plPhysSubWorldComponent::IAddChildren(plMaxNode* node, plMaxNode* subworld)
{
int numChildren = node->NumberOfChildren();
for (int i = 0; i < numChildren; i++)
{
plMaxNode* child = (plMaxNode*)node->GetChildNode(i);
const char* childName = child->GetName();
bool hasSubworld = false;
UInt32 numComps = child->NumAttachedComponents();
for (int j = 0; j < numComps; j++)
{
plComponentBase* comp = child->GetAttachedComponent(j);
if (comp && comp->ClassID() == PHYS_SUBWORLD_CID)
{
hasSubworld = true;
break;
}
}
// If we've reached another subworld, terminate our descent so we don't file
// children in our subworld instead.
// This has to happen *after* we've converted this node, because it may be a physical
// in the parent subworld.
if (!hasSubworld)
{
plPhysicalProps* props = child->GetPhysicalProps();
if (props)
props->SetSubworld(subworld);
IAddChildren(child, subworld);
}
}
}
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// the detector for triggering subworld changes
///////////////////////////////////////////////////////
class plSubworldDetectorComponent : public plPhysicCoreComponent
{
public:
plSubworldDetectorComponent();
hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plSubworldDetectorComponent, gSubworldDetectorDesc, "Subworld Region", "SubworldRegion", COMP_TYPE_PHYSICAL, SUBWORLD_REGION_CID)
enum
{
kSubworldTarget,
kInclusive_DEAD,
kSubworldTriggerOn,
};
enum
{
kSubTriggerOnEnter,
kSubTriggerOnExit,
};
ParamBlockDesc2 gSubworldRegionBlock
(
plComponent::kBlkComp, _T("subworldRegion"), 0, &gSubworldDetectorDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SUBWORLD_REGION, IDS_COMP_SUBWORLD_REGION, 0, 0, NULL,
kSubworldTarget, _T("SubworldTarget"), TYPE_INODE, 0, 0,
p_ui, TYPE_PICKNODEBUTTON, IDC_COMP_CAMERARGN_PICKSTATE_BASE,
p_sclassID, HELPER_CLASS_ID,
p_prompt, IDS_COMP_PHYS_CHOSEN_BASE,
end,
kSubworldTriggerOn, _T("triggerOn"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 2, IDC_RADIO_ENTER, IDC_RADIO_EXIT,
p_vals, kSubTriggerOnEnter, kSubTriggerOnExit,
p_default, kSubTriggerOnEnter,
end,
end
);
plSubworldDetectorComponent::plSubworldDetectorComponent()
{
fClassDesc = &gSubworldDetectorDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plSubworldDetectorComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
pNode->SetForceLocal(true);
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(1.0, pNode, pErrMsg);
physProps->SetFriction(0.0, pNode, pErrMsg);
physProps->SetRestitution(0.0, pNode, pErrMsg);
//physProps->SetBoundsType(plSimDefs::kExplicitBounds, pNode, pErrMsg);
physProps->SetBoundsType(plSimDefs::kHullBounds, pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupDetector, pNode, pErrMsg);
physProps->SetReportGroup(1<<plSimDefs::kGroupAvatar, pNode, pErrMsg);
return true;
}
hsBool plSubworldDetectorComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
hsBool plSubworldDetectorComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSceneObject *obj = node->GetSceneObject();
plLocation loc = node->GetLocation();
plSubworldRegionDetector *detector = TRACKED_NEW plSubworldRegionDetector;
// Register the detector
plKey detectorKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), detector, loc);
hsgResMgr::ResMgr()->AddViaNotify(detectorKey, TRACKED_NEW plObjRefMsg(obj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
// need to get the key for the camera here...
plMaxNode* pSubNode = (plMaxNode*)fCompPB->GetINode(kSubworldTarget);
if (pSubNode)
{
if(pSubNode->CanConvert())
{
detector->SetSubworldKey(pSubNode->GetKey());
}
}
else
{
detector->SetSubworldKey(nil);
}
bool onExit = (fCompPB->GetInt(kSubworldTriggerOn) == kSubTriggerOnExit);
detector->SetTriggerOnExit(onExit);
return true;
}
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
// the detector for triggering panic links
///////////////////////////////////////////////////////
class plPanicLinkDetectorComponent : public plPhysicCoreComponent
{
public:
enum
{
kPlayAnim,
};
plPanicLinkDetectorComponent();
void DeleteThis() { delete this; }
hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plPanicLinkDetectorComponent, gPanicLinkDetectorDesc, "Panic Link Region", "PanicLinkRegion", COMP_TYPE_PHYSICAL, PANIC_LINK_REGION_CID)
ParamBlockDesc2 gPanicLinkRegionBlock
(
plComponent::kBlkComp, _T("panicLinkRegion"), 0, &gPanicLinkDetectorDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_PANIC, IDS_COMP_PANIC, 0, 0, NULL,
plPanicLinkDetectorComponent::kPlayAnim, _T("PlayAnim"), TYPE_BOOL, 0, 0,
p_default, true,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_PANIC_ANIM,
end,
end
);
plPanicLinkDetectorComponent::plPanicLinkDetectorComponent()
{
fClassDesc = &gPanicLinkDetectorDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plPanicLinkDetectorComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
pNode->SetForceLocal(true);
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(1.0, pNode, pErrMsg);
physProps->SetFriction(0.0, pNode, pErrMsg);
physProps->SetRestitution(0.0, pNode, pErrMsg);
physProps->SetBoundsType(plSimDefs::kHullBounds, pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupDetector, pNode, pErrMsg);
physProps->SetReportGroup(1<<plSimDefs::kGroupAvatar, pNode, pErrMsg);
return true;
}
hsBool plPanicLinkDetectorComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
hsBool plPanicLinkDetectorComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSceneObject *obj = node->GetSceneObject();
plLocation loc = node->GetLocation();
plPanicLinkRegion *detector = TRACKED_NEW plPanicLinkRegion;
detector->fPlayLinkOutAnim = fCompPB->GetInt(ParamID(kPlayAnim));
// Register the detector
plKey detectorKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), detector, loc);
hsgResMgr::ResMgr()->AddViaNotify(detectorKey, TRACKED_NEW plObjRefMsg(obj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// Shootable COMPONENT
//
/////////////////////////////////////////////////////////////////////////////////////////
//Class that accesses the paramblock below.
class plShootableComponent : public plComponent
{
public:
plShootableComponent();
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading
// of properties on the MaxNode, as it's still indeterminant.
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg);
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
};
//Max desc stuff necessary below.
CLASS_DESC(plShootableComponent, gShootableDesc, "Shootable", "Shootable", COMP_TYPE_PHYSICAL, Class_ID(0x77b94f4a, 0x6d3851fc))
ParamBlockDesc2 gShootableBk
(
// 1, _T(""), 0, &gShootableDesc, P_AUTO_CONSTRUCT, 0,
plComponent::kBlkComp, _T("Shootable"), 0, &gShootableDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SHOOTABLE, IDS_COMP_SHOOTABLE, 0, 0, NULL,
end
);
plShootableComponent::plShootableComponent()
{
fClassDesc = &gShootableDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading
// of properties on the MaxNode, as it's still indeterminant.
hsBool plShootableComponent::SetupProperties(plMaxNode *node, plErrorMsg *errMsg)
{
plPhysicalProps *props = node->GetPhysicalProps();
props->SetMass(0.0, node, errMsg);
props->SetFriction(0.0, node, errMsg);
props->SetRestitution(0.0, node, errMsg);
props->SetBoundsType(plSimDefs::kExplicitBounds, node, errMsg);
props->SetGroup(plSimDefs::kGroupLOSOnly, node, errMsg);
props->SetPinned(true, node, errMsg);
props->SetLOSShootable(true, node, errMsg);
return true;
}
hsBool plShootableComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
class plRideAnimatedPhysicalComponent : public plPhysicCoreComponent
{
public:
plRideAnimatedPhysicalComponent();
void DeleteThis(){delete this;}
hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg);
virtual void CollectNonDrawables(INodeTab& nonDrawables) { AddTargetsToList(nonDrawables); }
};
CLASS_DESC(plRideAnimatedPhysicalComponent , gRideAnimatedPhysicalComponent, "RideAnimPhysReg", "RideAnimatedPhysicalRegion", COMP_TYPE_PHYSICAL, Class_ID(0xaf305963, 0x63a246df));
ParamBlockDesc2 gSRideAnimatedPhysBk
(
plComponent::kBlkComp, _T("rideAnimated"), 0, &gRideAnimatedPhysicalComponent, P_AUTO_CONSTRUCT + P_AUTO_UI , plComponent::kRefComp,
//Roll out
IDD_COMP_RIDE_ANIMATED_PHYS, IDS_COMP_RIDE_ANIMATED_PHYS, 0, 0, NULL,
plPhysicCoreComponent::kBoundCondRadio, _T("BoundingConditions"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 4, IDC_RADIO_BSPHERE, IDC_RADIO_BBOX, IDC_RADIO_BHULL, IDC_RADIO_PICKSTATE,
p_vals, plSimDefs::kSphereBounds, plSimDefs::kBoxBounds, plSimDefs::kHullBounds, plSimDefs::kExplicitBounds,
p_default, plSimDefs::kHullBounds,
end,
end
);
plRideAnimatedPhysicalComponent::plRideAnimatedPhysicalComponent()
{
fClassDesc = &gRideAnimatedPhysicalComponent;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plRideAnimatedPhysicalComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
pNode->SetForceLocal(true);
pNode->SetDrawable(false);
plPhysicalProps *physProps = pNode->GetPhysicalProps();
physProps->SetMass(1.0, pNode, pErrMsg);
physProps->SetFriction(0.0, pNode, pErrMsg);
physProps->SetRestitution(0.0, pNode, pErrMsg);
physProps->SetGroup(plSimDefs::kGroupDetector, pNode, pErrMsg);
physProps->SetReportGroup(1<<plSimDefs::kGroupAvatar, pNode, pErrMsg);
physProps->SetBoundsType(fCompPB->GetInt(kBoundCondRadio), pNode, pErrMsg);
return true;
}
hsBool plRideAnimatedPhysicalComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
hsBool plRideAnimatedPhysicalComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSceneObject *obj = node->GetSceneObject();
plLocation loc = node->GetLocation();
plRideAnimatedPhysMsg* enter = TRACKED_NEW plRideAnimatedPhysMsg(obj->GetKey(), nil, true, nil);
enter->SetBCastFlag(plMessage::kPropagateToModifiers);
plRideAnimatedPhysMsg* exit = TRACKED_NEW plRideAnimatedPhysMsg(obj->GetKey(), nil, false, nil);
exit->SetBCastFlag(plMessage::kPropagateToModifiers);
plRidingAnimatedPhysicalDetector *detector = TRACKED_NEW plRidingAnimatedPhysicalDetector(enter, exit);
// Register the detector
//node->AddModifier(detector, IGetUniqueName(node));
plKey detectorKey = hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), detector, loc);
hsgResMgr::ResMgr()->AddViaNotify(detectorKey, TRACKED_NEW plObjRefMsg(obj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
return true;
}