/*==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 . 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<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<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<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<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<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<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; }