diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 7d8cb9ddd..cd404a685 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1922,6 +1922,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (*oldtic != I_GetTime()) { I_OsPolling(); + + memset(deviceResponding, false, sizeof (deviceResponding)); for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) G_MapEventsToControls(&events[eventtail]); @@ -1937,6 +1939,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic CL_Reset(); D_StartTitle(); memset(gamekeydown, 0, sizeof (gamekeydown)); + memset(deviceResponding, false, sizeof (deviceResponding)); return false; } diff --git a/src/d_main.c b/src/d_main.c index 54d62fbbe..9bb6c678d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -183,6 +183,7 @@ void D_ProcessEvents(void) boolean eaten; + memset(deviceResponding, false, sizeof (deviceResponding)); for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) { ev = &events[eventtail]; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 80493d7f3..0f91028ff 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -231,7 +231,7 @@ static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"}, {4, "/dev/js3"}, {0, NULL}}; #else // accept whatever value - it is in fact the joystick device number -#define usejoystick_cons_t NULL +static CV_PossibleValue_t usejoystick_cons_t[] = {{-1, "MIN"}, {MAXGAMEPADS, "MAX"}, {0, NULL}}; #endif static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; @@ -308,10 +308,10 @@ INT32 cv_debug; consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse); consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1), - CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2), - CVAR_INIT ("use_joystick3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3), - CVAR_INIT ("use_joystick4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4) + CVAR_INIT ("use_device", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1), + CVAR_INIT ("use_device2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2), + CVAR_INIT ("use_device3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3), + CVAR_INIT ("use_device4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4) }; #if (defined (LJOYSTICK) || defined (HAVE_SDL)) diff --git a/src/doomdef.h b/src/doomdef.h index ff6d2c1e5..c5ef7839f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -204,6 +204,7 @@ extern char logfilename[1024]; #define PLAYERSMASK (MAXPLAYERS-1) #define MAXPLAYERNAME 21 #define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer +#define MAXGAMEPADS (MAXSPLITSCREENPLAYERS * 2) // Number of gamepads we'll be allowing #define MAXSKINS 128 diff --git a/src/g_game.c b/src/g_game.c index 13751b2d3..4e3030fb4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1146,6 +1146,7 @@ void G_DoLoadLevel(boolean resetplayer) // clear cmd building stuff memset(gamekeydown, 0, sizeof (gamekeydown)); + memset(deviceResponding, false, sizeof (deviceResponding)); // clear hud messages remains (usually from game startup) CON_ClearHUD(); diff --git a/src/g_input.c b/src/g_input.c index 9ecb24e38..5b4fe8675 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -34,6 +34,7 @@ consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecont // current state of the keys // FRACUNIT for fully pressed, 0 for not pressed INT32 gamekeydown[MAXSPLITSCREENPLAYERS][NUMINPUTS]; +boolean deviceResponding[MAXDEVICES]; // two key codes (or virtual key) per game control INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][MAXINPUTMAPPING]; @@ -76,13 +77,44 @@ const INT32 gcl_full[num_gcl_full] = { void G_MapEventsToControls(event_t *ev) { INT32 i; + INT32 devicePlayer = INT32_MAX; + + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + if (ev->device == cv_usejoystick[i].value) + { + devicePlayer = i; + break; + } + } + + if (ev->device >= 0 && ev->device <= MAXGAMEPADS) + { + switch (ev->type) + { + case ev_keydown: + //case ev_keyup: + //case ev_mouse: + //case ev_joystick: + deviceResponding[ev->device] = true; + break; + + default: + break; + } + } + + if (devicePlayer == INT32_MAX) + { + return; + } switch (ev->type) { case ev_keydown: if (ev->data1 < NUMINPUTS) { - gamekeydown[ev->device][ev->data1] = FRACUNIT; + gamekeydown[devicePlayer][ev->data1] = FRACUNIT; } #ifdef PARANOIA else @@ -95,7 +127,7 @@ void G_MapEventsToControls(event_t *ev) case ev_keyup: if (ev->data1 < NUMINPUTS) { - gamekeydown[ev->device][ev->data1] = 0; + gamekeydown[devicePlayer][ev->data1] = 0; } #ifdef PARANOIA else @@ -115,28 +147,28 @@ void G_MapEventsToControls(event_t *ev) if (ev->data2 < 0) { // Left - gamekeydown[ev->device][KEY_MOUSEMOVE + 2] = abs(ev->data2); - gamekeydown[ev->device][KEY_MOUSEMOVE + 3] = 0; + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 2] = abs(ev->data2); + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 3] = 0; } else { // Right - gamekeydown[ev->device][KEY_MOUSEMOVE + 2] = 0; - gamekeydown[ev->device][KEY_MOUSEMOVE + 3] = abs(ev->data2); + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 2] = 0; + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 3] = abs(ev->data2); } // Y axis if (ev->data3 < 0) { // Up - gamekeydown[ev->device][KEY_MOUSEMOVE] = abs(ev->data3); - gamekeydown[ev->device][KEY_MOUSEMOVE + 1] = 0; + gamekeydown[devicePlayer][KEY_MOUSEMOVE] = abs(ev->data3); + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 1] = 0; } else { // Down - gamekeydown[ev->device][KEY_MOUSEMOVE] = 0; - gamekeydown[ev->device][KEY_MOUSEMOVE + 1] = abs(ev->data3); + gamekeydown[devicePlayer][KEY_MOUSEMOVE] = 0; + gamekeydown[devicePlayer][KEY_MOUSEMOVE + 1] = abs(ev->data3); } break; @@ -168,14 +200,14 @@ void G_MapEventsToControls(event_t *ev) if (ev->data2 < 0) { // Left - gamekeydown[ev->device][KEY_AXIS1 + i] = abs(ev->data2); - gamekeydown[ev->device][KEY_AXIS1 + i + 1] = 0; + gamekeydown[devicePlayer][KEY_AXIS1 + i] = abs(ev->data2); + gamekeydown[devicePlayer][KEY_AXIS1 + i + 1] = 0; } else { // Right - gamekeydown[ev->device][KEY_AXIS1 + i] = 0; - gamekeydown[ev->device][KEY_AXIS1 + i + 1] = abs(ev->data2); + gamekeydown[devicePlayer][KEY_AXIS1 + i] = 0; + gamekeydown[devicePlayer][KEY_AXIS1 + i + 1] = abs(ev->data2); } } @@ -185,14 +217,14 @@ void G_MapEventsToControls(event_t *ev) if (ev->data3 < 0) { // Up - gamekeydown[ev->device][KEY_AXIS1 + i + 2] = abs(ev->data3); - gamekeydown[ev->device][KEY_AXIS1 + i + 3] = 0; + gamekeydown[devicePlayer][KEY_AXIS1 + i + 2] = abs(ev->data3); + gamekeydown[devicePlayer][KEY_AXIS1 + i + 3] = 0; } else { // Down - gamekeydown[ev->device][KEY_AXIS1 + i + 2] = 0; - gamekeydown[ev->device][KEY_AXIS1 + i + 3] = abs(ev->data3); + gamekeydown[devicePlayer][KEY_AXIS1 + i + 2] = 0; + gamekeydown[devicePlayer][KEY_AXIS1 + i + 3] = abs(ev->data3); } } diff --git a/src/g_input.h b/src/g_input.h index 3542d9ede..8a41267c5 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -86,6 +86,9 @@ extern consvar_t cv_controlperkey; // Or anything inbetween for analog values extern INT32 gamekeydown[MAXSPLITSCREENPLAYERS][NUMINPUTS]; +#define MAXDEVICES (MAXGAMEPADS + 1) // Gamepads + keyboard & mouse +extern boolean deviceResponding[MAXDEVICES]; + // several key codes (or virtual key) per game control extern INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][MAXINPUTMAPPING]; extern INT32 gamecontroldefault[num_gamecontrols][MAXINPUTMAPPING]; // default control storage diff --git a/src/k_menudraw.c b/src/k_menudraw.c index f529585d2..2f4a29d15 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -934,10 +934,15 @@ static void M_DrawCharSelectCursor(UINT8 num) void M_DrawCharacterSelect(void) { UINT8 i, j, k; - UINT8 priority = setup_animcounter % setup_numplayers; + UINT8 priority = 0; INT16 quadx, quady; SINT8 skin; + if (setup_numplayers > 0) + { + priority = setup_animcounter % setup_numplayers; + } + // We have to loop twice -- first time to draw the drop shadows, a second time to draw the icons. for (i = 0; i < 9; i++) { diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 360d2aadb..824c0050c 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -1871,8 +1871,8 @@ void M_CharacterSelectInit(INT32 choice) } memset(setup_player, 0, sizeof(setup_player)); - setup_player[0].mdepth = CSSTEP_CHARS; - setup_numplayers = 1; + //setup_player[0].mdepth = CSSTEP_CHARS; + setup_numplayers = 0; memset(setup_explosions, 0, sizeof(setup_explosions)); setup_animcounter = 0; @@ -1952,6 +1952,91 @@ static void M_SetupReadyExplosions(setup_player_t *p) } } +static boolean M_DeviceAvailable(UINT8 deviceID, UINT8 numPlayers) +{ + INT32 i; + + if (numPlayers == 0) + { + // All of them are available! + return true; + } + + for (i = 0; i < numPlayers; i++) + { + if (cv_usejoystick[i].value == deviceID) + { + // This one's already being used. + return false; + } + } + + // This device is good to go. + return true; +} + +static void M_HandlePressStart(setup_player_t *p, UINT8 num) +{ + INT32 i, j; + + // Detect B press first ... this means P1 can actually exit out of the menu. + if (menucmd[num].buttons & MBT_B) + { + M_SetMenuDelay(num); + + if (num == 0) + { + // We're done here. + M_GoBack(0); + return; + } + + // Don't allow this press to ever count as "start". + return; + } + + if (num != setup_numplayers) + { + // Only detect devices for the last player... + // just too complicated otherwise. + return; + } + + // Now detect new devices trying to join. + for (i = 0; i < MAXDEVICES; i++) + { + if (deviceResponding[i] == false) + { + // No buttons are being pushed. + continue; + } + + if (M_DeviceAvailable(i, setup_numplayers) == true) + { + // Available!! Let's use this one!! + cv_usejoystick[setup_numplayers].value = i; + + for (j = setup_numplayers+1; j < MAXSPLITSCREENPLAYERS; j++) + { + if (cv_usejoystick[j].value == i) + { + // Un-set devices for other players. + cv_usejoystick[j].value = -1; + } + } + + setup_numplayers++; + p->mdepth = CSSTEP_CHARS; + S_StartSound(NULL, sfx_s3k65); + + // Prevent excess presses + memset(deviceResponding, false, sizeof (deviceResponding)); + + M_SetMenuDelay(num); + } + } +} + static void M_HandleCharacterGrid(setup_player_t *p, UINT8 num) { if (menucmd[num].dpad_ud > 0) @@ -2117,13 +2202,7 @@ boolean M_CharacterSelectHandler(INT32 choice) switch (p->mdepth) { case CSSTEP_NONE: // Enter Game - if (i == setup_numplayers) - { - //I_DetectNewControllers(); // Look through all joysticks to see if any have pressed start. - - p->mdepth = CSSTEP_CHARS; - S_StartSound(NULL, sfx_s3k65); - } + M_HandlePressStart(p, i); break; case CSSTEP_CHARS: // Character Select grid M_HandleCharacterGrid(p, i); @@ -2162,15 +2241,6 @@ boolean M_CharacterSelectHandler(INT32 choice) setup_numplayers = i+1; } - // If the first player unjoins, then we get outta here - if (setup_player[0].mdepth == CSSTEP_NONE) - { - if (currentMenu->prevMenu) - M_SetupNextMenu(currentMenu->prevMenu, false); - else - M_ClearMenus(true); - } - return true; } @@ -2249,7 +2319,7 @@ void M_CharacterSelectTick(void) setup_explosions[i].tics--; } - if (setupnext) + if (setupnext && setup_numplayers > 0) { // Selecting from the menu diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index a856c6f84..8c80b9d24 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -197,6 +197,48 @@ static char returnWadPath[256]; #include "../byteptr.h" #endif +void I_StoreExJoystick(SDL_Joystick *dev) +{ + // ExJoystick is a massive hack to avoid needing to completely + // rewrite pretty much all of the controller support from scratch... + + // Used in favor of most instances of SDL_JoystickClose. + // If a joystick would've been discarded, then save it in an array, + // because we want it have it for the joystick input screen. + + int index = 0; + + if (dev == NULL) + { + // No joystick? + return; + } + + index = SDL_JoystickInstanceID(dev); + + if (index >= MAXGAMEPADS || index < 0) + { + // Not enough space to save this joystick, completely discard. + SDL_JoystickClose(dev); + return; + } + + if (ExJoystick[index] == dev) + { + // No need to do anything else. + return; + } + + if (ExJoystick[index] != NULL) + { + // Discard joystick in the old slot. + SDL_JoystickClose(ExJoystick[index]); + } + + // Keep for safe-keeping. + ExJoystick[index] = dev; +} + /** \brief The JoyReset function \param JoySet Joystick info to reset @@ -207,7 +249,7 @@ static void JoyReset(SDLJoyInfo_t *JoySet) { if (JoySet->dev) { - SDL_JoystickClose(JoySet->dev); + I_StoreExJoystick(JoySet->dev); } JoySet->dev = NULL; JoySet->oldjoy = -1; @@ -222,6 +264,7 @@ static INT32 joystick_started[MAXSPLITSCREENPLAYERS] = {0,0,0,0}; /** \brief SDL info about joystick 1 */ SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS]; +SDL_Joystick *ExJoystick[MAXGAMEPADS]; SDL_bool consolevent = SDL_FALSE; SDL_bool framebuffer = SDL_FALSE; @@ -963,7 +1006,7 @@ INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev) } if (j == MAXSPLITSCREENPLAYERS) - SDL_JoystickClose(test); + I_StoreExJoystick(test); } } @@ -1373,7 +1416,7 @@ void I_InitJoystick(UINT8 index) if (i == MAXSPLITSCREENPLAYERS) { // Joystick didn't end up being used - SDL_JoystickClose(newjoy); + I_StoreExJoystick(newjoy); } } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index ad5b3723d..fec2bc306 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -619,6 +619,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) SDLforceUngrabMouse(); } memset(gamekeydown, 0, sizeof(gamekeydown)); // TODO this is a scary memset + memset(deviceResponding, false, sizeof (deviceResponding)); if (MOUSE_MENU) { @@ -632,7 +633,7 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) { event_t event; - event.device = 0; // TODO: properly set a device + event.device = 0; if (type == SDL_KEYUP) { @@ -715,7 +716,7 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) /// \todo inputEvent.button.which if (USE_MOUSEINPUT) { - event.device = 0; // TODO: properly set a device + event.device = 0; if (type == SDL_MOUSEBUTTONUP) { @@ -749,7 +750,7 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt) SDL_memset(&event, 0, sizeof(event_t)); - event.device = 0; // TODO: properly set a device + event.device = 0; if (evt.y > 0) { @@ -775,23 +776,9 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt) static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt) { event_t event; - SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS]; - UINT8 i; - event.device = INT32_MAX; event.data1 = event.data2 = event.data3 = INT32_MAX; - - // Determine the Joystick IDs for each current open joystick - for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) - { - joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev); - - if (evt.which == joyid[i]) - { - event.device = i; - } - } - + event.device = 1 + evt.which; evt.axis++; if (event.device == INT32_MAX) @@ -826,20 +813,8 @@ static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt) { event_t event; SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS]; - UINT8 i; - event.device = INT32_MAX; - - // Determine the Joystick IDs for each current open joystick - for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) - { - joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev); - - if (evt.which == joyid[i]) - { - event.device = i; - } - } + event.device = 1 + evt.which; if (event.device == INT32_MAX) { @@ -860,21 +835,8 @@ static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt) static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type) { event_t event; - SDL_JoystickID joyid[MAXSPLITSCREENPLAYERS]; - UINT8 i; - event.device = INT32_MAX; - - // Determine the Joystick IDs for each current open joystick - for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) - { - joyid[i] = SDL_JoystickInstanceID(JoyInfo[i].dev); - - if (evt.which == joyid[i]) - { - event.device = i; - } - } + event.device = 1 + evt.which; if (event.device == INT32_MAX) { @@ -913,8 +875,6 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type) } } - - void I_GetEvent(void) { SDL_Event evt; @@ -1054,7 +1014,7 @@ void I_GetEvent(void) } if (i == MAXSPLITSCREENPLAYERS) - SDL_JoystickClose(newjoy); + I_StoreExJoystick(newjoy); } break; diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index 39c099a2b..391614bcd 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -61,6 +61,9 @@ typedef struct SDLJoyInfo_s /** \brief SDL info about joysticks */ extern SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS]; +extern SDL_Joystick *ExJoystick[MAXGAMEPADS]; + +void I_StoreExJoystick(SDL_Joystick *dev); /** \brief joystick axis deadzone */