901 lines
23 KiB
C++
901 lines
23 KiB
C++
// #include "../server/exe_headers.h"
|
|
|
|
#include "../client/client.h"
|
|
//JLF
|
|
#include "../client/client_ui.h"
|
|
|
|
|
|
#include "../qcommon/qcommon.h"
|
|
#ifdef _JK2MP
|
|
#include "../ui/keycodes.h"
|
|
#else
|
|
#include "../client/keycodes.h"
|
|
#endif
|
|
|
|
#include "win_local.h"
|
|
#include "win_input.h"
|
|
|
|
cvar_t *inSplashMenu = NULL;
|
|
cvar_t *controllerOut = NULL;
|
|
|
|
static void HandleDebugJoystickPress(fakeAscii_t button);
|
|
|
|
static bool _UIRunning = false;
|
|
|
|
static bool IN_ControllerMustBePlugged(int controller);
|
|
|
|
// By default, cheatpad is turned on except in final build. Just change
|
|
// here to modify that.
|
|
#ifndef FINAL_BUILD
|
|
//#define DEBUG_CONTROLLER
|
|
#endif
|
|
|
|
// Controller connection globals
|
|
static signed char uiControllerNotification = -1;
|
|
bool noControllersConnected = false;
|
|
bool wasPlugged[4];
|
|
|
|
int mainControllerDelayedUnplug = 0;
|
|
|
|
PadInfo _padInfo; // gamepad thumbstick buffer
|
|
|
|
/**********************************************************
|
|
*
|
|
* CHEAT FUNCTIONS
|
|
*
|
|
**********************************************************/
|
|
|
|
bool Cheat_God( void )
|
|
{
|
|
Cbuf_ExecuteText( EXEC_APPEND, "god\n" );
|
|
return true;
|
|
}
|
|
|
|
void Cheat_GiveAll( void )
|
|
{
|
|
Cbuf_ExecuteText(EXEC_APPEND, "give all\n");
|
|
}
|
|
extern bool Cheat_ChangeSaber( void ); // In wp_saber.cpp
|
|
|
|
#include "../game/anims.h"
|
|
#include "../cgame/cg_local.h"
|
|
static bool isDeathAnimation( int anim )
|
|
{
|
|
switch( anim )
|
|
{
|
|
case BOTH_DEATH1: //# First Death anim
|
|
case BOTH_DEATH2: //# Second Death anim
|
|
case BOTH_DEATH3: //# Third Death anim
|
|
case BOTH_DEATH4: //# Fourth Death anim
|
|
case BOTH_DEATH5: //# Fifth Death anim
|
|
case BOTH_DEATH6: //# Sixth Death anim
|
|
case BOTH_DEATH7: //# Seventh Death anim
|
|
case BOTH_DEATH8: //#
|
|
case BOTH_DEATH9: //#
|
|
case BOTH_DEATH10: //#
|
|
case BOTH_DEATH11: //#
|
|
case BOTH_DEATH12: //#
|
|
case BOTH_DEATH13: //#
|
|
case BOTH_DEATH14: //#
|
|
case BOTH_DEATH14_UNGRIP: //# Desann's end death (cin #35)
|
|
case BOTH_DEATH14_SITUP: //# Tavion sitting up after having been thrown (cin #23)
|
|
case BOTH_DEATH15: //#
|
|
case BOTH_DEATH16: //#
|
|
case BOTH_DEATH17: //#
|
|
case BOTH_DEATH18: //#
|
|
case BOTH_DEATH19: //#
|
|
case BOTH_DEATH20: //#
|
|
case BOTH_DEATH21: //#
|
|
case BOTH_DEATH22: //#
|
|
case BOTH_DEATH23: //#
|
|
case BOTH_DEATH24: //#
|
|
case BOTH_DEATH25: //#
|
|
case BOTH_DEATHFORWARD1: //# First Death in which they get thrown forward
|
|
case BOTH_DEATHFORWARD2: //# Second Death in which they get thrown forward
|
|
case BOTH_DEATHFORWARD3: //# Tavion's falling in cin# 23
|
|
case BOTH_DEATHBACKWARD1: //# First Death in which they get thrown backward
|
|
case BOTH_DEATHBACKWARD2: //# Second Death in which they get thrown backward
|
|
case BOTH_DEATH1IDLE: //# Idle while close to death
|
|
case BOTH_LYINGDEATH1: //# Death to play when killed lying down
|
|
case BOTH_STUMBLEDEATH1: //# Stumble forward and fall face first death
|
|
case BOTH_FALLDEATH1: //# Fall forward off a high cliff and splat death - start
|
|
case BOTH_FALLDEATH1INAIR: //# Fall forward off a high cliff and splat death - loop
|
|
case BOTH_FALLDEATH1LAND: //# Fall forward off a high cliff and splat death - hit bottom
|
|
case BOTH_DEAD1: //# First Death finished pose
|
|
case BOTH_DEAD2: //# Second Death finished pose
|
|
case BOTH_DEAD3: //# Third Death finished pose
|
|
case BOTH_DEAD4: //# Fourth Death finished pose
|
|
case BOTH_DEAD5: //# Fifth Death finished pose
|
|
case BOTH_DEAD6: //# Sixth Death finished pose
|
|
case BOTH_DEAD7: //# Seventh Death finished pose
|
|
case BOTH_DEAD8: //#
|
|
case BOTH_DEAD9: //#
|
|
case BOTH_DEAD10: //#
|
|
case BOTH_DEAD11: //#
|
|
case BOTH_DEAD12: //#
|
|
case BOTH_DEAD13: //#
|
|
case BOTH_DEAD14: //#
|
|
case BOTH_DEAD15: //#
|
|
case BOTH_DEAD16: //#
|
|
case BOTH_DEAD17: //#
|
|
case BOTH_DEAD18: //#
|
|
case BOTH_DEAD19: //#
|
|
case BOTH_DEAD20: //#
|
|
case BOTH_DEAD21: //#
|
|
case BOTH_DEAD22: //#
|
|
case BOTH_DEAD23: //#
|
|
case BOTH_DEAD24: //#
|
|
case BOTH_DEAD25: //#
|
|
case BOTH_DEADFORWARD1: //# First thrown forward death finished pose
|
|
case BOTH_DEADFORWARD2: //# Second thrown forward death finished pose
|
|
case BOTH_DEADBACKWARD1: //# First thrown backward death finished pose
|
|
case BOTH_DEADBACKWARD2: //# Second thrown backward death finished pose
|
|
case BOTH_LYINGDEAD1: //# Killed lying down death finished pose
|
|
case BOTH_STUMBLEDEAD1: //# Stumble forward death finished pose
|
|
case BOTH_FALLDEAD1LAND: //# Fall forward and splat death finished pose
|
|
case BOTH_DEADFLOP1: //# React to being shot from First Death finished pose
|
|
case BOTH_DEADFLOP2: //# React to being shot from Second Death finished pose
|
|
case BOTH_DISMEMBER_HEAD1: //#
|
|
case BOTH_DISMEMBER_TORSO1: //#
|
|
case BOTH_DISMEMBER_LLEG: //#
|
|
case BOTH_DISMEMBER_RLEG: //#
|
|
case BOTH_DISMEMBER_RARM: //#
|
|
case BOTH_DISMEMBER_LARM: //#
|
|
case BOTH_DEATH_ROLL: //# Death anim from a roll
|
|
case BOTH_DEATH_FLIP: //# Death anim from a flip
|
|
case BOTH_DEATH_SPIN_90_R: //# Death anim when facing 90 degrees right
|
|
case BOTH_DEATH_SPIN_90_L: //# Death anim when facing 90 degrees left
|
|
case BOTH_DEATH_SPIN_180: //# Death anim when facing backwards
|
|
case BOTH_DEATH_LYING_UP: //# Death anim when lying on back
|
|
case BOTH_DEATH_LYING_DN: //# Death anim when lying on front
|
|
case BOTH_DEATH_FALLING_DN: //# Death anim when falling on face
|
|
case BOTH_DEATH_FALLING_UP: //# Death anim when falling on back
|
|
case BOTH_DEATH_CROUCHED: //# Death anim when crouched
|
|
return true;
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Cheat_WinLevel( void )
|
|
{
|
|
// Do not do this while any UI is active. It's dangerous:
|
|
extern int Key_GetCatcher( void );
|
|
if( Key_GetCatcher() == KEYCATCH_UI )
|
|
return false;
|
|
|
|
// Also, don't do it during cutscenes:
|
|
extern bool in_camera;
|
|
if( in_camera || ( g_entities[0].client && isDeathAnimation(g_entities[0].client->ps.legsAnim)))
|
|
return false;
|
|
|
|
|
|
// All maps (except kor2) have a trigger item named end_level
|
|
Cbuf_ExecuteText( EXEC_APPEND, "use end_level\n" );
|
|
|
|
return true;
|
|
}
|
|
|
|
#ifndef XBOX_DEMO
|
|
bool Cheat_LevelSelect( void )
|
|
{
|
|
// Set cvar that enables the level select menu:
|
|
Cvar_SetValue( "ui_levelselect", 1 );
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
extern bool Cheat_InfiniteForce( void ); // In wp_saber.cpp
|
|
|
|
#if YELLOW_MODE
|
|
extern bool enableYellowMode;
|
|
char yellowModeLevel = 0;
|
|
bool enableYellowStage2 = false;
|
|
|
|
bool Cheat_Yellow_Stage2( void )
|
|
{
|
|
if(!enableYellowStage2)
|
|
return false;
|
|
|
|
if(IN_GetMainController() != 0)
|
|
return false;
|
|
|
|
if( g_entities[0].client && isDeathAnimation(g_entities[0].client->ps.legsAnim))
|
|
enableYellowMode = true;
|
|
else
|
|
enableYellowMode = false;
|
|
|
|
return enableYellowMode;
|
|
}
|
|
|
|
bool Cheat_Yellow_Stage1( void )
|
|
{
|
|
if(IN_GetMainController() != 1)
|
|
return false;
|
|
|
|
if(yellowModeLevel == 0) // step one, in a cutscene
|
|
{
|
|
extern bool in_camera;
|
|
if(in_camera)
|
|
{
|
|
yellowModeLevel++;
|
|
return true;
|
|
}
|
|
}
|
|
else if( yellowModeLevel == 1 ) // step two, during the splash screen
|
|
{
|
|
if(inSplashMenu->integer)
|
|
{
|
|
yellowModeLevel++;
|
|
return true;
|
|
}
|
|
}
|
|
else if( yellowModeLevel == 2 ) // step three, while force hud is active
|
|
{
|
|
if(cg.forceHUDActive)
|
|
{
|
|
yellowModeLevel++;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if(yellowModeLevel == 3) // eveything is ok, now reset and move to stage 2
|
|
{
|
|
enableYellowStage2 = true;
|
|
yellowModeLevel = 4;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endif // YELLOW_MODE
|
|
|
|
bool Cheat_AllForce( void )
|
|
{
|
|
// Do not do this while the force config UI is running. That causes SERIOUS problems:
|
|
extern bool UI_ForceConfigUIActive( void );
|
|
if( UI_ForceConfigUIActive() )
|
|
return false;
|
|
|
|
// Set all Light powers to level 3:
|
|
Cbuf_ExecuteText( EXEC_APPEND, "setForceHeal 3\nsetMindTrick 3\nsetForceProtect 3\nsetForceAbsorb 3\n" );
|
|
// Set all Dark powers to level 3:
|
|
Cbuf_ExecuteText( EXEC_APPEND, "setForceGrip 3\nsetForceLightning 3\nsetForceRage 3\nsetForceDrain 3\n" );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Cheat_KungFoo( void )
|
|
{
|
|
Cbuf_ExecuteText( EXEC_APPEND, "iknowkungfu\n");
|
|
return qtrue;
|
|
}
|
|
|
|
//
|
|
// CHEAT DATA
|
|
//
|
|
// Every cheat is a sequence of D-pad presses, performed while the right
|
|
// thumbstick is being pressed. The cheat sequences are all length 6, and
|
|
// each cheat is tied to a void (void) function. Mapping:
|
|
// 5 - Up, 7 - Down, 8 - Left, 6 - Right
|
|
typedef bool(*xcommandC_t)(void);
|
|
struct cheat_t
|
|
{
|
|
fakeAscii_t buttons[6];
|
|
xcommandC_t function;
|
|
};
|
|
|
|
cheat_t cheats[] = {
|
|
{ {A_JOY7, A_JOY5, A_JOY8, A_JOY6, A_JOY7, A_JOY5}, Cheat_God },
|
|
//{ {A_JOY6, A_JOY6, A_JOY8, A_JOY8, A_JOY7, A_JOY5}, Cheat_GiveAll },
|
|
{ {A_JOY7, A_JOY8, A_JOY5, A_JOY7, A_JOY6, A_JOY5}, Cheat_ChangeSaber },
|
|
{ {A_JOY5, A_JOY5, A_JOY7, A_JOY7, A_JOY8, A_JOY6}, Cheat_WinLevel },
|
|
#ifndef XBOX_DEMO
|
|
{ {A_JOY6, A_JOY8, A_JOY6, A_JOY7, A_JOY6, A_JOY5}, Cheat_LevelSelect },
|
|
#endif
|
|
{ {A_JOY5, A_JOY7, A_JOY5, A_JOY8, A_JOY5, A_JOY6}, Cheat_InfiniteForce },
|
|
{ {A_JOY8, A_JOY7, A_JOY6, A_JOY5, A_JOY7, A_JOY7}, Cheat_AllForce },
|
|
// { {A_JOY8, A_JOY7, A_JOY6, A_JOY5, A_JOY7, A_JOY8}, Cheat_KungFoo },
|
|
#if YELLOW_MODE
|
|
{ {A_JOY5, A_JOY7, A_JOY5, A_JOY8, A_JOY6, A_JOY5}, Cheat_Yellow_Stage1 },
|
|
{ {A_JOY5, A_JOY6, A_JOY8, A_JOY5, A_JOY7, A_JOY7}, Cheat_Yellow_Stage2 },
|
|
#endif // YELLOW_MODE
|
|
};
|
|
|
|
const int numCheats = sizeof(cheats) / sizeof(cheats[0]);
|
|
|
|
bool enteringCheat = false;
|
|
int cheatLength = 0;
|
|
fakeAscii_t curCheat[6];
|
|
|
|
|
|
//If the Xbox white or black button was held for less than this amount of
|
|
//time while a selection bar was up, the user wants to use the button rather
|
|
//than reassign it.
|
|
#define MAX_WB_HOLD_TIME 500
|
|
|
|
static fakeAscii_t UIJoy2Key(fakeAscii_t button)
|
|
{
|
|
switch(button) {
|
|
// D-Pad
|
|
case A_JOY7:
|
|
return A_CURSOR_DOWN;
|
|
case A_JOY5:
|
|
return A_CURSOR_UP;
|
|
case A_JOY6:
|
|
return A_CURSOR_RIGHT;
|
|
case A_JOY8:
|
|
return A_CURSOR_LEFT;
|
|
|
|
// A and B
|
|
case A_JOY15:
|
|
return A_MOUSE1;
|
|
case A_JOY14:
|
|
return A_ESCAPE;
|
|
|
|
// X and Y
|
|
case A_JOY16:
|
|
return A_DELETE;
|
|
case A_JOY13:
|
|
return A_BACKSPACE;
|
|
|
|
// L and R triggers
|
|
case A_JOY11:
|
|
return A_PAGE_UP;
|
|
case A_JOY12:
|
|
return A_PAGE_DOWN;
|
|
|
|
// Start and Back
|
|
case A_JOY4:
|
|
return A_MOUSE1;
|
|
case A_JOY1:
|
|
return A_ESCAPE;
|
|
|
|
// White and Black
|
|
case A_JOY9:
|
|
return A_HOME;
|
|
case A_JOY10:
|
|
return A_END;
|
|
|
|
// Left and Right thumbstick - do nothing in the UI
|
|
case A_JOY2:
|
|
return A_SPACE;
|
|
case A_JOY3:
|
|
return A_SPACE;
|
|
}
|
|
|
|
return A_SPACE; //Invalid button.
|
|
}
|
|
|
|
struct
|
|
{
|
|
int button;
|
|
bool pressed;
|
|
} uiKeyQueue[2][5] = {0};
|
|
int uiQueueLen[2] = {0};
|
|
int uiLastKeyUpDown[2] = {0};
|
|
int uiLastKeyLeftRight[2] = {0};
|
|
|
|
void IN_UIEmptyQueue()
|
|
{
|
|
/// If the ui is not running then this doesn't have any effect
|
|
if (!_UIRunning)
|
|
{
|
|
uiQueueLen[0] = uiQueueLen[1] = 0;
|
|
return;
|
|
}
|
|
|
|
// BTO - No CM, bypass that logic.
|
|
// for (int i = 0; i < ClientManager::NumClients(); i++)
|
|
for (int i = 0; i < 1; ++i)
|
|
{
|
|
// ClientManager::ActivateClient(i);
|
|
int found = 0;
|
|
int bCancel = 0;
|
|
for (int j = 0; j < uiQueueLen[i]; j++)
|
|
{
|
|
switch (uiKeyQueue[i][j].button)
|
|
{
|
|
case A_CURSOR_DOWN:
|
|
case A_CURSOR_UP:
|
|
if ( found & 2 ) // Was a left/right key pressed already?
|
|
bCancel = 1;
|
|
found |= 1;
|
|
break;
|
|
case A_CURSOR_RIGHT:
|
|
case A_CURSOR_LEFT:
|
|
if ( found & 1 ) // Was an up/down key already pressed?
|
|
bCancel = 1;
|
|
found |= 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bCancel) // was it cancelled?
|
|
{
|
|
for (int j = 0; j < uiQueueLen[i]; j++)
|
|
{
|
|
int time = Sys_Milliseconds();
|
|
switch (uiKeyQueue[i][j].button)
|
|
{
|
|
case A_CURSOR_DOWN:
|
|
case A_CURSOR_UP:
|
|
if (uiLastKeyLeftRight[i])
|
|
{
|
|
if (uiLastKeyLeftRight[i] > time) // don't allow up/down till left/right has enough leway time
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
uiLastKeyUpDown[i] = time + 150; /// 250 ms sound right?
|
|
break;
|
|
case A_CURSOR_LEFT:
|
|
case A_CURSOR_RIGHT:
|
|
if (uiLastKeyUpDown[i])
|
|
{
|
|
if (uiLastKeyUpDown[i] > time) // don't allow up/down till left/right has enough leway time
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
uiLastKeyLeftRight[i] = time + 150; /// 250 ms sound right?
|
|
break;
|
|
}
|
|
Sys_QueEvent(0, SE_KEY, uiKeyQueue[i][j].button, uiKeyQueue[i][j].pressed, 0, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset the queue
|
|
uiQueueLen[0] = uiQueueLen[1] = 0;
|
|
}
|
|
|
|
// extern void G_DemoKeypress();
|
|
// extern void CG_SkipCredits(void);
|
|
char lastControllerUsed = 0;
|
|
|
|
void IN_CommonJoyPress(int controller, fakeAscii_t button, bool pressed)
|
|
{
|
|
#ifdef XBOX_DEMO
|
|
// Reset the demo timer so that we don't auto-reboot to CDX
|
|
extern void Demo_TimerKeypress( void );
|
|
Demo_TimerKeypress();
|
|
#endif
|
|
|
|
lastControllerUsed = controller;
|
|
|
|
// Cheat system hooks. The right thumbstick button has to be held for a cheat:
|
|
if (button == A_JOY3)
|
|
{
|
|
if (pressed)
|
|
{
|
|
// Just pressed the right thumstick in. Reset cheat detector
|
|
enteringCheat = true;
|
|
cheatLength = 0;
|
|
}
|
|
else
|
|
{
|
|
enteringCheat = false;
|
|
if (cheatLength == 6)
|
|
{
|
|
for( int i = 0; i < numCheats; ++i)
|
|
{
|
|
if( memcmp( &cheats[i].buttons[0], &curCheat[0], sizeof(curCheat) ) == 0 )
|
|
{
|
|
if(cheats[i].function())
|
|
S_StartLocalSound( S_RegisterSound( "sound/vehicles/x-wing/s-foil" ), CHAN_AUTO );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (enteringCheat && pressed)
|
|
{
|
|
// Handle all other buttons while entering a cheat
|
|
if (cheatLength == 6 || (button != A_JOY5 && button != A_JOY6 && button != A_JOY7 && button != A_JOY8))
|
|
{
|
|
// If we press too many buttons, or anything but the D-pad, cancel entry:
|
|
enteringCheat = false;
|
|
cheatLength = 0;
|
|
}
|
|
else
|
|
{
|
|
// We pressed a d-pad button, we're entering a cheat, and there's still room
|
|
curCheat[cheatLength++] = button;
|
|
}
|
|
}
|
|
|
|
// Check for special cases for map hack
|
|
#ifndef FINAL_BUILD
|
|
if (Cvar_VariableIntegerValue("cl_maphack"))
|
|
{
|
|
if (_UIRunning && button == A_JOY11 && pressed)
|
|
{
|
|
// Left trigger -> F1
|
|
Sys_QueEvent( 0, SE_KEY, A_F1, pressed, 0, NULL );
|
|
return;
|
|
}
|
|
else if (_UIRunning && button == A_JOY12 && pressed)
|
|
{
|
|
// Right trigger -> F2
|
|
Sys_QueEvent( 0, SE_KEY, A_F2, pressed, 0, NULL );
|
|
return;
|
|
}
|
|
else if (_UIRunning && button == A_JOY4 && pressed)
|
|
{
|
|
// Start button -> F3
|
|
//IN_SetMainController(controller);
|
|
Sys_QueEvent( 0, SE_KEY, A_F3, pressed, 0, NULL );
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(inSplashMenu->integer)
|
|
{
|
|
// START always works, A only works if the popup isn't shown:
|
|
if(button == A_JOY4 || (button == A_JOY15 && controllerOut->integer < 0))
|
|
{
|
|
Sys_QueEvent( 0, SE_KEY, _UIRunning ? UIJoy2Key(button) : button, pressed, 0, NULL );
|
|
}
|
|
return;
|
|
}
|
|
|
|
int controllerout = controllerOut->integer;
|
|
if(controllerout != -1)
|
|
{
|
|
if(controllerout == controller && (button == A_JOY4))// || button == A_JOY15))
|
|
Sys_QueEvent( 0, SE_KEY, _UIRunning ? UIJoy2Key(button) : button, pressed, 0, NULL );
|
|
return;
|
|
}
|
|
|
|
if(IN_GetMainController() == controller )
|
|
{
|
|
// Always map start button to ESCAPE
|
|
if (!_UIRunning && button == A_JOY4 && cls.state != CA_CINEMATIC)
|
|
Sys_QueEvent( 0, SE_KEY, A_ESCAPE, pressed, 0, NULL );
|
|
|
|
#ifdef DEBUG_CONTROLLER
|
|
if (controller != 3)
|
|
#endif
|
|
Sys_QueEvent( 0, SE_KEY, _UIRunning ? UIJoy2Key(button) : button, pressed, 0, NULL );
|
|
}
|
|
|
|
#ifdef DEBUG_CONTROLLER
|
|
if (controller == 3 && pressed)
|
|
{
|
|
HandleDebugJoystickPress(button);
|
|
return;
|
|
}
|
|
#endif
|
|
//JLF
|
|
|
|
}
|
|
|
|
qboolean g_noCheckAxis = qfalse;
|
|
|
|
/**********
|
|
IN_CommonUpdate
|
|
Updates thumbstick events based on _padInfo and ui_thumbStickMode
|
|
**********/
|
|
void IN_CommonUpdate()
|
|
{
|
|
extern int Key_GetCatcher( void );
|
|
_UIRunning = Key_GetCatcher() == KEYCATCH_UI;
|
|
|
|
// Even in the UI, only the main controller should be able to scroll:
|
|
if( _UIRunning && _padInfo.padId == IN_GetMainController() )
|
|
{
|
|
Sys_QueEvent( 0,
|
|
SE_MOUSE,
|
|
(_padInfo.joyInfo[0].x + _padInfo.joyInfo[1].x) * 4.0f,
|
|
(_padInfo.joyInfo[0].y + _padInfo.joyInfo[1].y) * -4.0f,
|
|
0,
|
|
NULL );
|
|
}
|
|
else if(_padInfo.padId == IN_GetMainController())
|
|
{
|
|
// Find out how to configure the thumbsticks
|
|
//int thumbStickMode = Cvar_Get("ui_thumbStickMode", "0" , 0)->integer;
|
|
int thumbStickMode = cl_thumbStickMode->integer;
|
|
|
|
switch(thumbStickMode)
|
|
{
|
|
case 0:
|
|
// Configure left thumbstick to move forward/back & strafe left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_SIDE, _padInfo.joyInfo[0].x * 127.0f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_FORWARD, _padInfo.joyInfo[0].y * 127.0f, 0, NULL );
|
|
|
|
// Configure right thumbstick for freelook
|
|
Sys_QueEvent( 0, SE_MOUSE, _padInfo.joyInfo[1].x * 48.0f, _padInfo.joyInfo[1].y * 48.0f, 0, NULL );
|
|
break;
|
|
case 1:
|
|
// Configure left thumbstick for freelook
|
|
Sys_QueEvent( 0, SE_MOUSE, _padInfo.joyInfo[0].x * 48.0f, _padInfo.joyInfo[0].y * 48.0f, 0, NULL );
|
|
|
|
// Configure right thumbstick to move forward/back & strafe left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_SIDE, _padInfo.joyInfo[1].x * 127.0f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_FORWARD, _padInfo.joyInfo[1].y * 127.0f, 0, NULL );
|
|
break;
|
|
case 2:
|
|
// Configure left thumbstick to move forward/back & turn left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_FORWARD, _padInfo.joyInfo[0].y * 127.0f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_MOUSE, _padInfo.joyInfo[0].x * 48.0f, 0.0f, 0, NULL );
|
|
|
|
// Configure right thumbstick to look up/down & strafe left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_SIDE, _padInfo.joyInfo[1].x * 127.f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_MOUSE, 0.0f, _padInfo.joyInfo[1].y * 48.0f, 0, NULL );
|
|
break;
|
|
case 3:
|
|
// Configure left thumbstick to look up/down & strafe left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_SIDE, _padInfo.joyInfo[0].x * 127.f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_MOUSE, 0.0f, _padInfo.joyInfo[0].y * 48.0f, 0, NULL );
|
|
|
|
// Configure right thumbstick to move forward/back & turn left/right
|
|
Sys_QueEvent( 0, SE_JOYSTICK_AXIS, AXIS_FORWARD, _padInfo.joyInfo[1].y * 127.0f, 0, NULL );
|
|
Sys_QueEvent( 0, SE_MOUSE, _padInfo.joyInfo[1].x * 48.0f, 0.0f, 0, NULL );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void startsetMainController(int controller)
|
|
{
|
|
|
|
IN_SetMainController(controller);
|
|
if ( !wasPlugged[controller])
|
|
{
|
|
mainControllerDelayedUnplug = 1 << controller;
|
|
}
|
|
}
|
|
|
|
/*********
|
|
IN_DisplayControllerUnplugged
|
|
*********/
|
|
|
|
static void IN_DisplayControllerUnplugged(int controller)
|
|
{
|
|
uiControllerNotification = controller;
|
|
|
|
bool noControllersConnected = !wasPlugged[0] &&
|
|
!wasPlugged[1] &&
|
|
!wasPlugged[2] &&
|
|
!wasPlugged[3];
|
|
|
|
if ( !( cls.keyCatchers & KEYCATCH_UI ) )
|
|
{
|
|
if ( cls.state == CA_ACTIVE )
|
|
{
|
|
if (controller == IN_GetMainController())
|
|
{
|
|
Cvar_SetValue("ControllerOutNum", controller);
|
|
UI_SetActiveMenu( "ingame","noController" );
|
|
}
|
|
}
|
|
}
|
|
else // UI
|
|
{
|
|
if(inSplashMenu->integer && noControllersConnected)
|
|
{
|
|
Cvar_SetValue("ControllerOutNum", 4);
|
|
UI_SetActiveMenu("ui_popup", "noController");
|
|
}
|
|
else if( controller == IN_GetMainController())
|
|
{
|
|
Cvar_SetValue("ControllerOutNum", controller);
|
|
UI_SetActiveMenu("ui_popup", "noController");
|
|
}
|
|
}
|
|
// END JLF
|
|
|
|
}
|
|
|
|
/*********
|
|
IN_ClearControllerUnplugged
|
|
*********/
|
|
static void IN_ClearControllerUnplugged(void)
|
|
{
|
|
uiControllerNotification = -1;
|
|
|
|
//TODO Add a call to the UI that removes the controller disconnected
|
|
// message from the screen.
|
|
// VM_Call( uivm, UI_CONTROLLER_UNPLUGGED, false, 0);
|
|
}
|
|
|
|
qboolean CurrentStateIsInteractive()
|
|
{
|
|
if (cls.state == CA_UNINITIALIZED ||
|
|
cls.state ==CA_CONNECTING||
|
|
cls.state ==CA_CONNECTED||
|
|
cls.state ==CA_CHALLENGING||
|
|
cls.state ==CA_PRIMED||
|
|
cls.state ==CA_CINEMATIC ||
|
|
!SG_GameAllowedToSaveHere(qtrue))
|
|
return qfalse;
|
|
return qtrue;
|
|
}
|
|
|
|
// Magic flag used to avoid popping up the "no controllers" dialog if
|
|
// none were present when we booted (but not from MP)
|
|
bool hadAController = false;
|
|
|
|
/*********
|
|
IN_ControllerMustBePlugged
|
|
*********/
|
|
static bool IN_ControllerMustBePlugged(int controller)
|
|
{
|
|
if( cls.state == CA_LOADING ||
|
|
cls.state == CA_CONNECTING ||
|
|
cls.state == CA_CONNECTED ||
|
|
cls.state == CA_CHALLENGING ||
|
|
cls.state == CA_PRIMED ||
|
|
cls.state == CA_CINEMATIC)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// If we're at the splash screen, have no controllers anymore, and there
|
|
// was a controller ever inserted into the machine:
|
|
extern bool Sys_QuickStart();
|
|
if( inSplashMenu->integer &&
|
|
!wasPlugged[0] && !wasPlugged[1] &&
|
|
!wasPlugged[2] && !wasPlugged[3] &&
|
|
hadAController )
|
|
return true;
|
|
|
|
// If we're at the splash screen, and anything else above is false
|
|
// (we have another controller, or there's never been a controller):
|
|
if( inSplashMenu->integer )
|
|
return false;
|
|
|
|
// OK. In all other cases, we need the main controller:
|
|
return (controller == IN_GetMainController());
|
|
}
|
|
|
|
|
|
/*********
|
|
IN_PadUnplugged
|
|
*********/
|
|
void IN_PadUnplugged(int controller)
|
|
{
|
|
if(wasPlugged[controller])
|
|
{
|
|
Com_Printf("\tController %d unplugged\n",controller);
|
|
}
|
|
//JLF moved
|
|
wasPlugged[controller] = false;
|
|
|
|
//IN_CheckForNoControllers();
|
|
|
|
if(IN_ControllerMustBePlugged(controller)&& SG_GameAllowedToSaveHere(qtrue))
|
|
{
|
|
//If UI isn't busy, inform it about controller loss.
|
|
if(uiControllerNotification == -1 && Cvar_VariableIntegerValue("ControllerOutNum")<0)
|
|
{
|
|
IN_DisplayControllerUnplugged(controller);
|
|
mainControllerDelayedUnplug &= ~( 1<< controller);
|
|
}
|
|
// else
|
|
// mainControllerDelayedUnplug = 1 << controller;
|
|
|
|
}
|
|
else
|
|
{
|
|
if ( controller == IN_GetMainController())
|
|
{
|
|
//store somehow for checking again later
|
|
mainControllerDelayedUnplug = 1 << controller;
|
|
}
|
|
}
|
|
// wasPlugged[controller] = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
/*********
|
|
IN_PadPlugged
|
|
*********/
|
|
void IN_PadPlugged(int controller)
|
|
{
|
|
if(!wasPlugged[controller])
|
|
{
|
|
Com_Printf("\tController %d plugged\n",controller);
|
|
}
|
|
|
|
if(IN_ControllerMustBePlugged(controller)&& SG_GameAllowedToSaveHere(qtrue))
|
|
{
|
|
//If UI is dealing with this controller, tell it to stop.
|
|
if(uiControllerNotification == controller || (_UIRunning && cls.state != CA_ACTIVE ))
|
|
{
|
|
IN_ClearControllerUnplugged();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (controller == IN_GetMainController())
|
|
{
|
|
//store somehow for checking again later
|
|
mainControllerDelayedUnplug &= ~(1 << controller);
|
|
}
|
|
}
|
|
|
|
wasPlugged[controller] = true;
|
|
noControllersConnected = false;
|
|
hadAController = true;
|
|
}
|
|
|
|
/*********
|
|
IN_GetMainController
|
|
*********/
|
|
int IN_GetMainController(void)
|
|
{
|
|
return cls.mainGamepad;
|
|
}
|
|
|
|
/*********
|
|
IN_SetMainController
|
|
*********/
|
|
void IN_SetMainController(int id)
|
|
{
|
|
cls.mainGamepad = id;
|
|
}
|
|
|
|
/**********************************************************
|
|
*
|
|
* DEBUGGING CODE
|
|
*
|
|
**********************************************************/
|
|
|
|
#ifdef DEBUG_CONTROLLER
|
|
static void HandleDebugJoystickPress(fakeAscii_t button)
|
|
{
|
|
switch(button) {
|
|
case A_JOY13: // Right pad up (yellow)
|
|
Cbuf_ExecuteText(EXEC_APPEND, "give all\n");
|
|
break;
|
|
case A_JOY16: // Right pad left (blue)
|
|
Cbuf_ExecuteText(EXEC_APPEND, "viewpos\n");
|
|
break;
|
|
case A_JOY14: // Right pad right (red)
|
|
Cbuf_ExecuteText(EXEC_APPEND, "noclip\n");
|
|
break;
|
|
case A_JOY15: // Right pad down (green)
|
|
Cbuf_ExecuteText(EXEC_APPEND, "god\n");
|
|
break;
|
|
case A_JOY4: // Start
|
|
break;
|
|
case A_JOY1: // back
|
|
break;
|
|
case A_JOY2: // Left thumbstick
|
|
extern void Z_CompactStats(void);
|
|
Z_CompactStats();
|
|
break;
|
|
case A_JOY12: // Upper right trigger
|
|
break;
|
|
case A_JOY8: // Left pad left
|
|
break;
|
|
case A_JOY6: // Left pad right
|
|
break;
|
|
case A_JOY5: // Left pad up
|
|
break;
|
|
case A_JOY7: // Left pad down
|
|
break;
|
|
case A_JOY11: // Upper left trigger
|
|
break;
|
|
case A_JOY9: // White button
|
|
break;
|
|
case A_JOY10: // Black button
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|