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