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.

404 lines
12 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"
// max includes
#include "plPickNode.h"
#include "resource.h"
// local
#include "plClimbComponent.h"
#include "plPhysicalComponents.h" // so we can pick terrains
#include "plComponentReg.h"
// other
#include "../MaxMain/plMaxNode.h"
#include "../plMessage/plClimbMsg.h"
#include "../plPhysical/plCollisionDetector.h"
#include "../MaxMain/plPhysicalProps.h"
#include "../plPhysical/plSimDefs.h"
#include "../pnSceneObject/plSceneObject.h"
// stl
#include <map>
/////////////////////////////////////////////////////////////////
//
// THE DUMMY
//
/////////////////////////////////////////////////////////////////
void DummyCodeIncludeFuncClimbTrigger() {}
/////////////////////////////////////////////////////////////////
//
// SOME ENUMS
//
/////////////////////////////////////////////////////////////////
// CLIMBCOMMANDS
enum Commands
{
kMount = 0,
kEnableDismount = 1,
kDisableDismount = 2,
kEnableClimb = 3,
kDisableClimb = 4,
kFallOff = 5,
kRelease = 6,
kMaxCommands = 7
};
// these synchronized ^^^^VVVVV
const char * fCommandStrs[] =
{
"Start Climbing",
"Enable Dismount",
"Disable Dismount",
"Enable Climb",
"Disable Climb",
"Fall Off",
"Let Go"
};
enum Directions
{
kUp = 0,
kDown = 1,
kLeft = 2,
kRight = 3,
kMaxDirections
};
const char * fDirectionStrs[] =
{
"Up",
"Down",
"Left",
"Right"
};
/////////////////////////////////////////////////////////////////
//
// CLASS DESCRIPTOR AND PARAM BLOCK
//
/////////////////////////////////////////////////////////////////
// CLASS DESCRIPTOR
CLASS_DESC(plClimbTriggerComponent, gClimbTriggerDesc, "Avatar ClimbTrigger", "AvatarClimbTrigger", COMP_TYPE_AVATAR, CLIMB_TRIGGER_COMPONENT_CLASS_ID)
// FORWARD REFERENCE OT THE COMPONENT DIALOG PROC
static plClimbTriggerComponentProc gClimbTriggerComponentProc;
// PARAM BLOCK
ParamBlockDesc2 gClimbTriggerBk
(
plComponent::kBlkComp, _T("ClimbTrigger"), 0, &gClimbTriggerDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
//Roll out
IDD_COMP_CLIMB_TRIGGER, IDS_COMP_CLIMB_TRIGGER, 0, 0, &gClimbTriggerComponentProc,
plClimbTriggerComponent::kCommand, _T("Command"), TYPE_INT, 0, 0,
p_default, kMount,
end,
plClimbTriggerComponent::kDirection, _T("Direction"), TYPE_INT, 0, 0,
p_default, kUp,
end,
plClimbTriggerComponent::kWallPicker, _T("WallPicker"), TYPE_INODE, 0, 0,
end,
end
);
/////////////////////////////////////////////////////////////////
//
// PLCLIMBTRIGGER IMPLEMENTATION
//
/////////////////////////////////////////////////////////////////
// CTOR
plClimbTriggerComponent::plClimbTriggerComponent()
{
fClassDesc = &gClimbTriggerDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
extern const plArmatureMod * FindArmatureMod(const plSceneObject *obj);
// CONVERT
hsBool plClimbTriggerComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plClimbMsg::Command enterCommand; // when entering the region
plClimbMsg::Command exitCommand; // run this command when exiting the region
hsBool enterStatus = false;
hsBool exitStatus = false;
plClimbMsg::Direction direction; // direction is assumed the same for both enter and exit commands
// i.e. enable up, disable up
int iCommand = fCompPB->GetInt(plClimbTriggerComponent::kCommand);
int iDirection = fCompPB->GetInt(plClimbTriggerComponent::kDirection);
switch(iCommand)
{
case kMount:
enterCommand = plClimbMsg::kStartClimbing;
exitCommand = plClimbMsg::kNoCommand;
break;
case kEnableClimb:
enterCommand = plClimbMsg::kEnableClimb;
enterStatus = true;
exitCommand = plClimbMsg::kEnableClimb;
exitStatus = false;
break;
case kDisableClimb:
enterCommand = plClimbMsg::kEnableClimb;
enterStatus = false;
exitCommand = plClimbMsg::kEnableClimb;
exitStatus = true;
break;
case kEnableDismount:
enterCommand = plClimbMsg::kEnableDismount;
enterStatus = true;
exitCommand = plClimbMsg::kEnableDismount;
exitStatus = false;
break;
case kDisableDismount:
enterCommand = plClimbMsg::kEnableDismount;
enterStatus = false;
exitCommand = plClimbMsg::kEnableDismount;
exitStatus = true;
break;
case kFallOff:
enterCommand = plClimbMsg::kFallOff;
exitCommand = plClimbMsg::kNoCommand;
break;
case kRelease:
enterCommand = plClimbMsg::kRelease;
exitCommand = plClimbMsg::kNoCommand;
break;
}
switch(iDirection)
{
case kUp:
direction = plClimbMsg::kUp;
break;
case kDown:
direction = plClimbMsg::kDown;
break;
case kLeft:
direction = plClimbMsg::kLeft;
break;
case kRight:
direction = plClimbMsg::kRight;
break;
}
plKey nilKey = nil;
plKey target = node->GetSceneObject()->GetKey();
plClimbMsg *enterMsg = nil;
if(enterCommand != plClimbMsg::kNoCommand)
{
enterMsg = TRACKED_NEW plClimbMsg(nilKey, nilKey, enterCommand, direction, enterStatus, target);
enterMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
enterMsg->SetBCastFlag(plMessage::kNetPropagate);
enterMsg->SetBCastFlag(plMessage::kNetForce);
}
plClimbMsg *exitMsg = nil;
if(exitCommand != nil)
{
exitMsg = TRACKED_NEW plClimbMsg(nilKey, nilKey, exitCommand, direction, exitStatus, target);
exitMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
exitMsg->SetBCastFlag(plMessage::kNetPropagate);
exitMsg->SetBCastFlag(plMessage::kNetForce);
}
plSimpleRegionSensor *sensMod = TRACKED_NEW plSimpleRegionSensor(enterMsg, exitMsg);
node->AddModifier(sensMod, IGetUniqueName(node));
return true;
}
hsBool plClimbTriggerComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg)
{
node->SetForceLocal(true);
node->SetDrawable(false);
plPhysicalProps *props = node->GetPhysicalProps();
// only if movable will it have mass (then it will keep track of movements in PhysX)
if ( node->IsMovable() || node->IsTMAnimatedRecur() )
props->SetMass(1.0, node, pErrMsg);
props->SetFriction(0.0, node, pErrMsg);
props->SetRestitution(0.0, node, pErrMsg);
props->SetBoundsType(plSimDefs::kExplicitBounds, node, pErrMsg);
props->SetGroup(plSimDefs::kGroupDetector, node, pErrMsg);
props->SetReportGroup(1<<plSimDefs::kGroupAvatar, node, pErrMsg);
// props->SetPinned(true, node, pErrMsg);
return true;
}
/////////////////////////////////////////////////////////////////
//
// DIALOG PROC IMPLEMENTATION
//
/////////////////////////////////////////////////////////////////
BOOL plClimbTriggerComponentProc::DlgProc(TimeValue t, IParamMap2 *pm, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
IParamBlock2 *pb = pm->GetParamBlock();
HWND hCommandMenu = GetDlgItem(hWnd, IDC_COMP_CLIMB_COMMAND);
HWND hDirectionMenu = GetDlgItem(hWnd, IDC_COMP_CLIMB_DIRECTION);
HWND hPick = GetDlgItem(hWnd, IDC_COMP_WALL_PICK);
INode *curPick = nil;
int curSurface = 0;
switch (msg)
{
case WM_INITDIALOG:
{
int i = 0;
// fill out the command menu
for (i = 0; i < kMaxCommands; i++)
ComboBox_AddString(hCommandMenu, fCommandStrs[i]);
// reflect the current selection
ComboBox_SetCurSel(hCommandMenu, pb->GetInt(ParamID(plClimbTriggerComponent::kCommand)));
// fill out the direction menu
for (i = 0; i < kMaxDirections; i++)
ComboBox_AddString(hDirectionMenu, fDirectionStrs[i]);
// reflect the current selection
ComboBox_SetCurSel(hDirectionMenu, pb->GetInt(ParamID(plClimbTriggerComponent::kDirection)));
// show the name of the currently picked item
curPick = pb->GetINode(ParamID(plClimbTriggerComponent::kWallPicker));
Button_SetText(hPick, (curPick == nil ? "None" : curPick->GetName()));
}
return TRUE;
break;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED)
{
if (LOWORD(wParam) == IDC_COMP_WALL_PICK)
{
// we're picking a new climbing wall
std::vector<Class_ID> pickableClasses;
pickableClasses.push_back(PHYSICS_TERRAIN_CID); // allow picking terrains
pickableClasses.push_back(PHYS_CLIMBABLE_CID); // and climbables
if (plPick::NodeRefKludge(pb, plClimbTriggerComponent::kWallPicker, &pickableClasses, true, false))
{
curPick = pb->GetINode(ParamID(plClimbTriggerComponent::kWallPicker));
Button_SetText(hPick, (curPick == nil ? "None" : curPick->GetName()));
}
return TRUE;
}
}
else if (LOWORD(wParam) == IDC_COMP_CLIMB_COMMAND)
{
HWND hSurface = GetDlgItem(hWnd, IDC_COMP_CLIMB_COMMAND);
curSurface = ComboBox_GetCurSel(hSurface);
pb->SetValue(ParamID(plClimbTriggerComponent::kCommand), 0, curSurface);
}
else if (LOWORD(wParam) == IDC_COMP_CLIMB_DIRECTION)
{
HWND hSurface = GetDlgItem(hWnd, IDC_COMP_CLIMB_DIRECTION);
curSurface = ComboBox_GetCurSel(hSurface);
pb->SetValue(ParamID(plClimbTriggerComponent::kDirection), 0, curSurface);
}
}
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// CLIMB BLOCKER COMPONENT
//
/////////////////////////////////////////////////////////////////////////////////////////
//Class that accesses the paramblock below.
class plClimbBlockerComponent : public plComponent
{
public:
plClimbBlockerComponent();
// 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(plClimbBlockerComponent, gClimbBlockDesc, "Climb Blocker", "ClimbBlocker", COMP_TYPE_AVATAR, Class_ID(0x170000ac, 0x3cee02c5))
ParamBlockDesc2 gClimbBlockBk
(
plComponent::kBlkComp, _T("Climb Blocker"), 0, &gClimbBlockDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_CLIMB_BLOCK, IDS_COMP_CLIMB_BLOCKER, 0, 0, NULL,
end
);
plClimbBlockerComponent::plClimbBlockerComponent()
{
fClassDesc = &gClimbBlockDesc;
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 plClimbBlockerComponent::SetupProperties(plMaxNode *node, plErrorMsg *errMsg)
{
node->SetDrawable(false);
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->SetPinned(true, node, errMsg);
props->SetLOSBlockCustom(true, node, errMsg);
return true;
}
hsBool plClimbBlockerComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}