Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1040 lines
40 KiB
C++
1040 lines
40 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: MultiMapper.cpp
|
|
//
|
|
// Desc: This is a simple sample to demonstrate how to code using the DInput
|
|
// action mapper feature.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#define STRICT
|
|
#define DIRECTINPUT_VERSION 0x0800
|
|
#include <windows.h>
|
|
#include <basetsd.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <DXErr8.h>
|
|
#include <tchar.h>
|
|
#include <dinput.h>
|
|
#include "MultiDI.h"
|
|
#include "DXUtil.h"
|
|
#include "resource.h"
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Defines, and constants
|
|
//-----------------------------------------------------------------------------
|
|
#define SAMPLE_KEY TEXT("Software\\Microsoft\\DirectX SDK\\MultiMapper")
|
|
|
|
// This GUID must be unique for every game, and the same for
|
|
// every instance of this app. // {67131584-2938-4857-8A2E-D99DC2C82068}
|
|
// The GUID allows DirectInput to remember input settings
|
|
GUID g_guidApp = { 0x67131584, 0x2938, 0x4857, { 0x8a, 0x2e, 0xd9, 0x9d, 0xc2, 0xc8, 0x20, 0x68 } };
|
|
|
|
|
|
// DirectInput action mapper reports events only when buttons/axis change
|
|
// so we need to remember the present state of relevant axis/buttons for
|
|
// each DirectInput device. The CMultiplayerInputDeviceManager will store a
|
|
// pointer for each device that points to this struct
|
|
struct InputDeviceState
|
|
{
|
|
FLOAT fAxisMoveUD;
|
|
BOOL bButtonForwardThrust;
|
|
BOOL bButtonReverseThrust;
|
|
|
|
FLOAT fAxisRotateLR;
|
|
BOOL bButtonRotateLeft;
|
|
BOOL bButtonRotateRight;
|
|
|
|
BOOL bButtonFireWeapons;
|
|
BOOL bButtonEnableShield;
|
|
};
|
|
|
|
|
|
// Struct to store the current input state
|
|
struct UserInput
|
|
{
|
|
FLOAT fAxisMoveUD;
|
|
FLOAT fAxisRotateLR;
|
|
BOOL bButtonFireWeapons;
|
|
BOOL bButtonEnableShield;
|
|
|
|
BOOL bDoConfigureInput;
|
|
BOOL bDoQuitGame;
|
|
};
|
|
|
|
|
|
// Input semantics used by this app
|
|
enum INPUT_SEMANTICS
|
|
{
|
|
// Gameplay semantics
|
|
INPUT_ROTATE_AXIS_LR=1, INPUT_MOVE_AXIS_UD,
|
|
INPUT_FIREWEAPONS, INPUT_ENABLESHIELD,
|
|
INPUT_TURNLEFT, INPUT_TURNRIGHT,
|
|
INPUT_FORWARDTHRUST, INPUT_REVERSETHRUST,
|
|
INPUT_DISPLAYGAMEMENU, INPUT_QUITGAME,
|
|
};
|
|
|
|
// Actions used by this app
|
|
DIACTION g_rgGameAction[] =
|
|
{
|
|
// If DirectInput has already been given an action map for this GUID, it
|
|
// will have created a user map for this application
|
|
// (C:\Program Files\DirectX\DirectInput\User Maps\*.ini). If a user map
|
|
// exists, DirectInput will use the action map defined in the stored user
|
|
// map instead of the map defined in your program. This allows the user to
|
|
// customize controls without losing changes when the game restarts. If you
|
|
// wish to make changes to the default action map without changing the
|
|
// GUID, you will need to delete the stored user map from your hard drive
|
|
// for the system to detect your changes and recreate a stored user map.
|
|
|
|
// Device input (joystick, etc.) that is pre-defined by DInput, according
|
|
// to genre type. The genre for this app is space simulators.
|
|
{ INPUT_ROTATE_AXIS_LR, DIAXIS_SPACESIM_LATERAL, 0, TEXT("Turn left/right"), },
|
|
{ INPUT_MOVE_AXIS_UD, DIAXIS_SPACESIM_MOVE, 0, TEXT("Move"), },
|
|
{ INPUT_FIREWEAPONS, DIBUTTON_SPACESIM_FIRE, 0, TEXT("Shoot"), },
|
|
{ INPUT_ENABLESHIELD, DIBUTTON_SPACESIM_GEAR, 0, TEXT("Shield"), },
|
|
{ INPUT_DISPLAYGAMEMENU, DIBUTTON_SPACESIM_DISPLAY, 0, TEXT("Configure"), },
|
|
|
|
// Keyboard input mappings
|
|
{ INPUT_TURNLEFT, DIKEYBOARD_LEFT, 0, TEXT("Turn left"), },
|
|
{ INPUT_TURNRIGHT, DIKEYBOARD_RIGHT, 0, TEXT("Turn right"), },
|
|
{ INPUT_FORWARDTHRUST, DIKEYBOARD_UP, 0, TEXT("Move forward"), },
|
|
{ INPUT_REVERSETHRUST, DIKEYBOARD_DOWN, 0, TEXT("Move backward"), },
|
|
{ INPUT_FIREWEAPONS, DIKEYBOARD_F, 0, TEXT("Fire weapons"), },
|
|
{ INPUT_ENABLESHIELD, DIKEYBOARD_S, 0, TEXT("Enable shields"), },
|
|
{ INPUT_DISPLAYGAMEMENU, DIKEYBOARD_D, DIA_APPFIXED, TEXT("Configure"), },
|
|
{ INPUT_QUITGAME, DIKEYBOARD_ESCAPE, DIA_APPFIXED, TEXT("Quit game"), },
|
|
|
|
// Mouse input mappings
|
|
{ INPUT_ROTATE_AXIS_LR, DIMOUSE_XAXIS, 0, _T("Turn left/right"), },
|
|
{ INPUT_MOVE_AXIS_UD, DIMOUSE_YAXIS, 0, _T("Move"), },
|
|
{ INPUT_FIREWEAPONS, DIMOUSE_BUTTON0, 0, _T("Shoot"), },
|
|
{ INPUT_ENABLESHIELD, DIMOUSE_BUTTON1, 0, _T("Enable shields"), },
|
|
};
|
|
|
|
#define NUMBER_OF_GAMEACTIONS (sizeof(g_rgGameAction)/sizeof(DIACTION))
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Function prototypes
|
|
//-----------------------------------------------------------------------------
|
|
INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: class CMyApplication
|
|
// Desc: Application class.
|
|
//-----------------------------------------------------------------------------
|
|
class CMyApplication
|
|
{
|
|
TCHAR* m_strWindowTitle; // Title for the app's window
|
|
HWND m_hWnd; // The main app window
|
|
FLOAT m_fTime; // Current time in seconds
|
|
FLOAT m_fElapsedTime; // Time elapsed since last frame
|
|
|
|
CMultiplayerInputDeviceManager* m_pInputDeviceManager; // DirectInput multiplayer device manager
|
|
DIACTIONFORMAT m_diafGame; // Action format for game play
|
|
UserInput m_UserInput[4]; // Struct for storing user input
|
|
|
|
DWORD m_dwNumPlayers; // Number of players in the game
|
|
FLOAT m_fWorldRotX; // World rotation state X-axis
|
|
FLOAT m_fWorldRotY; // World rotation state Y-axis
|
|
|
|
protected:
|
|
HRESULT OneTimeSceneInit();
|
|
HRESULT Render();
|
|
HRESULT FrameMove();
|
|
HRESULT FinalCleanup();
|
|
|
|
HRESULT EnableUI();
|
|
HRESULT RenderText();
|
|
|
|
HRESULT InitInput();
|
|
HRESULT ChangeNumPlayers( DWORD dwNumPlayers, BOOL bResetOwnership, BOOL bResetMappings );
|
|
VOID ConfigInput();
|
|
void UpdateInput();
|
|
void CleanupDirectInput();
|
|
void CleanupDeviceStateStructs();
|
|
|
|
public:
|
|
HRESULT Create( HINSTANCE hInstance );
|
|
INT Run();
|
|
INT_PTR MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
|
|
|
CMyApplication();
|
|
|
|
HRESULT InputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi );
|
|
static HRESULT CALLBACK StaticInputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID pParam );
|
|
};
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Global access to the app (needed for the global WndProc())
|
|
//-----------------------------------------------------------------------------
|
|
CMyApplication* g_pApp = NULL;
|
|
HINSTANCE g_hInst = NULL;
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: WinMain()
|
|
// Desc: Application entry point
|
|
//-----------------------------------------------------------------------------
|
|
INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
|
|
{
|
|
CMyApplication app;
|
|
|
|
g_hInst = hInstance;
|
|
|
|
if( FAILED( app.Create( hInstance ) ) )
|
|
return 0;
|
|
|
|
return app.Run();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CMyApplication()
|
|
// Desc: Constructor
|
|
//-----------------------------------------------------------------------------
|
|
CMyApplication::CMyApplication()
|
|
{
|
|
g_pApp = this;
|
|
m_hWnd = NULL;
|
|
m_strWindowTitle = TEXT( "DirectInput MultiMapper Sample" );
|
|
m_pInputDeviceManager = NULL;
|
|
|
|
ZeroMemory( m_UserInput, sizeof(UserInput)*4 );
|
|
m_fWorldRotX = 0.0f;
|
|
m_fWorldRotY = 0.0f;
|
|
m_dwNumPlayers = 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Create()
|
|
// Desc: Creates the window
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::Create( HINSTANCE hInstance )
|
|
{
|
|
// Display the main dialog box.
|
|
CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAIN),
|
|
NULL, StaticMsgProc );
|
|
if( NULL == m_hWnd )
|
|
return E_FAIL;
|
|
|
|
// Initialize the application timer
|
|
DXUtil_Timer( TIMER_START );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Run()
|
|
// Desc: Handles the message loop and calls FrameMove() and Render() when
|
|
// idle.
|
|
//-----------------------------------------------------------------------------
|
|
INT CMyApplication::Run()
|
|
{
|
|
MSG msg;
|
|
|
|
// Message loop to run the app
|
|
while( TRUE )
|
|
{
|
|
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
|
|
{
|
|
// Skip WM_KEYDOWN so they aren't handled by the dialog
|
|
if( msg.message == WM_KEYDOWN )
|
|
continue;
|
|
|
|
if( !IsDialogMessage( m_hWnd, &msg ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
|
|
if( msg.message == WM_QUIT )
|
|
{
|
|
DestroyWindow( m_hWnd );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Update the time variables
|
|
m_fTime = DXUtil_Timer( TIMER_GETAPPTIME );
|
|
m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
|
|
|
|
// This app uses idle time processing for the game loop
|
|
if( FAILED( FrameMove() ) )
|
|
SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
|
|
if( FAILED( Render() ) )
|
|
SendMessage( m_hWnd, WM_DESTROY, 0, 0 );
|
|
|
|
Sleep( 20 );
|
|
}
|
|
}
|
|
|
|
FinalCleanup();
|
|
|
|
return (INT)msg.wParam;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: OneTimeSceneInit()
|
|
// Desc: Called during initial app startup, this function performs all the
|
|
// permanent initialization.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::OneTimeSceneInit()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Load the icon
|
|
HICON hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE( IDI_MAIN ) );
|
|
|
|
// Set the icon for this dialog.
|
|
SendMessage( m_hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon ); // Set big icon
|
|
SendMessage( m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIcon ); // Set small icon
|
|
|
|
// Initialize DirectInput
|
|
if( FAILED( hr = InitInput() ) )
|
|
return DXTRACE_ERR( TEXT("InitInput"), hr );
|
|
|
|
HWND hNumPlayers = GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO );
|
|
SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("1") );
|
|
SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("2") );
|
|
SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("3") );
|
|
SendMessage( hNumPlayers, CB_ADDSTRING, 0, (LPARAM) TEXT("4") );
|
|
SendMessage( hNumPlayers, CB_SETCURSEL, m_dwNumPlayers-1, 0 );
|
|
|
|
EnableUI();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: InitInput()
|
|
// Desc: Initialize DirectInput objects
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::InitInput()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Setup action format for the actual gameplay
|
|
ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
|
|
m_diafGame.dwSize = sizeof(DIACTIONFORMAT);
|
|
m_diafGame.dwActionSize = sizeof(DIACTION);
|
|
m_diafGame.dwDataSize = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
|
|
m_diafGame.guidActionMap = g_guidApp;
|
|
m_diafGame.dwGenre = DIVIRTUAL_SPACESIM;
|
|
m_diafGame.dwNumActions = NUMBER_OF_GAMEACTIONS;
|
|
m_diafGame.rgoAction = g_rgGameAction;
|
|
m_diafGame.lAxisMin = -100;
|
|
m_diafGame.lAxisMax = 100;
|
|
m_diafGame.dwBufferSize = 16;
|
|
_tcscpy( m_diafGame.tszActionMap, _T("MultiMapper Sample") );
|
|
|
|
// Create a new input device manager
|
|
m_pInputDeviceManager = new CMultiplayerInputDeviceManager( SAMPLE_KEY );
|
|
|
|
if( FAILED( hr = ChangeNumPlayers( 1, FALSE, FALSE ) ) )
|
|
return DXTRACE_ERR( TEXT("ChangeNumPlayers"), hr );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: StaticInputAddDeviceCB()
|
|
// Desc: Static callback helper to call into CMyApplication class
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CALLBACK CMyApplication::StaticInputAddDeviceCB(
|
|
CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo,
|
|
CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo,
|
|
const DIDEVICEINSTANCE* pdidi,
|
|
LPVOID pParam )
|
|
{
|
|
CMyApplication* pApp = (CMyApplication*) pParam;
|
|
return pApp->InputAddDeviceCB( pPlayerInfo, pDeviceInfo, pdidi );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: InputAddDeviceCB()
|
|
// Desc: Called from CMultiplayerInputDeviceManager whenever a device is added.
|
|
// Set the dead zone, and creates a new InputDeviceState for each device
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::InputAddDeviceCB( CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo,
|
|
CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo,
|
|
const DIDEVICEINSTANCE* pdidi )
|
|
{
|
|
if( (GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_KEYBOARD) &&
|
|
(GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_MOUSE) )
|
|
{
|
|
// Setup the deadzone
|
|
DIPROPDWORD dipdw;
|
|
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dipdw.diph.dwObj = 0;
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
dipdw.dwData = 500;
|
|
pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
|
|
}
|
|
|
|
// Create a new InputDeviceState for each device so the
|
|
// app can record its state
|
|
InputDeviceState* pNewInputDeviceState = new InputDeviceState;
|
|
ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
|
|
pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
|
|
|
|
HWND hPlayerDevice;
|
|
switch( pPlayerInfo->dwPlayerIndex )
|
|
{
|
|
case 0:
|
|
hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P1 );
|
|
break;
|
|
case 1:
|
|
hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P2 );
|
|
break;
|
|
case 2:
|
|
hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P3 );
|
|
break;
|
|
case 3:
|
|
hPlayerDevice = GetDlgItem( m_hWnd, IDC_DEVICE_ASSIGNED_P4 );
|
|
break;
|
|
}
|
|
|
|
SendMessage( hPlayerDevice, LB_ADDSTRING, 0, (LPARAM) pdidi->tszProductName );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ChangeNumPlayers()
|
|
// Desc: Signals a change in the number of players. It is also called to reset
|
|
// ownership and mapping data.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::ChangeNumPlayers( DWORD dwNumPlayers, BOOL bResetOwnership,
|
|
BOOL bResetMappings )
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_dwNumPlayers = dwNumPlayers;
|
|
|
|
// Just pass in stock names. Real games may want to ask the user for a name, etc.
|
|
TCHAR* strUserNames[4] = { TEXT("Player 1"), TEXT("Player 2"),
|
|
TEXT("Player 3"), TEXT("Player 4") };
|
|
|
|
BOOL bSuccess = FALSE;
|
|
while( !bSuccess )
|
|
{
|
|
// Update UI
|
|
EnableUI();
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P1), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), LB_RESETCONTENT, 0, 0 );
|
|
|
|
hr = m_pInputDeviceManager->Create( m_hWnd, strUserNames, m_dwNumPlayers, &m_diafGame,
|
|
StaticInputAddDeviceCB, this,
|
|
bResetOwnership, bResetMappings );
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
switch( hr )
|
|
{
|
|
case E_DIUTILERR_DEVICESTAKEN:
|
|
{
|
|
// It's possible that a single user could "own" too many devices for the other
|
|
// players to get into the game. If so, we reinit the manager class to provide
|
|
// each user with a device that has a default configuration.
|
|
bResetOwnership = TRUE;
|
|
|
|
MessageBox( m_hWnd, TEXT("You have entered more users than there are suitable ") \
|
|
TEXT("devices, or some users are claiming too many devices.\n") \
|
|
TEXT("Press OK to give each user a default device"),
|
|
TEXT("Devices Are Taken"), MB_OK | MB_ICONEXCLAMATION );
|
|
break;
|
|
}
|
|
|
|
case E_DIUTILERR_TOOMANYUSERS:
|
|
{
|
|
// Another common error is if more users are attempting to play than there are devices
|
|
// attached to the machine. In this case, the number of players is automatically
|
|
// lowered to make playing the game possible.
|
|
DWORD dwNumDevices = m_pInputDeviceManager->GetNumDevices();
|
|
m_dwNumPlayers = dwNumDevices;
|
|
SendMessage( GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO ),
|
|
CB_SETCURSEL, m_dwNumPlayers-1, 0 );
|
|
|
|
TCHAR sz[256];
|
|
wsprintf( sz, TEXT("There are not enough devices attached to the ") \
|
|
TEXT("system for the number of users you entered.\nThe ") \
|
|
TEXT("number of users has been automatically changed to ") \
|
|
TEXT("%i (the number of devices available on the system)."),
|
|
m_dwNumPlayers );
|
|
MessageBox( m_hWnd, sz, _T("Too Many Users"), MB_OK | MB_ICONEXCLAMATION );
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return DXTRACE_ERR( TEXT("m_pInputDeviceManager->Create"), hr );
|
|
break;
|
|
}
|
|
|
|
m_pInputDeviceManager->Cleanup();
|
|
}
|
|
else
|
|
{
|
|
bSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: FrameMove()
|
|
// Desc: Called once per frame, the call is the entry point for animating
|
|
// the scene.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::FrameMove()
|
|
{
|
|
// Update user input state
|
|
UpdateInput();
|
|
|
|
for( DWORD iPlayer=0; iPlayer<m_dwNumPlayers; iPlayer++ )
|
|
{
|
|
// Respond to input
|
|
if( m_UserInput[iPlayer].bDoConfigureInput )
|
|
{
|
|
// One-shot per keypress
|
|
m_UserInput[iPlayer].bDoConfigureInput = FALSE;
|
|
|
|
ConfigInput();
|
|
}
|
|
|
|
// Update the world state according to user input
|
|
if( m_UserInput[iPlayer].fAxisMoveUD )
|
|
m_fWorldRotY += m_fElapsedTime * m_UserInput[iPlayer].fAxisMoveUD;
|
|
|
|
if( m_UserInput[iPlayer].fAxisRotateLR )
|
|
m_fWorldRotX += m_fElapsedTime * m_UserInput[iPlayer].fAxisRotateLR;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: UpdateInput()
|
|
// Desc: Update the user input. Called once per frame
|
|
//-----------------------------------------------------------------------------
|
|
void CMyApplication::UpdateInput()
|
|
{
|
|
if( NULL == m_pInputDeviceManager )
|
|
return;
|
|
|
|
CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfos;
|
|
DWORD dwNumDevices;
|
|
|
|
// Get access to the list of semantically-mapped input devices
|
|
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
|
|
|
|
// Loop through all devices and check game input
|
|
for( DWORD i=0; i<dwNumDevices; i++ )
|
|
{
|
|
// skip past any devices that aren't assigned,
|
|
// since we don't care about them
|
|
if( pDeviceInfos[i].pPlayerInfo == NULL )
|
|
continue;
|
|
|
|
DIDEVICEOBJECTDATA rgdod[10];
|
|
DWORD dwItems = 10;
|
|
HRESULT hr;
|
|
LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
|
|
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
|
|
FLOAT fScale = 1.0f;
|
|
|
|
if( pDeviceInfos[i].bRelativeAxis )
|
|
{
|
|
// For relative axis data, the action mapper only informs us when
|
|
// the delta data is non-zero, so we need to zero its state
|
|
// out each frame
|
|
pInputDeviceState->fAxisMoveUD = 0.0f;
|
|
pInputDeviceState->fAxisRotateLR = 0.0f;
|
|
|
|
// Scale the relative axis data to make it more equal to
|
|
// absolute joystick data
|
|
fScale = 5.0f;
|
|
}
|
|
|
|
hr = pdidDevice->Acquire();
|
|
hr = pdidDevice->Poll();
|
|
hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
|
|
rgdod, &dwItems, 0 );
|
|
if( FAILED(hr) )
|
|
continue;
|
|
|
|
// Get the sematics codes for the game menu
|
|
for( DWORD j=0; j<dwItems; j++ )
|
|
{
|
|
BOOL bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
|
|
FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
|
|
FLOAT fAxisState = (FLOAT)((int)rgdod[j].dwData)/100.0f * fScale;
|
|
|
|
switch( rgdod[j].uAppData )
|
|
{
|
|
// Handle relative axis data
|
|
case INPUT_ROTATE_AXIS_LR:
|
|
pInputDeviceState->fAxisRotateLR = fAxisState;
|
|
break;
|
|
case INPUT_MOVE_AXIS_UD:
|
|
pInputDeviceState->fAxisMoveUD = -fAxisState;
|
|
break;
|
|
|
|
// Handle buttons separately so the button state data
|
|
// doesn't overwrite the axis state data, and handle
|
|
// each button separately so they don't overwrite each other
|
|
case INPUT_TURNLEFT: pInputDeviceState->bButtonRotateLeft = bButtonState; break;
|
|
case INPUT_TURNRIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break;
|
|
case INPUT_FORWARDTHRUST: pInputDeviceState->bButtonForwardThrust = bButtonState; break;
|
|
case INPUT_REVERSETHRUST: pInputDeviceState->bButtonReverseThrust = bButtonState; break;
|
|
case INPUT_FIREWEAPONS: pInputDeviceState->bButtonFireWeapons = bButtonState; break;
|
|
case INPUT_ENABLESHIELD: pInputDeviceState->bButtonEnableShield = bButtonState; break;
|
|
|
|
// Handle one-shot buttons
|
|
case INPUT_DISPLAYGAMEMENU: if( bButtonState ) m_UserInput[0].bDoConfigureInput = TRUE; break;
|
|
case INPUT_QUITGAME: if( bButtonState ) m_UserInput[0].bDoQuitGame = TRUE; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for( DWORD iPlayer=0; iPlayer<m_dwNumPlayers; iPlayer++ )
|
|
{
|
|
// Process user input and store result into pUserInput struct
|
|
m_UserInput[iPlayer].fAxisRotateLR = 0.0f;
|
|
m_UserInput[iPlayer].fAxisMoveUD = 0.0f;
|
|
m_UserInput[iPlayer].bButtonFireWeapons = FALSE;
|
|
m_UserInput[iPlayer].bButtonEnableShield = FALSE;
|
|
|
|
// Concatinate the data from all the DirectInput devices
|
|
for( i=0; i<dwNumDevices; i++ )
|
|
{
|
|
// Only look at devices that are assigned to this player
|
|
if( pDeviceInfos[i].pPlayerInfo == NULL ||
|
|
pDeviceInfos[i].pPlayerInfo->dwPlayerIndex != iPlayer )
|
|
continue;
|
|
|
|
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
|
|
|
|
// Use the axis data that is furthest from zero
|
|
if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(m_UserInput[iPlayer].fAxisRotateLR) )
|
|
m_UserInput[iPlayer].fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
|
|
|
|
if( fabs(pInputDeviceState->fAxisMoveUD) > fabs(m_UserInput[iPlayer].fAxisMoveUD) )
|
|
m_UserInput[iPlayer].fAxisMoveUD = pInputDeviceState->fAxisMoveUD;
|
|
|
|
// Process the button data
|
|
if( pInputDeviceState->bButtonRotateLeft )
|
|
m_UserInput[iPlayer].fAxisRotateLR = -1.0f;
|
|
else if( pInputDeviceState->bButtonRotateRight )
|
|
m_UserInput[iPlayer].fAxisRotateLR = 1.0f;
|
|
|
|
if( pInputDeviceState->bButtonForwardThrust )
|
|
m_UserInput[iPlayer].fAxisMoveUD = 1.0f;
|
|
else if( pInputDeviceState->bButtonReverseThrust )
|
|
m_UserInput[iPlayer].fAxisMoveUD = -1.0f;
|
|
|
|
if( pInputDeviceState->bButtonFireWeapons )
|
|
m_UserInput[iPlayer].bButtonFireWeapons = TRUE;
|
|
if( pInputDeviceState->bButtonEnableShield )
|
|
m_UserInput[iPlayer].bButtonEnableShield = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Render()
|
|
// Desc: Called once per frame, the call is the entry point for rendering the
|
|
// world.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::Render()
|
|
{
|
|
TCHAR szMsg[MAX_PATH];
|
|
TCHAR szMsgCurrent[MAX_PATH];
|
|
|
|
// Update Player 1
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[0].fAxisMoveUD );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P1), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P1), szMsg );
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[0].fAxisRotateLR );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P1), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P1), szMsg );
|
|
if( !m_UserInput[0].bButtonEnableShield && !m_UserInput[0].bButtonFireWeapons )
|
|
_stprintf( szMsg, TEXT("None") );
|
|
else
|
|
_stprintf( szMsg, TEXT("%s%s"), m_UserInput[0].bButtonEnableShield ? TEXT("Shield ") : TEXT(""),
|
|
m_UserInput[0].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P1), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P1), szMsg );
|
|
|
|
// Update Player 2
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[1].fAxisMoveUD );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), szMsg );
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[1].fAxisRotateLR );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), szMsg );
|
|
if( !m_UserInput[1].bButtonEnableShield && !m_UserInput[1].bButtonFireWeapons )
|
|
_stprintf( szMsg, TEXT("None") );
|
|
else
|
|
_stprintf( szMsg, TEXT("%s%s"), m_UserInput[1].bButtonEnableShield ? TEXT("Shield ") : TEXT(""),
|
|
m_UserInput[1].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), szMsg );
|
|
|
|
// Update Player 3
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[2].fAxisMoveUD );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), szMsg );
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[2].fAxisRotateLR );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), szMsg );
|
|
if( !m_UserInput[2].bButtonEnableShield && !m_UserInput[2].bButtonFireWeapons )
|
|
_stprintf( szMsg, TEXT("None") );
|
|
else
|
|
_stprintf( szMsg, TEXT("%s%s"), m_UserInput[2].bButtonEnableShield ? TEXT("Shield ") : TEXT(""),
|
|
m_UserInput[2].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), szMsg );
|
|
|
|
// Update Player 4
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[3].fAxisMoveUD );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), szMsg );
|
|
_stprintf( szMsg, TEXT("%0.2f"), m_UserInput[3].fAxisRotateLR );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), szMsg );
|
|
if( !m_UserInput[3].bButtonEnableShield && !m_UserInput[3].bButtonFireWeapons )
|
|
_stprintf( szMsg, TEXT("None") );
|
|
else
|
|
_stprintf( szMsg, TEXT("%s%s"), m_UserInput[3].bButtonEnableShield ? TEXT("Shield ") : TEXT(""),
|
|
m_UserInput[3].bButtonFireWeapons ? TEXT("Fire ") : TEXT("") );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), szMsg );
|
|
|
|
// Update world state
|
|
_stprintf( szMsg, TEXT("%0.3f, %0.3f"), m_fWorldRotX, m_fWorldRotY );
|
|
GetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsgCurrent, MAX_PATH );
|
|
if( lstrcmp( szMsgCurrent, szMsg ) != 0 )
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_WORLD_STATE), szMsg );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: StaticMsgProc()
|
|
// Desc: Static msg handler which passes messages to the application class.
|
|
//-----------------------------------------------------------------------------
|
|
INT_PTR CALLBACK StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
return g_pApp->MsgProc( hWnd, uMsg, wParam, lParam );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: MsgProc()
|
|
// Desc: Callback for all Windows messages
|
|
//-----------------------------------------------------------------------------
|
|
INT_PTR CMyApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
HRESULT hr;
|
|
|
|
switch( msg )
|
|
{
|
|
case WM_INITDIALOG:
|
|
m_hWnd = hWnd;
|
|
|
|
// Initialize the app's custom scene stuff
|
|
if( FAILED( hr = OneTimeSceneInit() ) )
|
|
{
|
|
DXTRACE_ERR( TEXT("OneTimeSceneInit"), hr );
|
|
MessageBox( hWnd, TEXT("Error initializing DirectInput. Sample will now exit."),
|
|
TEXT("DirectInput Sample"), MB_OK | MB_ICONERROR );
|
|
PostQuitMessage( IDCANCEL );
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
switch( LOWORD(wParam) )
|
|
{
|
|
case IDC_NUM_PLAYERS_COMBO:
|
|
{
|
|
if( HIWORD(wParam) == CBN_SELCHANGE )
|
|
{
|
|
TCHAR strItem[MAX_PATH];
|
|
HWND hNumPlayers = GetDlgItem( m_hWnd, IDC_NUM_PLAYERS_COMBO );
|
|
|
|
int nCurSel = (int) SendMessage( hNumPlayers, CB_GETCURSEL, 0, 0 );
|
|
SendMessage( hNumPlayers, CB_GETLBTEXT, nCurSel, (LPARAM) strItem );
|
|
DWORD dwNumPlayers = _ttoi( strItem );
|
|
|
|
if( FAILED( hr = ChangeNumPlayers( dwNumPlayers, FALSE, FALSE ) ) )
|
|
{
|
|
PostQuitMessage( IDCANCEL );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IDC_RESET_OWNERSHIP:
|
|
ChangeNumPlayers( m_dwNumPlayers, TRUE, FALSE );
|
|
break;
|
|
|
|
case IDC_RESET_MAPPINGS:
|
|
ChangeNumPlayers( m_dwNumPlayers, FALSE, TRUE );
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
PostQuitMessage( IDCANCEL );
|
|
break;
|
|
|
|
case IDM_CONFIGINPUT:
|
|
m_UserInput[0].bDoConfigureInput = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: FinalCleanup()
|
|
// Desc: Called before the app exits, this function gives the app the chance
|
|
// to cleanup after itself.
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::FinalCleanup()
|
|
{
|
|
// Cleanup DirectInput
|
|
CleanupDirectInput();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CleanupDirectInput()
|
|
// Desc: Cleanup DirectInput
|
|
//-----------------------------------------------------------------------------
|
|
VOID CMyApplication::CleanupDirectInput()
|
|
{
|
|
if( NULL == m_pInputDeviceManager )
|
|
return;
|
|
|
|
CleanupDeviceStateStructs();
|
|
|
|
// Cleanup DirectX input objects
|
|
SAFE_DELETE( m_pInputDeviceManager );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: CleanupDeviceStateStructs()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID CMyApplication::CleanupDeviceStateStructs()
|
|
{
|
|
// Get access to the list of semantically-mapped input devices
|
|
// to delete all InputDeviceState structs before calling ConfigureDevices()
|
|
CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfos;
|
|
DWORD dwNumDevices;
|
|
|
|
m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
|
|
|
|
for( DWORD i=0; i<dwNumDevices; i++ )
|
|
{
|
|
InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
|
|
SAFE_DELETE( pInputDeviceState );
|
|
pDeviceInfos[i].pParam = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ConfigInput()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
VOID CMyApplication::ConfigInput()
|
|
{
|
|
HRESULT hr;
|
|
|
|
EnableWindow( m_hWnd, FALSE );
|
|
|
|
CleanupDeviceStateStructs();
|
|
|
|
// Update UI
|
|
EnableUI();
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P1), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3), LB_RESETCONTENT, 0, 0 );
|
|
SendMessage( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), LB_RESETCONTENT, 0, 0 );
|
|
|
|
// Configure the devices (with edit capability)
|
|
hr = m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );
|
|
if( FAILED(hr) )
|
|
{
|
|
if( hr == E_DIUTILERR_PLAYERWITHOUTDEVICE )
|
|
{
|
|
// There's a player that hasn't been assigned a device. Some games may
|
|
// want to handle this by reducing the number of players, or auto-assigning
|
|
// a device, or warning the user, etc.
|
|
MessageBox( m_hWnd, TEXT("There is at least one player that wasn't assigned ") \
|
|
TEXT("a device\n") \
|
|
TEXT("Press OK to auto-assign a device to these users"),
|
|
TEXT("Player Without Device"), MB_OK | MB_ICONEXCLAMATION );
|
|
}
|
|
|
|
// Auto-reassign every player a device.
|
|
ChangeNumPlayers( m_dwNumPlayers, FALSE, FALSE );
|
|
}
|
|
|
|
EnableWindow( m_hWnd, TRUE );
|
|
SetForegroundWindow( m_hWnd );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: EnableUI()
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMyApplication::EnableUI()
|
|
{
|
|
BOOL bEnablePlayer4 = ( m_dwNumPlayers > 3 );
|
|
BOOL bEnablePlayer3 = ( m_dwNumPlayers > 2 );
|
|
BOOL bEnablePlayer2 = ( m_dwNumPlayers > 1 );
|
|
|
|
// Enable/disable the player 2 ui
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER2_GROUP), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), bEnablePlayer2 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P2), bEnablePlayer2 );
|
|
if( !bEnablePlayer2 )
|
|
{
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P2), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P2), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P2), TEXT("n/a") );
|
|
}
|
|
|
|
// Enable/disable the player 3 ui
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER3_GROUP), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), bEnablePlayer3 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P3), bEnablePlayer3 );
|
|
if( !bEnablePlayer4 )
|
|
{
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P3), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P3), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P3), TEXT("n/a") );
|
|
}
|
|
|
|
// Enable/disable the player 4 ui
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT1_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT2_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_TEXT3_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_PLAYER4_GROUP), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), bEnablePlayer4 );
|
|
EnableWindow( GetDlgItem(m_hWnd,IDC_DEVICE_ASSIGNED_P4), bEnablePlayer4 );
|
|
if( !bEnablePlayer4 )
|
|
{
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_UD_AXIS_STATE_P4), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_LR_AXIS_STATE_P4), TEXT("n/a") );
|
|
SetWindowText( GetDlgItem(m_hWnd,IDC_BUTTON_STATE_P4), TEXT("n/a") );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|