/*==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" #include "max.h" #include "resource.h" // Resource Dependencies #include "../MaxMain/plPhysicalProps.h" #include "plComponent.h" //Component Dependencies #include "plComponentReg.h" // Ibid #include "../MaxMain/plMaxNode.h" // Ibid #include "../pnKeyedObject/plKey.h" // Ibid #include "plComponentProcBase.h" #include "plNavigableComponents.h" #include "plActivatorBaseComponent.h" #include "plPhysicalComponents.h" #include "../MaxConvert/hsConverterUtils.h" //Conversion Dependencies #include "../MaxConvert/hsControlConverter.h" // Ibid #include "../plAvatar/plAvLadderModifier.h" //Modifier Dependencies #include "../plPhysical/plSimDefs.h" #include "plgDispatch.h" //Message Dependencies #include "../pnMessage/plObjRefMsg.h" // Ibid #include "../pnMessage/plIntRefMsg.h" // Ibid #include "../pnMessage/plNodeRefMsg.h" // Ibid #include "../MaxMain/plPlasmaRefMsgs.h" // Ibid void DummyCodeIncludeFuncNavigablesRegion() {} CLASS_DESC(plAvLadderComponent, gAvLadderComponentDesc, "(ex)Ladder Component", "(ex)LadderComp", COMP_TYPE_PHYS_TERRAINS, NAV_LADDER_CID) class plAvLadderComponentProc; extern plAvLadderComponentProc gAvLadderComponentProc; enum kAvLadderFields { kTypeCombo, kLoopsInt, kTriggerNode, kDirectionBool, kBoundsType_DEAD, kEnabled, kLadderNode, }; ParamBlockDesc2 gAvLadderComponentBlock ( plComponent::kBlkComp, _T("(ex)Ladder Component"), 0, &gAvLadderComponentDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, IDD_COMP_NAV_LADDER, IDS_COMP_NAV_LADDERS, 0, 0, &gAvLadderComponentProc, kTypeCombo, _T("Ladder Type"), TYPE_INT, 0,0, end, kDirectionBool, _T("Climbing Direction"), TYPE_INT, 0, 0, p_ui, TYPE_RADIO, 2, IDC_RADIO_UP, IDC_RADIO_DOWN, p_vals, true, false, end, kLoopsInt, _T("BigLadderNumLoop"), TYPE_INT, 0, 0, p_default, 0, p_range, 0, 500, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_COMP_NAV_LADDER_LOOPS_EDIT, IDC_COMP_NAV_LADDER_LOOPS_SPIN, 0.4, end, kTriggerNode, _T("Trigger Node"), TYPE_INODE, 0, 0, p_ui, TYPE_PICKNODEBUTTON, IDC_COMP_NAV_TRIGGER, //p_sclassID, GEOMOBJECT_CLASS_ID, p_prompt, IDS_COMP_PHYS_CHOSEN_BASE, //p_accessor, &gPhysCoreAccessor, end, kLadderNode, _T("ladder"), TYPE_INODE, 0, 0, p_ui, TYPE_PICKNODEBUTTON, IDC_COMP_NAV_LADDER, end, kEnabled, _T("enabled"), TYPE_BOOL, 0, 0, p_ui, TYPE_SINGLECHEKBOX, IDC_ENABLED, p_default, TRUE, end, end ); plAvLadderComponent::plAvLadderComponent() { fClassDesc = &gAvLadderComponentDesc; fClassDesc->MakeAutoParamBlocks(this); } void plAvLadderComponent::CollectNonDrawables(INodeTab& nonDrawables) { INode* ladderNode = fCompPB->GetINode(kLadderNode); if( ladderNode ) nonDrawables.Append(1, &ladderNode); INode* triggerNode = fCompPB->GetINode(kTriggerNode); if( triggerNode ) nonDrawables.Append(1, &triggerNode); AddTargetsToList(nonDrawables); } hsBool plAvLadderComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) { fKeys.Reset(); // // Create an invisible blocker for the ladder shape, so the avatar won't fall over the side // plMaxNode *ladderNode = (plMaxNode*)fCompPB->GetINode(kLadderNode); if (ladderNode) { plPhysicalProps* ladderPhys = ladderNode->GetPhysicalProps(); // ladderPhys->SetMass(0, ladderNode, pErrMsg); ladderPhys->SetBoundsType(plSimDefs::kHullBounds, ladderNode, pErrMsg); ladderPhys->SetGroup(plSimDefs::kGroupStatic, ladderNode, pErrMsg); /// ladderPhys->SetAllowLOS(true, ladderNode, pErrMsg); ladderNode->SetDrawable(false); ladderNode->SetForceLocal(true); // Get a coord interface for facing calculations } else { pErrMsg->Set(true, "Ladder Warning", "Ladder component %s doesn't have the ladder node set", GetINode()->GetName()).Show(); pErrMsg->Set(false); return false; } // // Create a detector region for the node we're attached to // plPhysicalProps *physProps = node->GetPhysicalProps(); plMaxNode *triggerNode = (plMaxNode*)fCompPB->GetINode(kTriggerNode); if (triggerNode) physProps->SetProxyNode(triggerNode, node, pErrMsg); physProps->SetGroup(plSimDefs::kGroupDetector, node, pErrMsg); // this is a detector physProps->SetReportGroup(1<SetPinned(true, node, pErrMsg); // only if movable will it have mass (then it will keep track of movements in PhysX) if ( node->IsMovable() || node->IsTMAnimated() ) physProps->SetMass(1.0f, node, pErrMsg); // detectors don't move physProps->SetBoundsType(plSimDefs::kHullBounds, node, pErrMsg); node->SetForceLocal(true); // force our seek point to be local node->SetDrawable(false); return true; } hsBool plAvLadderComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { plMaxNode *ladderNode = (plMaxNode*)fCompPB->GetINode(kLadderNode); if (!ladderNode) return false; plMaxNode *triggerNode = (plMaxNode*)fCompPB->GetINode(kTriggerNode); if (!triggerNode) triggerNode = node; // Get a vector pointing from the ladder to the detector, for facing calculations Point3 ladderViewMax = ladderNode->GetNodeTM(0).GetTrans() - triggerNode->GetNodeTM(0).GetTrans(); hsVector3 ladderView(ladderViewMax.x, ladderViewMax.y, ladderViewMax.z); ladderView.fZ = 0; ladderView.Normalize(); bool goingUp = (fCompPB->GetInt(kDirectionBool) != 0); int loops = fCompPB->GetInt(kLoopsInt); int ladderType = fCompPB->GetInt(kTypeCombo); bool enabled = (fCompPB->GetInt(kEnabled) != 0); plAvLadderMod* ladMod = TRACKED_NEW plAvLadderMod(goingUp, ladderType, loops, enabled, ladderView); plKey modKey = node->AddModifier(ladMod, IGetUniqueName(node)); fKeys.Append(modKey); return true; } hsBool plAvLadderComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) { return true; } hsBool plAvLadderComponent::DeInit(plMaxNode *node, plErrorMsg *pErrMsg) { fKeys.Reset(); return true; } class plAvLadderComponentProc : public ParamMap2UserDlgProc { public: enum kLadderTypesEnums { kReallyBig, kFourFeet, kTwoFeet, }; BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { HWND hLadder = GetDlgItem(hWnd,IDC_COMP_NAV_LADDER_COMBO); ComboBox_AddString(hLadder, "Big"); ComboBox_AddString(hLadder, "4 feet"); ComboBox_AddString(hLadder, "2 feet"); int type = map->GetParamBlock()->GetInt(kTypeCombo); ComboBox_SetCurSel(hLadder, type); } return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDC_COMP_NAV_LADDER_COMBO && HIWORD(wParam) == CBN_SELCHANGE) { //Util fcn found in plEventGroupRefs files in MaxMain HWND hLadder = GetDlgItem(hWnd,IDC_COMP_NAV_LADDER_COMBO); int idx = ComboBox_GetCurSel(hLadder); map->GetParamBlock()->SetValue(kTypeCombo, 0, idx); /* if (idx == kReallyBig) { map->Enable(kLoopsInt, TRUE); // map->Invalidate(kLoopsInt); } else { map->Enable(kLoopsInt, TRUE); // map->Invalidate(kLoopsInt); } */ return TRUE; } break; } return FALSE; } void DeleteThis() {} }; static plAvLadderComponentProc gAvLadderComponentProc;