Merge branch 'next' into font_drawer

This commit is contained in:
spherallic 2023-03-05 22:27:22 +01:00
commit 8228275cf8
56 changed files with 3184 additions and 4250 deletions

View file

@ -265,14 +265,8 @@ universalfields
triggerer
{
type = 0;
default = 0;
enum
{
0 = "Player";
1 = "All players";
2 = "Object";
}
type = 2;
default = "Player";
}
}

View file

@ -4546,7 +4546,7 @@ udmf
sprite = "EMBMA0";
width = 16;
height = 30;
arg0
arg1
{
title = "Float?";
type = 11;

View file

@ -127,7 +127,9 @@ endif()
# Compatibility flag with later versions of GCC
# We should really fix our code to not need this
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64|em64t|EM64T)")
target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
endif()
endif()
# Compiler warnings configuration

View file

@ -51,7 +51,6 @@ p_spec.c
p_telept.c
p_tick.c
p_user.c
p_haptic.c
p_slopes.c
tables.c
r_bsp.c

View file

@ -77,6 +77,7 @@ CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
// Filter consvars by EXECVERSION
// First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20)
// Also set CV_HIDEN during runtime, after config is loaded
static boolean execversion_enabled = false;
consvar_t cv_execversion = CVAR_INIT ("execversion","25",CV_CALL,CV_Unsigned, CV_EnforceExecVersion);
@ -2181,48 +2182,131 @@ static void CV_EnforceExecVersion(void)
CV_StealthSetValue(&cv_execversion, EXECVERSION);
}
#ifndef OLD_GAMEPAD_AXES
static boolean CV_ConvertOldJoyAxisVars(consvar_t *v, const char *valstr)
static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
{
static struct {
const char *old;
const char *new;
} axis_names[] = {
{"X-Axis", "Left Stick X"},
{"Y-Axis", "Left Stick Y"},
{"X-Axis-", "Left Stick X-"},
{"Y-Axis-", "Left Stick Y-"},
{"X-Rudder", "Right Stick X"},
{"Y-Rudder", "Right Stick Y"},
{"X-Rudder-", "Right Stick X-"},
{"Y-Rudder-", "Right Stick Y-"},
{"Z-Axis", "Left Trigger"},
{"Z-Rudder", "Right Trigger"},
{"Z-Axis-", "Left Trigger"},
{"Z-Rudder-", "Right Trigger"},
{NULL, NULL}
};
// If ALL axis settings are previous defaults, set them to the new defaults
// EXECVERSION < 26 (2.1.21)
if (v->PossibleValue != joyaxis_cons_t)
return true;
for (unsigned i = 0;; i++)
if (joyaxis_default)
{
if (axis_names[i].old == NULL)
if (!stricmp(v->name, "joyaxis_turn"))
{
CV_SetCVar(v, "None", false);
return false;
if (joyaxis_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
else if (!stricmp(valstr, axis_names[i].old))
if (!stricmp(v->name, "joyaxis_move"))
{
CV_SetCVar(v, axis_names[i].new, false);
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
if (!stricmp(v->name, "joyaxis_side"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis_count++;
else joyaxis_default = false;
}
if (!stricmp(v->name, "joyaxis_look"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
if (!stricmp(v->name, "joyaxis_fire")
|| !stricmp(v->name, "joyaxis_firenormal"))
{
if (joyaxis_count > 6) return false;
else if (joyaxis_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false;
}
// reset all axis settings to defaults
if (joyaxis_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis.name, cv_turnaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis.name, cv_moveaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis.name, cv_sideaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis.name, cv_lookaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis.name, cv_fireaxis.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis.name, cv_firenaxis.defaultvalue));
joyaxis_count++;
return false;
}
}
if (joyaxis2_default)
{
if (!stricmp(v->name, "joyaxis2_turn"))
{
if (joyaxis2_count > 6) return false;
// we're currently setting the new defaults, don't interfere
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "X-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
if (!stricmp(v->name, "joyaxis2_move"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
if (!stricmp(v->name, "joyaxis2_side"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++;
else joyaxis2_default = false;
}
if (!stricmp(v->name, "joyaxis2_look"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
if (!stricmp(v->name, "joyaxis2_fire")
|| !stricmp(v->name, "joyaxis2_firenormal"))
{
if (joyaxis2_count > 6) return false;
else if (joyaxis2_count == 6) return true;
if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false;
}
// reset all axis settings to defaults
if (joyaxis2_count == 6)
{
COM_BufInsertText(va("%s \"%s\"\n", cv_turnaxis2.name, cv_turnaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_moveaxis2.name, cv_moveaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_sideaxis2.name, cv_sideaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_lookaxis2.name, cv_lookaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_fireaxis2.name, cv_fireaxis2.defaultvalue));
COM_BufInsertText(va("%s \"%s\"\n", cv_firenaxis2.name, cv_firenaxis2.defaultvalue));
joyaxis2_count++;
return false;
}
}
// we haven't reached our counts yet, or we're not default
return true;
}
#endif
static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
{
@ -2233,14 +2317,39 @@ static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr)
if (!(v->flags & CV_SAVE))
return true;
#ifndef OLD_GAMEPAD_AXES
if (GETMAJOREXECVERSION(cv_execversion.value) <= 51 && GETMINOREXECVERSION(cv_execversion.value) < 1)
if (GETMAJOREXECVERSION(cv_execversion.value) < 26) // 26 = 2.1.21
{
if (!CV_ConvertOldJoyAxisVars(v, valstr))
// MOUSE SETTINGS
// alwaysfreelook split between first and third person (chasefreelook)
// mousemove was on by default, which invalidates the current approach
if (!stricmp(v->name, "alwaysmlook")
|| !stricmp(v->name, "alwaysmlook2")
|| !stricmp(v->name, "mousemove")
|| !stricmp(v->name, "mousemove2"))
return false;
// mousesens was changed from 35 to 20 due to oversensitivity
if ((!stricmp(v->name, "mousesens")
|| !stricmp(v->name, "mousesens2")
|| !stricmp(v->name, "mouseysens")
|| !stricmp(v->name, "mouseysens2"))
&& atoi(valstr) == 35)
return false;
// JOYSTICK DEFAULTS
// use_joystick was changed from 0 to 1 to automatically use a joystick if available
#if defined(HAVE_SDL) || defined(_WINDOWS)
if ((!stricmp(v->name, "use_joystick")
|| !stricmp(v->name, "use_joystick2"))
&& atoi(valstr) == 0)
return false;
}
#endif
// axis defaults were changed to be friendly to 360 controllers
// if ALL axis settings are defaults, then change them to new values
if (!CV_FilterJoyAxisVars(v, valstr))
return false;
}
return true;
}

View file

@ -918,8 +918,7 @@ boolean CON_Responder(event_t *ev)
static INT32 alias_skips;
const char *cmd = NULL;
INT32 key = ev->key;
boolean key_is_console = (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]);
INT32 key;
if (chat_on)
return false;
@ -927,18 +926,20 @@ boolean CON_Responder(event_t *ev)
// let go keyup events, don't eat them
if (ev->type != ev_keydown && ev->type != ev_console)
{
if (key_is_console)
if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1])
consdown = false;
return false;
}
key = ev->key;
// check for console toggle key
if (ev->type != ev_console)
{
if (modeattacking || metalrecording || marathonmode)
return false;
if (key_is_console)
if (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1])
{
if (consdown) // ignore repeat
return true;

View file

@ -25,8 +25,7 @@
#include "st_stuff.h"
#include "hu_stuff.h"
#include "keys.h"
#include "g_input.h"
#include "i_gamepad.h"
#include "g_input.h" // JOY1
#include "m_menu.h"
#include "console.h"
#include "d_netfil.h"
@ -34,7 +33,6 @@
#include "p_saveg.h"
#include "z_zone.h"
#include "p_local.h"
#include "p_haptic.h"
#include "m_misc.h"
#include "am_map.h"
#include "m_random.h"
@ -51,7 +49,7 @@
#include "m_perfstats.h"
// aaaaaa
#include "i_gamepad.h"
#include "i_joy.h"
#ifndef NONET
// cl loading screen
@ -655,6 +653,22 @@ static UINT8 Snake_GetOppositeDir(UINT8 dir)
return 12 + 5 - dir;
}
event_t *snakejoyevents[MAXEVENTS];
UINT16 joyeventcount = 0;
// I'm screaming the hack is clean - ashi
static boolean Snake_Joy_Grabber(event_t *ev)
{
if (ev->type == ev_joystick && ev->key == 0)
{
snakejoyevents[joyeventcount] = ev;
joyeventcount++;
return true;
}
else
return false;
}
static void Snake_FindFreeSlot(UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady)
{
UINT8 x, y;
@ -681,17 +695,19 @@ static void Snake_Handle(void)
UINT8 x, y;
UINT8 oldx, oldy;
UINT16 i;
UINT16 j;
UINT16 joystate = 0;
static INT32 pjoyx = 0, pjoyy = 0;
// Handle retry
if (snake->gameover && (G_PlayerInputDown(0, GC_JUMP) || gamekeydown[KEY_ENTER]))
if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER]))
{
Snake_Initialise();
snake->pausepressed = true; // Avoid accidental pause on respawn
}
// Handle pause
if (G_PlayerInputDown(0, GC_PAUSE) || gamekeydown[KEY_ENTER])
if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER])
{
if (!snake->pausepressed)
snake->paused = !snake->paused;
@ -710,23 +726,58 @@ static void Snake_Handle(void)
oldx = snake->snakex[1];
oldy = snake->snakey[1];
// process the input events in here dear lord
for (j = 0; j < joyeventcount; j++)
{
event_t *ev = snakejoyevents[j];
const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT;
if (ev->y != INT32_MAX)
{
if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone)
{
if (ev->y < 0 && pjoyy >= 0)
joystate = 1;
else if (ev->y > 0 && pjoyy <= 0)
joystate = 2;
pjoyy = ev->y;
}
else
pjoyy = 0;
}
if (ev->x != INT32_MAX)
{
if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone)
{
if (ev->x < 0 && pjoyx >= 0)
joystate = 3;
else if (ev->x > 0 && pjoyx <= 0)
joystate = 4;
pjoyx = ev->x;
}
else
pjoyx = 0;
}
}
joyeventcount = 0;
// Update direction
if (G_PlayerInputDown(0, GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3)
if (PLAYER1INPUTDOWN(GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3)
{
if (snake->snakelength < 2 || x <= oldx)
snake->snakedir[0] = 1;
}
else if (G_PlayerInputDown(0, GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4)
else if (PLAYER1INPUTDOWN(GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4)
{
if (snake->snakelength < 2 || x >= oldx)
snake->snakedir[0] = 2;
}
else if (G_PlayerInputDown(0, GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1)
else if (PLAYER1INPUTDOWN(GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1)
{
if (snake->snakelength < 2 || y <= oldy)
snake->snakedir[0] = 3;
}
else if (G_PlayerInputDown(0, GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2)
else if (PLAYER1INPUTDOWN(GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2)
{
if (snake->snakelength < 2 || y >= oldy)
snake->snakedir[0] = 4;
@ -1652,8 +1703,6 @@ static void CL_LoadReceivedSavegame(boolean reloading)
titledemo = false;
automapactive = false;
P_StopRumble(NULL);
// load a base level
if (P_LoadNetGame(reloading))
{
@ -1940,10 +1989,9 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
static void M_ConfirmConnect(event_t *ev)
{
#ifndef NONET
if (ev->type == ev_keydown || ev->type == ev_gamepad_down)
if (ev->type == ev_keydown)
{
if ((ev->type == ev_keydown && (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_A))
if (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER || ev->key == KEY_JOY1)
{
if (totalfilesrequestednum > 0)
{
@ -1958,7 +2006,7 @@ static void M_ConfirmConnect(event_t *ev)
M_ClearMenus(true);
}
else if ((ev->type == ev_keydown && (ev->key == 'n' || ev->key == KEY_ESCAPE)) || (ev->type == ev_gamepad_down && ev->which == 0 && ev->key == GAMEPAD_BUTTON_B))
else if (ev->key == 'n' || ev->key == KEY_ESCAPE || ev->key == KEY_JOY1 + 3)
{
cl_mode = CL_ABORTED;
M_ClearMenus(true);
@ -2392,11 +2440,14 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
// my hand has been forced and I am dearly sorry for this awful hack :vomit:
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
{
G_MapEventsToControls(&events[eventtail]);
#ifndef NONET
if (!Snake_Joy_Grabber(&events[eventtail]))
#endif
G_MapEventsToControls(&events[eventtail]);
}
}
if (gamekeydown[KEY_ESCAPE] || gamepads[0].buttons[GAMEPAD_BUTTON_B] || cl_mode == CL_ABORTED)
if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED)
{
CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
@ -5179,7 +5230,7 @@ static void Local_Maketic(INT32 realtics)
// game responder calls HU_Responder, AM_Responder,
// and G_MapEventsToControls
if (!dedicated) rendergametic = gametic;
// translate inputs (keyboard/mouse/gamepad) into game controls
// translate inputs (keyboard/mouse/joystick) into game controls
G_BuildTiccmd(&localcmds, realtics, 1);
if (splitscreen || botingame)
G_BuildTiccmd(&localcmds2, realtics, 2);

View file

@ -24,21 +24,19 @@ typedef enum
ev_keyup,
ev_console,
ev_mouse,
ev_joystick,
ev_mouse2,
ev_gamepad_up,
ev_gamepad_down,
ev_gamepad_axis
ev_joystick2,
} evtype_t;
// Event structure.
typedef struct
{
evtype_t type;
INT32 key; // key, mouse button, or gamepad button/axis type
INT32 x; // mouse x move, or gamepad axis value
INT32 y; // mouse y move
UINT8 which; // which gamepad or mouse ID
boolean repeated; // is the event repeated?
INT32 key; // keys/mouse/joystick buttons
INT32 x; // mouse/joystick x move
INT32 y; // mouse/joystick y move
boolean repeated; // key repeat
} event_t;
//

View file

@ -43,7 +43,6 @@
#include "i_time.h"
#include "i_threads.h"
#include "i_video.h"
#include "i_gamepad.h"
#include "m_argv.h"
#include "m_menu.h"
#include "m_misc.h"
@ -987,7 +986,6 @@ void D_StartTitle(void)
G_SetGametype(GT_COOP);
paused = false;
advancedemo = false;
P_StopRumble(NULL);
F_InitMenuPresValues();
F_StartTitleScreen();
@ -1398,9 +1396,6 @@ void D_SRB2Main(void)
CONS_Printf("I_InitializeTime()...\n");
I_InitializeTime();
// Initializes the game logic side of gamepads
G_InitGamepads();
// Make backups of some SOCcable tables.
P_BackupTables();
@ -1456,9 +1451,6 @@ void D_SRB2Main(void)
D_RegisterServerCommands();
D_RegisterClientCommands(); // be sure that this is called before D_CheckNetGame
I_InitGamepads();
R_RegisterEngineStuff();
S_RegisterSoundStuff();

View file

@ -21,7 +21,6 @@
#include "g_game.h"
#include "hu_stuff.h"
#include "g_input.h"
#include "i_gamepad.h"
#include "m_menu.h"
#include "r_local.h"
#include "r_skins.h"
@ -183,6 +182,14 @@ static CV_PossibleValue_t mouse2port_cons_t[] = {{1, "COM1"}, {2, "COM2"}, {3, "
{0, NULL}};
#endif
#ifdef LJOYSTICK
static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"}, {3, "/dev/js2"},
{4, "/dev/js3"}, {0, NULL}};
#else
// accept whatever value - it is in fact the joystick device number
#define usejoystick_cons_t NULL
#endif
static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}};
static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
@ -241,61 +248,19 @@ INT32 cv_debug;
consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse);
consvar_t cv_usemouse2 = CVAR_INIT ("use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2);
// We use cv_usegamepad.string as the USER-SET var
// and cv_usegamepad.value as the INTERNAL var
//
// In practice, if cv_usegamepad.string == 0, this overrides
// cv_usegamepad.value and always disables
static void UseGamepad_OnChange(void)
{
I_ChangeGamepad(0);
}
static void UseGamepad2_OnChange(void)
{
I_ChangeGamepad(1);
}
consvar_t cv_usegamepad[2] = {
CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, NULL, UseGamepad_OnChange),
CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, NULL, UseGamepad2_OnChange)
};
static void PadScale_OnChange(void)
{
I_SetGamepadDigital(0, cv_gamepad_scale[0].value == 0);
}
static void PadScale2_OnChange(void)
{
I_SetGamepadDigital(1, cv_gamepad_scale[1].value == 0);
}
consvar_t cv_gamepad_scale[2] = {
CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, PadScale_OnChange),
CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, PadScale2_OnChange)
};
static void PadRumble_OnChange(void)
{
if (!cv_gamepad_rumble[0].value)
I_StopGamepadRumble(0);
}
static void PadRumble2_OnChange(void)
{
if (!cv_gamepad_rumble[1].value)
I_StopGamepadRumble(1);
}
consvar_t cv_gamepad_rumble[2] = {
CVAR_INIT ("padrumble", "Off", CV_SAVE|CV_CALL, CV_OnOff, PadRumble_OnChange),
CVAR_INIT ("padrumble2", "Off", CV_SAVE|CV_CALL, CV_OnOff, PadRumble2_OnChange)
};
consvar_t cv_gamepad_autopause = CVAR_INIT ("pauseongamepaddisconnect", "On", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_usejoystick = CVAR_INIT ("use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick);
consvar_t cv_usejoystick2 = CVAR_INIT ("use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2);
#if (defined (LJOYSTICK) || defined (HAVE_SDL))
#ifdef LJOYSTICK
consvar_t cv_joyport = CVAR_INIT ("padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL);
consvar_t cv_joyport2 = CVAR_INIT ("padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL); //Alam: for later
#endif
consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale);
consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2);
#else
consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save
consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save
#endif
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL);
consvar_t cv_mouse2opt = CVAR_INIT ("mouse2opt", "0", CV_SAVE, NULL, NULL);
@ -807,18 +772,26 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_pauseifunfocused);
// g_input.c
CV_RegisterVar(&cv_sideaxis[0]);
CV_RegisterVar(&cv_sideaxis[1]);
CV_RegisterVar(&cv_turnaxis[0]);
CV_RegisterVar(&cv_turnaxis[1]);
CV_RegisterVar(&cv_moveaxis[0]);
CV_RegisterVar(&cv_moveaxis[1]);
CV_RegisterVar(&cv_lookaxis[0]);
CV_RegisterVar(&cv_lookaxis[1]);
CV_RegisterVar(&cv_deadzone[0]);
CV_RegisterVar(&cv_deadzone[1]);
CV_RegisterVar(&cv_digitaldeadzone[0]);
CV_RegisterVar(&cv_digitaldeadzone[1]);
CV_RegisterVar(&cv_sideaxis);
CV_RegisterVar(&cv_sideaxis2);
CV_RegisterVar(&cv_turnaxis);
CV_RegisterVar(&cv_turnaxis2);
CV_RegisterVar(&cv_moveaxis);
CV_RegisterVar(&cv_moveaxis2);
CV_RegisterVar(&cv_lookaxis);
CV_RegisterVar(&cv_lookaxis2);
CV_RegisterVar(&cv_jumpaxis);
CV_RegisterVar(&cv_jumpaxis2);
CV_RegisterVar(&cv_spinaxis);
CV_RegisterVar(&cv_spinaxis2);
CV_RegisterVar(&cv_fireaxis);
CV_RegisterVar(&cv_fireaxis2);
CV_RegisterVar(&cv_firenaxis);
CV_RegisterVar(&cv_firenaxis2);
CV_RegisterVar(&cv_deadzone);
CV_RegisterVar(&cv_deadzone2);
CV_RegisterVar(&cv_digitaldeadzone);
CV_RegisterVar(&cv_digitaldeadzone2);
// filesrch.c
CV_RegisterVar(&cv_addons_option);
@ -834,6 +807,7 @@ void D_RegisterClientCommands(void)
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
CV_RegisterVar(&cv_mouse2opt);
#endif
CV_RegisterVar(&cv_controlperkey);
CV_RegisterVar(&cv_usemouse);
CV_RegisterVar(&cv_usemouse2);
@ -846,14 +820,14 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_mousemove);
CV_RegisterVar(&cv_mousemove2);
for (i = 0; i < 2; i++)
{
CV_RegisterVar(&cv_usegamepad[i]);
CV_RegisterVar(&cv_gamepad_scale[i]);
CV_RegisterVar(&cv_gamepad_rumble[i]);
}
CV_RegisterVar(&cv_gamepad_autopause);
CV_RegisterVar(&cv_usejoystick);
CV_RegisterVar(&cv_usejoystick2);
#ifdef LJOYSTICK
CV_RegisterVar(&cv_joyport);
CV_RegisterVar(&cv_joyport2);
#endif
CV_RegisterVar(&cv_joyscale);
CV_RegisterVar(&cv_joyscale2);
// Analog Control
CV_RegisterVar(&cv_analog[0]);
@ -2242,14 +2216,9 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
{
if (!menuactive || netgame)
S_PauseAudio();
P_PauseRumble(NULL);
}
else
{
S_ResumeAudio();
P_UnpauseRumble(NULL);
}
}
I_UpdateMouseGrab();
@ -4644,8 +4613,6 @@ void Command_ExitGame_f(void)
emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks));
P_StopRumble(NULL);
if (dirmenu)
closefilemenu(true);

View file

@ -33,10 +33,14 @@ extern consvar_t cv_defaultskin2;
extern consvar_t cv_seenames, cv_allowseenames;
extern consvar_t cv_usemouse;
extern consvar_t cv_usegamepad[2];
extern consvar_t cv_gamepad_scale[2];
extern consvar_t cv_gamepad_rumble[2];
extern consvar_t cv_gamepad_autopause;
extern consvar_t cv_usejoystick;
extern consvar_t cv_usejoystick2;
#ifdef LJOYSTICK
extern consvar_t cv_joyport;
extern consvar_t cv_joyport2;
#endif
extern consvar_t cv_joyscale;
extern consvar_t cv_joyscale2;
// splitscreen with second mouse
extern consvar_t cv_mouse2port;

View file

@ -22,9 +22,9 @@
#include "v_video.h" // video flags (for lua)
#include "i_sound.h" // musictype_t (for lua)
#include "g_state.h" // gamestate_t (for lua)
#include "g_game.h" // Gamepad axes (for lua)
#include "g_game.h" // Joystick axes (for lua)
#include "i_joy.h"
#include "g_input.h" // Game controls (for lua)
#include "i_gamepad.h"
#include "deh_tables.h"
@ -4841,7 +4841,7 @@ const char *const MENUTYPES_LIST[] = {
"OP_CHANGECONTROLS", // OP_ChangeControlsDef shared with P2
"OP_P1MOUSE",
"OP_P1JOYSTICK",
"OP_JOYSTICKSET", // OP_GamepadSetDef shared with P2
"OP_JOYSTICKSET", // OP_JoystickSetDef shared with P2
"OP_P1CAMERA",
"OP_P2CONTROLS",
@ -5642,13 +5642,18 @@ struct int_const_s const INT_CONST[] = {
{"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER},
{"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS},
// Gamepad axes
// Joystick axes
{"JA_NONE",JA_NONE},
{"JA_TURN",JA_TURN},
{"JA_MOVE",JA_MOVE},
{"JA_LOOK",JA_LOOK},
{"JA_STRAFE",JA_STRAFE},
{"JOYAXISRANGE",OLDJOYAXISRANGE},
{"JA_DIGITAL",JA_DIGITAL},
{"JA_JUMP",JA_JUMP},
{"JA_SPIN",JA_SPIN},
{"JA_FIRE",JA_FIRE},
{"JA_FIRENORMAL",JA_FIRENORMAL},
{"JOYAXISRANGE",JOYAXISRANGE},
// Game controls
{"GC_NULL",GC_NULL},

View file

@ -209,7 +209,7 @@ extern char logfilename[1024];
// to an increment in MODVERSION. This might never happen in practice.
// If MODVERSION increases, set MINOREXECVERSION to 0.
#define MAJOREXECVERSION MODVERSION
#define MINOREXECVERSION 1
#define MINOREXECVERSION 0
// (It would have been nice to use VERSION and SUBVERSION but those are zero'd out for DEVELOP builds)
// Macros
@ -556,6 +556,9 @@ UINT32 quickncasehash (const char *p, size_t n)
#define max(x, y) (((x) > (y)) ? (x) : (y))
#endif
// Max gamepad/joysticks that can be detected/used.
#define MAX_JOYSTICKS 4
#ifndef M_PIl
#define M_PIl 3.1415926535897932384626433832795029L
#endif

View file

@ -37,7 +37,6 @@
#include "m_cond.h"
#include "p_local.h"
#include "p_setup.h"
#include "p_haptic.h"
#include "st_stuff.h" // hud hiding
#include "fastcmp.h"
#include "console.h"
@ -511,7 +510,6 @@ void F_StartIntro(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
F_NewCutscene(introtext[0]);
intro_scenenum = 0;
@ -993,10 +991,9 @@ void F_IntroTicker(void)
//
boolean F_IntroResponder(event_t *event)
{
INT32 type = event->type;
INT32 key = G_RemapGamepadEvent(event, &type);
INT32 key = event->key;
// remap virtual keys (mouse & gamepad buttons)
// remap virtual keys (mouse & joystick buttons)
switch (key)
{
case KEY_MOUSE1:
@ -1005,30 +1002,34 @@ boolean F_IntroResponder(event_t *event)
case KEY_MOUSE1 + 1:
key = KEY_BACKSPACE;
break;
case GAMEPAD_KEY(START):
case GAMEPAD_KEY(A):
case GAMEPAD_KEY(X):
case GAMEPAD_KEY(B):
case KEY_JOY1:
case KEY_JOY1 + 2:
key = KEY_ENTER;
break;
case GAMEPAD_KEY(DPAD_UP):
case KEY_JOY1 + 3:
key = 'n';
break;
case KEY_JOY1 + 1:
key = KEY_BACKSPACE;
break;
case KEY_HAT1:
key = KEY_UPARROW;
break;
case GAMEPAD_KEY(DPAD_DOWN):
case KEY_HAT1 + 1:
key = KEY_DOWNARROW;
break;
case GAMEPAD_KEY(DPAD_LEFT):
case KEY_HAT1 + 2:
key = KEY_LEFTARROW;
break;
case GAMEPAD_KEY(DPAD_RIGHT):
case KEY_HAT1 + 3:
key = KEY_RIGHTARROW;
break;
}
if (type != ev_keydown)
if (event->type != ev_keydown && key != 301)
return false;
if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE)
if (key != 27 && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE)
return false;
if (keypressed)
@ -1263,7 +1264,6 @@ void F_StartCredits(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
S_StopMusic();
S_StopSounds();
@ -1376,10 +1376,9 @@ void F_CreditTicker(void)
boolean F_CreditResponder(event_t *event)
{
INT32 type = event->type;
INT32 key = G_RemapGamepadEvent(event, &type);
INT32 key = event->key;
// remap virtual keys (mouse & gamepad buttons)
// remap virtual keys (mouse & joystick buttons)
switch (key)
{
case KEY_MOUSE1:
@ -1388,22 +1387,26 @@ boolean F_CreditResponder(event_t *event)
case KEY_MOUSE1 + 1:
key = KEY_BACKSPACE;
break;
case GAMEPAD_KEY(START):
case GAMEPAD_KEY(A):
case GAMEPAD_KEY(X):
case GAMEPAD_KEY(B):
case KEY_JOY1:
case KEY_JOY1 + 2:
key = KEY_ENTER;
break;
case GAMEPAD_KEY(DPAD_UP):
case KEY_JOY1 + 3:
key = 'n';
break;
case KEY_JOY1 + 1:
key = KEY_BACKSPACE;
break;
case KEY_HAT1:
key = KEY_UPARROW;
break;
case GAMEPAD_KEY(DPAD_DOWN):
case KEY_HAT1 + 1:
key = KEY_DOWNARROW;
break;
case GAMEPAD_KEY(DPAD_LEFT):
case KEY_HAT1 + 2:
key = KEY_LEFTARROW;
break;
case GAMEPAD_KEY(DPAD_RIGHT):
case KEY_HAT1 + 3:
key = KEY_RIGHTARROW;
break;
}
@ -1411,7 +1414,7 @@ boolean F_CreditResponder(event_t *event)
if (!(timesBeaten) && !(netgame || multiplayer) && !cv_debug)
return false;
if (type != ev_keydown)
if (event->type != ev_keydown)
return false;
if (key != KEY_ESCAPE && key != KEY_ENTER && key != KEY_SPACE && key != KEY_BACKSPACE)
@ -1452,7 +1455,6 @@ void F_StartGameEvaluation(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
finalecount = -1;
sparklloop = 0;
@ -1778,7 +1780,6 @@ void F_StartEnding(void)
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
S_StopMusic(); // todo: placeholder
S_StopSounds();
@ -2224,7 +2225,6 @@ void F_StartGameEnd(void)
paused = false;
CON_ToggleOff();
S_StopSounds();
P_StopRumble(NULL);
// In case menus are still up?!!
M_ClearMenus(true);
@ -3567,7 +3567,6 @@ void F_StartContinue(void)
keypressed = false;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
// In case menus are still up?!!
M_ClearMenus(true);
@ -3820,26 +3819,24 @@ void F_ContinueTicker(void)
boolean F_ContinueResponder(event_t *event)
{
INT32 key = event->key;
if (keypressed)
return true;
INT32 type = event->type;
INT32 key = G_RemapGamepadEvent(event, &type);
if (timetonext >= 21*TICRATE/2)
return false;
if (event->type != ev_keydown)
return false;
// remap virtual keys (mouse & gamepad buttons)
// remap virtual keys (mouse & joystick buttons)
switch (key)
{
case KEY_ENTER:
case KEY_SPACE:
case KEY_MOUSE1:
case GAMEPAD_KEY(START):
case GAMEPAD_KEY(A):
case GAMEPAD_KEY(X):
case KEY_JOY1:
case KEY_JOY1 + 2:
break;
default:
return false;
@ -3957,7 +3954,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
gameaction = ga_nothing;
paused = false;
CON_ToggleOff();
P_StopRumble(NULL);
F_NewCutscene(cutscenes[cutscenenum]->scene[0].text);

View file

@ -32,7 +32,7 @@
#include "z_zone.h"
#include "i_video.h"
#include "byteptr.h"
#include "i_gamepad.h"
#include "i_joy.h"
#include "r_local.h"
#include "r_skins.h"
#include "y_inter.h"
@ -1527,9 +1527,9 @@ void G_BeginRecording(void)
buf |= 0x08;
pflags |= PF_AUTOBRAKE;
}
if (cv_usegamepad[0].value)
if (cv_usejoystick.value)
buf |= 0x10;
CV_SetValue(&cv_showinputjoy, !!(cv_usegamepad[0].value));
CV_SetValue(&cv_showinputjoy, !!(cv_usejoystick.value));
WRITEUINT8(demo_p,buf);
player->pflags = pflags;

File diff suppressed because it is too large Load diff

View file

@ -68,13 +68,10 @@ typedef enum {
#define P_ControlStyle(player) ((((player)->pflags & PF_ANALOGMODE) ? CS_LMAOGALOG : 0) | (((player)->pflags & PF_DIRECTIONCHAR) ? CS_STANDARD : 0))
extern consvar_t cv_autobrake, cv_autobrake2;
extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis,cv_deadzone,cv_digitaldeadzone;
extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2,cv_deadzone2,cv_digitaldeadzone2;
extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest;
extern consvar_t cv_sideaxis[2], cv_turnaxis[2], cv_moveaxis[2], cv_lookaxis[2],
cv_deadzone[2], cv_digitaldeadzone[2];
extern CV_PossibleValue_t joyaxis_cons_t[];
// hi here's some new controls
extern consvar_t cv_cam_shiftfacing[2], cv_cam_turnfacing[2],
cv_cam_turnfacingability[2], cv_cam_turnfacingspindash[2], cv_cam_turnfacinginput[2],
@ -87,19 +84,25 @@ typedef enum
LOCK_INTERESTS = 1<<2,
} lockassist_e;
// Legacy axis stuff
#define JOYAXISSET 4 // 4 Sets of 2 axes
typedef enum
{
JA_NONE,
JA_NONE = 0,
JA_TURN,
JA_MOVE,
JA_LOOK,
JA_STRAFE,
JA_DIGITAL, // axes henceforth use digital deadzone
JA_JUMP = JA_DIGITAL,
JA_SPIN,
JA_FIRE,
JA_FIRENORMAL,
} joyaxis_e;
INT16 G_JoyAxis(UINT8 which, joyaxis_e axissel);
INT32 JoyAxis(joyaxis_e axissel);
INT32 Joy2Axis(joyaxis_e axissel);
// mouseaiming (looking up/down with the mouse or keyboard)
#define KB_LOOKSPEED (1<<25)
@ -119,18 +122,6 @@ ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n);
// copy ticcmd_t to and fro network packets
ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n);
// gets the user-set gamepad device for a specific player
INT32 G_GetGamepadDeviceIndex(INT32 player);
// returns a player's gamepad index
INT16 G_GetGamepadForPlayer(player_t *player);
// called when a player's gamepad is connected
void G_OnGamepadConnect(UINT8 which);
// called when a player's gamepad is disconnected
void G_OnGamepadDisconnect(UINT8 which);
// clip the console player aiming to the view
INT16 G_ClipAimingPitch(INT32 *aiming);
INT16 G_SoftwareClipAimingPitch(INT32 *aiming);

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file g_input.h
/// \brief handle mouse/keyboard/gamepad inputs,
/// \brief handle mouse/keyboard/joystick inputs,
/// maps inputs to game controls (forward, spin, jump...)
#ifndef __G_INPUT__
@ -17,179 +17,45 @@
#include "d_event.h"
#include "keys.h"
#include "command.h"
#include "m_fixed.h"
// number of total 'button' inputs, include keyboard keys, plus virtual
// keys (mousebuttons and joybuttons becomes keys)
#define NUMKEYS 256
// Max gamepads that can be used by every player
#define NUM_GAMEPADS 2
// Max gamepads that can be detected
#define MAX_CONNECTED_GAMEPADS 4
// Max mouse buttons
#define MOUSEBUTTONS 8
typedef enum
{
GAMEPAD_TYPE_UNKNOWN,
GAMEPAD_TYPE_XBOX360,
GAMEPAD_TYPE_XBOXONE,
GAMEPAD_TYPE_XBOX_SERIES_XS,
GAMEPAD_TYPE_XBOX_ELITE,
GAMEPAD_TYPE_PS3,
GAMEPAD_TYPE_PS4,
GAMEPAD_TYPE_PS5,
GAMEPAD_TYPE_NINTENDO_SWITCH_PRO,
GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_GRIP,
GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_LEFT,
GAMEPAD_TYPE_NINTENDO_SWITCH_JOY_CON_RIGHT,
GAMEPAD_TYPE_GOOGLE_STADIA,
GAMEPAD_TYPE_AMAZON_LUNA,
GAMEPAD_TYPE_STEAM_CONTROLLER,
GAMEPAD_TYPE_VIRTUAL
} gamepadtype_e;
boolean G_GamepadTypeIsXbox(gamepadtype_e type);
boolean G_GamepadTypeIsPlayStation(gamepadtype_e type);
boolean G_GamepadTypeIsNintendoSwitch(gamepadtype_e type);
boolean G_GamepadTypeIsJoyCon(gamepadtype_e type);
const char *G_GamepadTypeToString(gamepadtype_e type);
typedef enum
{
GAMEPAD_BUTTON_A,
GAMEPAD_BUTTON_B,
GAMEPAD_BUTTON_X,
GAMEPAD_BUTTON_Y,
GAMEPAD_BUTTON_BACK,
GAMEPAD_BUTTON_GUIDE,
GAMEPAD_BUTTON_START,
GAMEPAD_BUTTON_LEFTSTICK,
GAMEPAD_BUTTON_RIGHTSTICK,
GAMEPAD_BUTTON_LEFTSHOULDER,
GAMEPAD_BUTTON_RIGHTSHOULDER,
GAMEPAD_BUTTON_DPAD_UP,
GAMEPAD_BUTTON_DPAD_DOWN,
GAMEPAD_BUTTON_DPAD_LEFT,
GAMEPAD_BUTTON_DPAD_RIGHT,
// According to SDL, this button can be:
// the Xbox Series X|S share button
// the PS5 microphone button
// the Nintendo Switch (Pro or Joy-Con) capture button
// the Amazon Luna microphone button
GAMEPAD_BUTTON_MISC1,
// Xbox Elite paddles
GAMEPAD_BUTTON_PADDLE1,
GAMEPAD_BUTTON_PADDLE2,
GAMEPAD_BUTTON_PADDLE3,
GAMEPAD_BUTTON_PADDLE4,
// PS4/PS5 touchpad button
GAMEPAD_BUTTON_TOUCHPAD,
NUM_GAMEPAD_BUTTONS
} gamepad_button_e;
typedef enum
{
GAMEPAD_AXIS_LEFTX,
GAMEPAD_AXIS_LEFTY,
GAMEPAD_AXIS_RIGHTX,
GAMEPAD_AXIS_RIGHTY,
GAMEPAD_AXIS_TRIGGERLEFT,
GAMEPAD_AXIS_TRIGGERRIGHT,
NUM_GAMEPAD_AXES
} gamepad_axis_e;
extern const char *const gamepad_button_names[NUM_GAMEPAD_BUTTONS + 1];
extern const char *const gamepad_axis_names[NUM_GAMEPAD_AXES + 1];
// Haptic effects
typedef struct
{
fixed_t large_magnitude; // Magnitude of the large motor
fixed_t small_magnitude; // Magnitude of the small motor
tic_t duration; // The total duration of the effect, in tics
} haptic_t;
// Gamepad info for each player on the system
typedef struct
{
// Gamepad index
UINT8 num;
// Gamepad is connected and being used by a player
boolean connected;
// What kind of controller this is (Xbox 360, DualShock, Joy-Con, etc.)
gamepadtype_e type;
// Treat this gamepad's axes as if it they were buttons
boolean digital;
struct {
boolean supported; // Gamepad can rumble
boolean active; // Rumble is active
boolean paused; // Rumble is paused
haptic_t data; // Current haptic effect status
} rumble;
UINT8 buttons[NUM_GAMEPAD_BUTTONS]; // Current state of all buttons
INT16 axes[NUM_GAMEPAD_AXES]; // Current state of all axes
} gamepad_t;
void G_InitGamepads(void);
typedef enum
{
GAMEPAD_STRING_DEFAULT, // A
GAMEPAD_STRING_MENU1, // A Button
GAMEPAD_STRING_MENU2 // the A Button
} gamepad_string_e;
const char *G_GetGamepadButtonString(gamepadtype_e type, gamepad_button_e button, gamepad_string_e strtype);
const char *G_GetGamepadAxisString(gamepadtype_e type, gamepad_axis_e button, gamepad_string_e strtype, boolean inv);
extern gamepad_t gamepads[NUM_GAMEPADS];
#define JOYBUTTONS 32 // 32 buttons
#define JOYHATS 4 // 4 hats
#define JOYAXISSET 4 // 4 Sets of 2 axises
//
// mouse and gamepad buttons are handled as 'virtual' keys
// mouse and joystick buttons are handled as 'virtual' keys
//
typedef enum
{
KEY_MOUSE1 = NUMKEYS,
KEY_GAMEPAD = KEY_MOUSE1 + MOUSEBUTTONS,
KEY_AXES = KEY_GAMEPAD + NUM_GAMEPAD_BUTTONS, // Sure, why not.
KEY_INV_AXES = KEY_AXES + NUM_GAMEPAD_AXES,
KEY_JOY1 = KEY_MOUSE1 + MOUSEBUTTONS,
KEY_HAT1 = KEY_JOY1 + JOYBUTTONS,
KEY_DBLMOUSE1 = KEY_INV_AXES + NUM_GAMEPAD_AXES, // double clicks
KEY_DBLMOUSE1 =KEY_HAT1 + JOYHATS*4, // double clicks
KEY_DBLJOY1 = KEY_DBLMOUSE1 + MOUSEBUTTONS,
KEY_DBLHAT1 = KEY_DBLJOY1 + JOYBUTTONS,
KEY_2MOUSE1 = KEY_DBLMOUSE1 + MOUSEBUTTONS,
KEY_DBL2MOUSE1 = KEY_2MOUSE1 + MOUSEBUTTONS,
KEY_2MOUSE1 = KEY_DBLHAT1 + JOYHATS*4,
KEY_2JOY1 = KEY_2MOUSE1 + MOUSEBUTTONS,
KEY_2HAT1 = KEY_2JOY1 + JOYBUTTONS,
KEY_MOUSEWHEELUP = KEY_DBL2MOUSE1 + MOUSEBUTTONS,
KEY_MOUSEWHEELDOWN,
KEY_2MOUSEWHEELUP,
KEY_2MOUSEWHEELDOWN,
KEY_DBL2MOUSE1 = KEY_2HAT1 + JOYHATS*4,
KEY_DBL2JOY1 = KEY_DBL2MOUSE1 + MOUSEBUTTONS,
KEY_DBL2HAT1 = KEY_DBL2JOY1 + JOYBUTTONS,
NUMINPUTS
KEY_MOUSEWHEELUP = KEY_DBL2HAT1 + JOYHATS*4,
KEY_MOUSEWHEELDOWN = KEY_MOUSEWHEELUP + 1,
KEY_2MOUSEWHEELUP = KEY_MOUSEWHEELDOWN + 1,
KEY_2MOUSEWHEELDOWN = KEY_2MOUSEWHEELUP + 1,
NUMINPUTS = KEY_2MOUSEWHEELDOWN + 1,
} key_input_e;
#define GAMEPAD_KEY(key) (KEY_GAMEPAD + GAMEPAD_BUTTON_##key)
#define GAMEPAD_AXIS(key) (KEY_AXES + GAMEPAD_AXIS_##key)
typedef enum
{
GC_NULL = 0, // a key/button mapped to GC_NULL has no effect
@ -249,6 +115,7 @@ typedef enum
// mouse values are used once
extern consvar_t cv_mousesens, cv_mouseysens;
extern consvar_t cv_mousesens2, cv_mouseysens2;
extern consvar_t cv_controlperkey;
typedef struct
{
@ -274,22 +141,19 @@ typedef struct
extern mouse_t mouse;
extern mouse_t mouse2;
extern INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET];
// current state of the keys: true if pushed
extern UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control
extern INT32 gamecontrol[NUM_GAMECONTROLS][2];
extern INT32 gamecontrolbis[NUM_GAMECONTROLS][2]; // secondary splitscreen player
// default control storage, use 0 (gcs_custom) for memory retention
extern INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2];
extern INT32 gamecontroldefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2]; // default control storage, use 0 (gcs_custom) for memory retention
extern INT32 gamecontrolbisdefault[num_gamecontrolschemes][NUM_GAMECONTROLS][2];
boolean G_PlayerInputDown(UINT8 which, gamecontrols_e gc);
boolean G_CheckDigitalPlayerInput(UINT8 which, gamecontrols_e gc);
SINT8 G_PlayerInputIsAnalog(UINT8 which, gamecontrols_e gc, UINT8 settings);
INT16 G_GetAnalogPlayerInput(UINT8 which, gamecontrols_e gc, UINT8 settings);
#define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]])
#define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]])
#define PLAYERINPUTDOWN(p, gc) ((p) == 2 ? PLAYER2INPUTDOWN(gc) : PLAYER1INPUTDOWN(gc))
#define num_gcl_tutorial_check 6
#define num_gcl_tutorial_used 8
@ -317,44 +181,20 @@ extern const INT32 gcl_jump_spin[num_gcl_jump_spin];
// remaps the input event to a game control.
void G_MapEventsToControls(event_t *ev);
boolean G_RumbleSupported(UINT8 which);
boolean G_RumbleGamepad(UINT8 which, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration);
void G_StopGamepadRumble(UINT8 which);
fixed_t G_GetLargeMotorFreq(UINT8 which);
fixed_t G_GetSmallMotorFreq(UINT8 which);
boolean G_GetGamepadRumblePaused(UINT8 which);
boolean G_SetLargeMotorFreq(UINT8 which, fixed_t freq);
boolean G_SetSmallMotorFreq(UINT8 which, fixed_t freq);
void G_SetGamepadRumblePaused(UINT8 which, boolean pause);
INT16 G_GamepadAxisEventValue(UINT8 which, INT16 value);
INT16 G_GetGamepadAxisValue(UINT8 which, gamepad_axis_e axis);
fixed_t G_GetAdjustedGamepadAxis(UINT8 which, gamepad_axis_e axis, boolean applyDeadzone);
UINT16 G_GetGamepadDeadZone(UINT8 which);
UINT16 G_GetGamepadDigitalDeadZone(UINT8 which);
INT32 G_BasicDeadZoneCalculation(INT32 magnitude, const UINT16 jdeadzone);
INT32 G_RemapGamepadEvent(event_t *event, INT32 *type);
// returns the name of a key
const char *G_KeyNumToName(INT32 keynum);
INT32 G_KeyNameToNum(const char *keystr);
const char *G_GetDisplayNameForKey(INT32 keynum);
// detach any keys associated to the given game control
void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control);
void G_ClearAllControlKeys(void);
void Command_Setcontrol_f(void);
void Command_Setcontrol2_f(void);
void G_DefineDefaultControls(void);
INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2]);
INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify, UINT8 player);
INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify);
// sets the members of a mouse_t given position deltas
void G_SetMouseDeltas(INT32 dx, INT32 dy, UINT8 ssplayer);

View file

@ -5180,7 +5180,15 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->rollangle
&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
{
rollangle = R_GetRollAngle(thing->rollangle);
if (papersprite)
{
// a positive rollangle should should pitch papersprites upwards relative to their facing angle
rollangle = R_GetRollAngle(InvAngle(thing->rollangle));
}
else
{
rollangle = R_GetRollAngle(thing->rollangle);
}
rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle);
if (rotsprite != NULL)
@ -5234,7 +5242,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
{
interpmobjstate_t casterinterp = { 0 };
fixed_t groundz;
fixed_t floordiff;
fixed_t floordiff;
if (R_UsingFrameInterpolation() && !paused)
{
@ -5244,7 +5252,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
{
R_InterpolateMobjState(caster, FRACUNIT, &casterinterp);
}
groundz = R_GetShadowZ(thing, NULL);
floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz);

View file

@ -86,13 +86,8 @@ Contact_error (void)
static void
get_user_agent(char *buf, size_t len)
{
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L
if (sprintf_s(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 1)
if (snprintf(buf, len, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0)
I_Error("http-mserv: get_user_agent failed");
#else
if (sprintf(buf, "%s/%s (%s; %s; %i; %i) SRB2BASE/%i", SRB2APPLICATION, VERSIONSTRING, compbranch, comprevision, MODID, MODVERSION, CODEBASE) < 0)
I_Error("http-mserv: get_user_agent failed");
#endif
}
static void

View file

@ -840,7 +840,7 @@ void HU_Ticker(void)
hu_tick++;
hu_tick &= 7; // currently only to blink chat input cursor
if (G_PlayerInputDown(0, GC_SCORES))
if (PLAYER1INPUTDOWN(GC_SCORES))
hu_showscores = !chat_on;
else
hu_showscores = false;
@ -1015,6 +1015,26 @@ boolean HU_Responder(event_t *ev)
// only KeyDown events now...
/*// Shoot, to prevent P1 chatting from ruining the game for everyone else, it's either:
// A. completely disallow opening chat entirely in online splitscreen
// or B. iterate through all controls to make sure it's bound to player 1 before eating
// You can see which one I chose.
// (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...)
// (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...)
if (ev->key >= KEY_MOUSE1)
{
INT32 i;
for (i = 0; i < NUM_GAMECONTROLS; i++)
{
if (gamecontrol[i][0] == ev->key || gamecontrol[i][1] == ev->key)
break;
}
if (i == NUM_GAMECONTROLS)
return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET
c = (INT32)ev->key;

View file

@ -1,58 +0,0 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file i_gamepad.h
/// \brief Gamepads
#ifndef __I_GAMEPAD_H__
#define __I_GAMEPAD_H__
#include "g_input.h"
#include "p_haptic.h"
// So m_menu knows whether to store cv_usegamepad value or string
#define GAMEPAD_HOTPLUG
// Value range for axes
#define JOYAXISRANGE INT16_MAX
#define OLDJOYAXISRANGE 1023
// Starts all gamepads
void I_InitGamepads(void);
// Returns the number of gamepads on the system
INT32 I_NumGamepads(void);
// Changes a gamepad's device
void I_ChangeGamepad(UINT8 which);
// Toggles a gamepad's digital axis setting
void I_SetGamepadDigital(UINT8 which, boolean enable);
// Shuts down all gamepads
void I_ShutdownGamepads(void);
// Returns the name of a gamepad from its index
const char *I_GetGamepadName(INT32 joyindex);
// Gamepad rumble interface
boolean I_RumbleSupported(void);
boolean I_RumbleGamepad(UINT8 which, const haptic_t *effect);
boolean I_GetGamepadRumblePaused(UINT8 which);
boolean I_SetGamepadLargeMotorFreq(UINT8 which, fixed_t freq);
boolean I_SetGamepadSmallMotorFreq(UINT8 which, fixed_t freq);
void I_SetGamepadRumblePaused(UINT8 which, boolean pause);
boolean I_GetGamepadRumbleSupported(UINT8 which);
void I_StopGamepadRumble(UINT8 which);
#endif // __I_GAMEPAD_H__

58
src/i_joy.h Normal file
View file

@ -0,0 +1,58 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file i_joy.h
/// \brief share joystick information with game control code
#ifndef __I_JOY_H__
#define __I_JOY_H__
#include "g_input.h"
/*!
\brief -JOYAXISRANGE to +JOYAXISRANGE for each axis
(1024-1) so we can do a right shift instead of division
(doesnt matter anyway, just give enough precision)
a gamepad will return -1, 0, or 1 in the event data
an analog type joystick will return a value
from -JOYAXISRANGE to +JOYAXISRANGE for each axis
*/
#define JOYAXISRANGE 1023
// detect a bug if we increase JOYBUTTONS above DIJOYSTATE's number of buttons
#if (JOYBUTTONS > 64)
"JOYBUTTONS is greater than INT64 bits can hold"
#endif
/** \brief The struct JoyType_s
share some joystick information (maybe 2 for splitscreen), to the game input code,
actually, we need to know if it is a gamepad or analog controls
*/
struct JoyType_s
{
/*! if true, we MUST Poll() to get new joystick data,
that is: we NEED the DIRECTINPUTDEVICE2 ! (watchout NT compatibility) */
INT32 bJoyNeedPoll;
/*! this joystick is a gamepad, read: digital axes
if FALSE, interpret the joystick event data as JOYAXISRANGE (see above) */
INT32 bGamepadStyle;
};
typedef struct JoyType_s JoyType_t;
/** \brief Joystick info
for palyer 1 and 2's joystick/gamepad
*/
extern JoyType_t Joystick, Joystick2;
#endif // __I_JOY_H__

View file

@ -101,6 +101,90 @@ ticcmd_t *I_BaseTiccmd2(void);
*/
void I_Quit(void) FUNCNORETURN;
typedef enum
{
EvilForce = -1,
//Constant
ConstantForce = 0,
//Ramp
RampForce,
//Periodics
SquareForce,
SineForce,
TriangleForce,
SawtoothUpForce,
SawtoothDownForce,
//MAX
NumberofForces,
} FFType;
typedef struct JoyFF_s
{
INT32 ForceX; ///< The X of the Force's Vel
INT32 ForceY; ///< The Y of the Force's Vel
//All
UINT32 Duration; ///< The total duration of the effect, in microseconds
INT32 Gain; //< /The gain to be applied to the effect, in the range from 0 through 10,000.
//All, CONSTANTFORCE -10,000 to 10,000
INT32 Magnitude; ///< Magnitude of the effect, in the range from 0 through 10,000.
//RAMPFORCE
INT32 Start; ///< Magnitude at the start of the effect, in the range from -10,000 through 10,000.
INT32 End; ///< Magnitude at the end of the effect, in the range from -10,000 through 10,000.
//PERIODIC
INT32 Offset; ///< Offset of the effect.
UINT32 Phase; ///< Position in the cycle of the periodic effect at which playback begins, in the range from 0 through 35,999
UINT32 Period; ///< Period of the effect, in microseconds.
} JoyFF_t;
/** \brief Forcefeedback for the first joystick
\param Type what kind of Effect
\param Effect Effect Info
\return void
*/
void I_Tactile(FFType Type, const JoyFF_t *Effect);
/** \brief Forcefeedback for the second joystick
\param Type what kind of Effect
\param Effect Effect Info
\return void
*/
void I_Tactile2(FFType Type, const JoyFF_t *Effect);
/** \brief to set up the first joystick scale
*/
void I_JoyScale(void);
/** \brief to set up the second joystick scale
*/
void I_JoyScale2(void);
// Called by D_SRB2Main.
/** \brief to startup the first joystick
*/
void I_InitJoystick(void);
/** \brief to startup the second joystick
*/
void I_InitJoystick2(void);
/** \brief return the number of joystick on the system
*/
INT32 I_NumJoys(void);
/** \brief The *I_GetJoyName function
\param joyindex which joystick
\return joystick name
*/
const char *I_GetJoyName(INT32 joyindex);
#ifndef NOMUMBLE
#include "p_mobj.h" // mobj_t
#include "s_sound.h" // listener_t
@ -209,7 +293,15 @@ const CPUInfoFlags *I_CPUInfo(void);
*/
const char *I_LocateWad(void);
/** \brief Mice events
/** \brief First Joystick's events
*/
void I_GetJoystickEvents(void);
/** \brief Second Joystick's events
*/
void I_GetJoystick2Events(void);
/** \brief Mouses events
*/
void I_GetMouseEvents(void);

View file

@ -3429,10 +3429,10 @@ state_t states[NUMSTATES] =
{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF3
{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF4
{SPR_TTAG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_TTAG
{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_TTAG
// CTF Sign
{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
// Finish flag
{SPR_FNSF, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG

View file

@ -15,7 +15,6 @@
#include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky
#include "p_slopes.h" // P_GetSlopeZAt
#include "p_haptic.h"
#include "z_zone.h"
#include "r_main.h"
#include "r_draw.h"
@ -221,7 +220,6 @@ static const struct {
{META_LUABANKS, "luabanks[]"},
{META_KEYEVENT, "keyevent_t"},
{META_GAMEPAD, "gamepad_t"},
{META_MOUSE, "mouse_t"},
{NULL, NULL}
};
@ -1734,78 +1732,6 @@ static int lib_pPlayerShouldUseSpinHeight(lua_State *L)
return 1;
}
// P_HAPTIC
///////////
#define GET_OPTIONAL_PLAYER(arg) \
player_t *player = NULL; \
if (!lua_isnoneornil(L, arg)) { \
player = *((player_t **)luaL_checkudata(L, arg, META_PLAYER)); \
if (!player) \
return LUA_ErrInvalid(L, "player_t"); \
}
static int lib_pDoRumble(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
fixed_t large_magnitude = luaL_checkfixed(L, 2);
fixed_t small_magnitude = luaL_optfixed(L, 3, large_magnitude);
tic_t duration = luaL_optinteger(L, 4, 0);
#define CHECK_MAGNITUDE(which) \
if (which##_magnitude < 0 || which##_magnitude > FRACUNIT) \
return luaL_error(L, va(#which " motor frequency %f out of range (minimum is 0.0, maximum is 1.0)", \
FixedToFloat(which##_magnitude)))
CHECK_MAGNITUDE(large);
CHECK_MAGNITUDE(small);
#undef CHECK_MAGNITUDE
lua_pushboolean(L, P_DoRumble(player, large_magnitude, small_magnitude, duration));
return 1;
}
static int lib_pPauseRumble(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
P_PauseRumble(player);
return 0;
}
static int lib_pUnpauseRumble(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
P_UnpauseRumble(player);
return 0;
}
static int lib_pIsRumbleEnabled(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
if (player && P_IsLocalPlayer(player))
lua_pushboolean(L, P_IsRumbleEnabled(player));
else
lua_pushnil(L);
return 1;
}
static int lib_pIsRumblePaused(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
if (player && P_IsLocalPlayer(player))
lua_pushboolean(L, P_IsRumblePaused(player));
else
lua_pushnil(L);
return 1;
}
static int lib_pStopRumble(lua_State *L)
{
GET_OPTIONAL_PLAYER(1);
P_StopRumble(player);
return 0;
}
// P_MAP
///////////
@ -2335,6 +2261,18 @@ static int lib_pMobjTouchingSectorSpecial(lua_State *L)
return 1;
}
static int lib_pThingOnSpecial3DFloor(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
NOHUD
INLEVEL
if (!mo)
return LUA_ErrInvalid(L, "mobj_t");
LUA_Deprecated(L, "P_ThingOnSpecial3DFloor", "P_MobjTouchingSectorSpecial\" or \"P_MobjTouchingSectorSpecialFlag");
LUA_PushUserdata(L, P_ThingOnSpecial3DFloor(mo), META_SECTOR);
return 1;
}
static int lib_pMobjTouchingSectorSpecialFlag(lua_State *L)
{
mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ));
@ -3442,6 +3380,7 @@ static int lib_sResumeMusic(lua_State *L)
// G_GAME
////////////
// Copypasted from lib_cvRegisterVar :]
static int lib_gAddGametype(lua_State *L)
{
const char *k;
@ -4163,14 +4102,6 @@ static luaL_Reg lib[] = {
{"P_PlayerCanEnterSpinGaps",lib_pPlayerCanEnterSpinGaps},
{"P_PlayerShouldUseSpinHeight",lib_pPlayerShouldUseSpinHeight},
// p_haptic
{"P_DoRumble",lib_pDoRumble},
{"P_PauseRumble",lib_pPauseRumble},
{"P_UnpauseRumble",lib_pUnpauseRumble},
{"P_IsRumbleEnabled",lib_pIsRumbleEnabled},
{"P_IsRumblePaused",lib_pIsRumblePaused},
{"P_StopRumble",lib_pStopRumble},
// p_map
{"P_CheckPosition",lib_pCheckPosition},
{"P_TryMove",lib_pTryMove},
@ -4213,6 +4144,7 @@ static luaL_Reg lib[] = {
{"P_DoSuperTransformation",lib_pDoSuperTransformation},
{"P_ExplodeMissile",lib_pExplodeMissile},
{"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial},
{"P_ThingOnSpecial3DFloor",lib_pThingOnSpecial3DFloor},
{"P_MobjTouchingSectorSpecialFlag",lib_pMobjTouchingSectorSpecialFlag},
{"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial},
{"P_PlayerTouchingSectorSpecialFlag",lib_pPlayerTouchingSectorSpecialFlag},

View file

@ -74,10 +74,6 @@ automatically.
X (PlayerCanEnterSpinGaps),\
X (KeyDown),\
X (KeyUp),\
X (GamepadButtonDown),\
X (GamepadButtonUp),\
X (GamepadAdded),\
X (GamepadRemoved),\
#define STRING_HOOK_LIST(X) \
X (BotAI),/* B_BuildTailsTiccmd by skin name */\
@ -129,8 +125,6 @@ void LUA_HookBool(boolean value, int hook);
int LUA_HookPlayer(player_t *, int hook);
int LUA_HookTiccmd(player_t *, ticcmd_t *, int hook);
int LUA_HookKey(event_t *event, int hook); // Hooks for key events
int LUA_HookGamepadButton(event_t *event, int hook);
void LUA_HookGamepadEvent(UINT8 which, int hook);
void LUA_HookThinkFrame(void);
int LUA_HookMobjLineCollide(mobj_t *, line_t *);

View file

@ -14,7 +14,6 @@
#include "doomstat.h"
#include "p_mobj.h"
#include "g_game.h"
#include "g_input.h"
#include "r_skins.h"
#include "b_bot.h"
#include "z_zone.h"
@ -647,28 +646,6 @@ int LUA_HookKey(event_t *event, int hook_type)
return hook.status;
}
int LUA_HookGamepadButton(event_t *event, int hook_type)
{
Hook_State hook;
if (prepare_hook(&hook, false, hook_type))
{
LUA_PushUserdata(gL, &gamepads[event->which], META_GAMEPAD);
lua_pushstring(gL, gamepad_button_names[event->key]);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
void LUA_HookGamepadEvent(UINT8 which, int hook_type)
{
Hook_State hook;
if (prepare_hook(&hook, 0, hook_type))
{
LUA_PushUserdata(gL, &gamepads[which], META_GAMEPAD);
call_hooks(&hook, 0, res_none);
}
}
void LUA_HookHUD(int hook_type, huddrawlist_h list)
{
const hook_t * map = &hudHookIds[hook_type];

View file

@ -15,7 +15,6 @@
#include "g_game.h"
#include "hu_stuff.h"
#include "i_system.h"
#include "i_gamepad.h"
#include "lua_script.h"
#include "lua_libs.h"
@ -31,7 +30,7 @@ static int lib_gameControlDown(lua_State *L)
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, G_PlayerInputDown(0, i));
lua_pushinteger(L, PLAYER1INPUTDOWN(i));
return 1;
}
@ -40,7 +39,7 @@ static int lib_gameControl2Down(lua_State *L)
int i = luaL_checkinteger(L, 1);
if (i < 0 || i >= NUM_GAMECONTROLS)
return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1);
lua_pushinteger(L, G_PlayerInputDown(1, i));
lua_pushinteger(L, PLAYER2INPUTDOWN(i));
return 1;
}
@ -67,14 +66,14 @@ static int lib_gameControl2ToKeyNum(lua_State *L)
static int lib_joyAxis(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
lua_pushinteger(L, G_JoyAxis(0, i) / 32);
lua_pushinteger(L, JoyAxis(i));
return 1;
}
static int lib_joy2Axis(lua_State *L)
{
int i = luaL_checkinteger(L, 1);
lua_pushinteger(L, G_JoyAxis(1, i) / 32);
lua_pushinteger(L, Joy2Axis(i));
return 1;
}
@ -129,21 +128,6 @@ static int lib_getCursorPosition(lua_State *L)
return 2;
}
static int lib_getPlayerGamepad(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
if (!player)
return LUA_ErrInvalid(L, "player_t");
INT16 which = G_GetGamepadForPlayer(player);
if (which >= 0)
LUA_PushUserdata(L, &gamepads[which], META_GAMEPAD);
else
lua_pushnil(L);
return 1;
}
static luaL_Reg lib[] = {
{"gameControlDown", lib_gameControlDown},
{"gameControl2Down", lib_gameControl2Down},
@ -158,7 +142,6 @@ static luaL_Reg lib[] = {
{"getMouseGrab", lib_getMouseGrab},
{"setMouseGrab", lib_setMouseGrab},
{"getCursorPosition", lib_getCursorPosition},
{"getPlayerGamepad", lib_getPlayerGamepad},
{NULL, NULL}
};
@ -214,341 +197,6 @@ static int keyevent_get(lua_State *L)
return 1;
}
/////////////
// GAMEPAD //
/////////////
enum gamepad_leftright_e {
gamepad_opt_left,
gamepad_opt_right
};
static const char *const gamepad_leftright_opt[] = {
"left",
"right",
NULL};
// Buttons
static int gamepad_isButtonDown(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
gamepad_button_e button = luaL_checkoption(L, 2, NULL, gamepad_button_names);
lua_pushboolean(L, gamepad->buttons[button] == 1);
return 1;
}
// Axes
static int gamepad_getAxis(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
gamepad_axis_e axis = luaL_checkoption(L, 2, NULL, gamepad_axis_names);
boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true);
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, axis, applyDeadzone));
return 1;
}
// Sticks
static int gamepad_getStick(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt);
boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true);
switch (stick)
{
case gamepad_opt_left:
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_LEFTX, applyDeadzone));
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_LEFTY, applyDeadzone));
break;
case gamepad_opt_right:
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_RIGHTX, applyDeadzone));
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, GAMEPAD_AXIS_RIGHTY, applyDeadzone));
break;
}
return 2;
}
// Triggers
static int gamepad_getTrigger(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt);
boolean applyDeadzone = luaL_opt(L, luaL_checkboolean, 3, true);
gamepad_axis_e axis = 0;
switch (stick)
{
case gamepad_opt_left:
axis = GAMEPAD_AXIS_TRIGGERLEFT;
break;
case gamepad_opt_right:
axis = GAMEPAD_AXIS_TRIGGERRIGHT;
break;
}
lua_pushfixed(L, G_GetAdjustedGamepadAxis(gamepad->num, axis, applyDeadzone));
return 1;
}
// Button and axis names
static int gamepad_getButtonName(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
gamepad_button_e button = luaL_checkoption(L, 2, NULL, gamepad_button_names);
lua_pushstring(L, G_GetGamepadButtonString(gamepad->type, button, GAMEPAD_STRING_DEFAULT));
return 1;
}
static int gamepad_getAxisName(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
gamepad_axis_e axis = luaL_checkoption(L, 2, NULL, gamepad_axis_names);
lua_pushstring(L, G_GetGamepadAxisString(gamepad->type, axis, GAMEPAD_STRING_DEFAULT, false));
return 1;
}
static int gamepad_getTriggerName(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
enum gamepad_leftright_e stick = luaL_checkoption(L, 2, NULL, gamepad_leftright_opt);
gamepad_axis_e axis = 0;
switch (stick)
{
case gamepad_opt_left:
axis = GAMEPAD_AXIS_TRIGGERLEFT;
break;
case gamepad_opt_right:
axis = GAMEPAD_AXIS_TRIGGERRIGHT;
break;
}
lua_pushstring(L, G_GetGamepadAxisString(gamepad->type, axis, GAMEPAD_STRING_DEFAULT, false));
return 1;
}
// Rumble
static int gamepad_doRumble(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
fixed_t large_magnitude = luaL_checkfixed(L, 2);
fixed_t small_magnitude = luaL_optfixed(L, 3, large_magnitude);
tic_t duration = luaL_optinteger(L, 4, 0);
#define CHECK_MAGNITUDE(which) \
if (which##_magnitude < 0 || which##_magnitude > FRACUNIT) \
return luaL_error(L, va(#which " motor frequency %f out of range (minimum is 0.0, maximum is 1.0)", \
FixedToFloat(which##_magnitude)))
CHECK_MAGNITUDE(large);
CHECK_MAGNITUDE(small);
#undef CHECK_MAGNITUDE
lua_pushboolean(L, G_RumbleGamepad(gamepad->num, large_magnitude, small_magnitude, duration));
return 1;
}
static int gamepad_stopRumble(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
G_StopGamepadRumble(gamepad->num);
return 0;
}
// Accessing gamepad userdata
enum gamepad_opt_e {
gamepad_opt_connected,
gamepad_opt_type,
gamepad_opt_isXbox,
gamepad_opt_isPlayStation,
gamepad_opt_isNintendoSwitch,
gamepad_opt_isJoyCon,
gamepad_opt_hasRumble,
gamepad_opt_isRumbling,
gamepad_opt_isRumblePaused,
gamepad_opt_largeMotorFrequency,
gamepad_opt_smallMotorFrequency,
gamepad_opt_isButtonDown,
gamepad_opt_getAxis,
gamepad_opt_getStick,
gamepad_opt_getTrigger,
gamepad_opt_getButtonName,
gamepad_opt_getAxisName,
gamepad_opt_getTriggerName,
gamepad_opt_rumble,
gamepad_opt_stopRumble
};
static const char *const gamepad_opt[] = {
"connected",
"type",
"isXbox",
"isPlayStation",
"isNintendoSwitch",
"isJoyCon",
"hasRumble",
"isRumbling",
"isRumblePaused",
"largeMotorFrequency",
"smallMotorFrequency",
"isButtonDown",
"getAxis",
"getStick",
"getTrigger",
"getButtonName",
"getAxisName",
"getTriggerName",
"rumble",
"stopRumble",
NULL};
static int (*gamepad_fn_list[9])(lua_State *L) = {
gamepad_isButtonDown,
gamepad_getAxis,
gamepad_getStick,
gamepad_getTrigger,
gamepad_getButtonName,
gamepad_getAxisName,
gamepad_getTriggerName,
gamepad_doRumble,
gamepad_stopRumble
};
static int gamepad_get(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
enum gamepad_opt_e field = luaL_checkoption(L, 2, NULL, gamepad_opt);
switch (field)
{
case gamepad_opt_connected:
lua_pushboolean(L, gamepad->connected);
break;
case gamepad_opt_type:
lua_pushstring(L, G_GamepadTypeToString(gamepad->type));
break;
case gamepad_opt_isXbox:
lua_pushboolean(L, G_GamepadTypeIsXbox(gamepad->type));
break;
case gamepad_opt_isPlayStation:
lua_pushboolean(L, G_GamepadTypeIsPlayStation(gamepad->type));
break;
case gamepad_opt_isNintendoSwitch:
lua_pushboolean(L, G_GamepadTypeIsNintendoSwitch(gamepad->type));
break;
case gamepad_opt_isJoyCon:
// No, this does not include the grip.
lua_pushboolean(L, G_GamepadTypeIsJoyCon(gamepad->type));
break;
case gamepad_opt_hasRumble:
lua_pushboolean(L, G_RumbleSupported(gamepad->num));
break;
case gamepad_opt_isRumbling:
lua_pushboolean(L, gamepad->rumble.active);
break;
case gamepad_opt_isRumblePaused:
lua_pushboolean(L, G_GetGamepadRumblePaused(gamepad->num));
break;
case gamepad_opt_largeMotorFrequency:
lua_pushfixed(L, G_GetLargeMotorFreq(gamepad->num));
break;
case gamepad_opt_smallMotorFrequency:
lua_pushfixed(L, G_GetSmallMotorFreq(gamepad->num));
break;
case gamepad_opt_isButtonDown:
case gamepad_opt_getAxis:
case gamepad_opt_getStick:
case gamepad_opt_getTrigger:
case gamepad_opt_getButtonName:
case gamepad_opt_getAxisName:
case gamepad_opt_getTriggerName:
case gamepad_opt_rumble:
case gamepad_opt_stopRumble:
lua_pushcfunction(L, gamepad_fn_list[field - gamepad_opt_isButtonDown]);
break;
}
return 1;
}
static int gamepad_set(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
enum gamepad_opt_e field = luaL_checkoption(L, 2, NULL, gamepad_opt);
switch (field)
{
case gamepad_opt_isRumblePaused:
G_SetGamepadRumblePaused(gamepad->num, luaL_checkboolean(L, 3));
break;
case gamepad_opt_largeMotorFrequency:
G_SetLargeMotorFreq(gamepad->num, luaL_checkfixed(L, 3));
break;
case gamepad_opt_smallMotorFrequency:
G_SetSmallMotorFreq(gamepad->num, luaL_checkfixed(L, 3));
break;
default:
return luaL_error(L, LUA_QL("gamepad") " field " LUA_QS " should not be set directly.", gamepad_opt[field]);
}
return 1;
}
static int gamepad_num(lua_State *L)
{
gamepad_t *gamepad = *((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD));
lua_pushinteger(L, gamepad->num + 1);
return 1;
}
static int lib_iterateGamepads(lua_State *L)
{
INT32 i = -1;
if (lua_gettop(L) < 2)
{
lua_pushcfunction(L, lib_iterateGamepads);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // State is unused
if (!lua_isnil(L, 1))
i = (INT32)(*((gamepad_t **)luaL_checkudata(L, 1, META_GAMEPAD)) - gamepads);
for (i++; i < NUM_GAMEPADS; i++)
{
if (!gamepads[i].connected)
continue;
LUA_PushUserdata(L, &gamepads[i], META_GAMEPAD);
return 1;
}
return 0;
}
static int lib_getGamepad(lua_State *L)
{
if (lua_type(L, 2) == LUA_TNUMBER)
{
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 1 || i > NUM_GAMEPADS)
return luaL_error(L, "gamepads[] index %d out of range (1 - %d)", i, NUM_GAMEPADS);
LUA_PushUserdata(L, &gamepads[i - 1], META_GAMEPAD);
return 1;
}
if (fastcmp(luaL_checkstring(L, 2), "iterate"))
{
lua_pushcfunction(L, lib_iterateGamepads);
return 1;
}
return 0;
}
static int lib_lenGamepad(lua_State *L)
{
lua_pushinteger(L, NUM_GAMEPADS);
return 1;
}
///////////
// MOUSE //
///////////
@ -609,27 +257,6 @@ int LUA_InputLib(lua_State *L)
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_GAMEPAD);
lua_pushcfunction(L, gamepad_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, gamepad_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, gamepad_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getGamepad);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_lenGamepad);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "gamepads");
luaL_newmetatable(L, META_MOUSE);
lua_pushcfunction(L, mouse_get);
lua_setfield(L, -2, "__index");

View file

@ -91,7 +91,6 @@ extern boolean mousegrabbedbylua;
#define META_LUABANKS "LUABANKS[]*"
#define META_KEYEVENT "KEYEVENT_T*"
#define META_GAMEPAD "GAMEPAD_T*"
#define META_MOUSE "MOUSE_T*"
boolean luaL_checkboolean(lua_State *L, int narg);

View file

@ -949,7 +949,6 @@ enum
ARCH_MAPHEADER,
ARCH_SKINCOLOR,
ARCH_MOUSE,
ARCH_GAMEPAD,
ARCH_TEND=0xFF,
};
@ -977,7 +976,6 @@ static const struct {
{META_SLOPE, ARCH_SLOPE},
{META_MAPHEADER, ARCH_MAPHEADER},
{META_SKINCOLOR, ARCH_SKINCOLOR},
{META_GAMEPAD, ARCH_GAMEPAD},
{META_MOUSE, ARCH_MOUSE},
{NULL, ARCH_NULL}
};
@ -1293,13 +1291,6 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
WRITEUINT16(save_p, info - skincolors);
break;
}
case ARCH_GAMEPAD:
{
gamepad_t *gamepad = *((gamepad_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_GAMEPAD);
WRITEUINT8(save_p, gamepad->num);
break;
}
case ARCH_MOUSE:
{
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
@ -1550,15 +1541,6 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR);
break;
case ARCH_GAMEPAD:
{
UINT8 which = READUINT8(save_p);
if (which < NUM_GAMEPADS)
LUA_PushUserdata(gL, &gamepads[which], META_GAMEPAD);
else // Wait, what?
lua_pushnil(gL);
break;
}
case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break;

View file

@ -30,13 +30,11 @@
// TODO add some distinction between fixed numbers and integer numbers
// for at least the purpose of printing and maybe math.
#define luaL_checkfixed(L, i) luaL_checkinteger(L, i)
#define luaL_optfixed(L, i, o) luaL_optinteger(L, i, o)
#define lua_pushfixed(L, f) lua_pushinteger(L, f)
// angle_t casting
// TODO deal with signedness
#define luaL_checkangle(L, i) ((angle_t)luaL_checkinteger(L, i))
#define luaL_optangle(L, i, o) ((angle_t)luaL_optinteger(L, i, o))
#define lua_pushangle(L, a) lua_pushinteger(L, a)
#ifdef _DEBUG

View file

@ -199,41 +199,39 @@ static UINT8 cht_CheckCheat(cheatseq_t *cht, char key)
boolean cht_Responder(event_t *ev)
{
UINT8 ch = 0;
UINT8 ret = 0, ch = 0;
if (ev->type != ev_keydown)
return false;
if (ev->type == ev_gamepad_down)
if (ev->key > 0xFF)
{
// map some fake (joy) inputs into keys
// map joy inputs into keys
switch (ev->key)
{
case GAMEPAD_BUTTON_DPAD_UP:
case KEY_JOY1:
case KEY_JOY1 + 2:
ch = KEY_ENTER;
break;
case KEY_HAT1:
ch = KEY_UPARROW;
break;
case GAMEPAD_BUTTON_DPAD_DOWN:
case KEY_HAT1 + 1:
ch = KEY_DOWNARROW;
break;
case GAMEPAD_BUTTON_DPAD_LEFT:
case KEY_HAT1 + 2:
ch = KEY_LEFTARROW;
break;
case GAMEPAD_BUTTON_DPAD_RIGHT:
case KEY_HAT1 + 3:
ch = KEY_RIGHTARROW;
break;
case GAMEPAD_BUTTON_START:
ch = KEY_ENTER;
break;
default:
// no mapping
return false;
}
}
else if (ev->type == ev_keydown)
{
if (ev->key > 0xFF)
return false;
else
ch = (UINT8)ev->key;
}
UINT8 ret = 0;
ret += cht_CheckCheat(&cheat_ultimate, (char)ch);
ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch);

File diff suppressed because it is too large Load diff

View file

@ -223,9 +223,8 @@ typedef enum
{
MM_NOTHING = 0, // is just displayed until the user do someting
MM_YESNO, // routine is called with only 'y' or 'n' in param
MM_KEYHANDLER, // the same of above but without 'y' or 'n' restriction
MM_EVENTHANDLER // the same of above but routine is void routine(event_t *)
// (ex: set control)
MM_EVENTHANDLER // the same of above but without 'y' or 'n' restriction
// and routine is void routine(event_t *) (ex: set control)
} menumessagetype_t;
void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype);
@ -362,11 +361,9 @@ extern menu_t *currentMenu;
extern menu_t MainDef;
extern menu_t SP_LoadDef;
// Call when a gamepad is connected or disconnected
void M_UpdateGamepadMenu(void);
// Returns true if the player is on the gamepad selection menu
boolean M_OnGamepadMenu(void);
// Call upon joystick hotplug
void M_SetupJoystickMenu(INT32 choice);
extern menu_t OP_JoystickSetDef;
// Stuff for customizing the player select screen
typedef struct
@ -541,19 +538,6 @@ void M_FreePlayerSetupColors(void);
NULL\
}
#define GAMEPADMENUSTYLE(id, header, source, prev, x, y)\
{\
id,\
header,\
sizeof(source)/sizeof(menuitem_t),\
prev,\
source,\
M_DrawGamepadMenu,\
x, y,\
0,\
NULL\
}
#define MAPPLATTERMENUSTYLE(id, header, source)\
{\
id,\
@ -574,7 +558,7 @@ void M_FreePlayerSetupColors(void);
sizeof (source)/sizeof (menuitem_t),\
prev,\
source,\
M_DrawControlConfigMenu,\
M_DrawControl,\
24, 40,\
0,\
NULL\

View file

@ -2671,7 +2671,7 @@ void A_LobShot(mobj_t *actor)
fixed_t z;
fixed_t dist;
fixed_t vertical, horizontal;
fixed_t airtime = var2 & 65535;
fixed_t airtime = max(1, var2 & 65535);
if (LUA_CallAction(A_LOBSHOT, actor))
return;
@ -13460,6 +13460,9 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
if (!player)
return true;
if (player->spectator)
return true;
if (player->powers[pw_carry] != CR_DUSTDEVIL && (player->powers[pw_ignorelatch] & (1<<15)))
return true;

View file

@ -1660,7 +1660,7 @@ void EV_DoFloor(mtag_t tag, line_t *line, floor_e floortype)
// chained linedef executing ability
// Only set it on one of the moving sectors (the smallest numbered)
if (line->args[3])
dofloor->tag = firstone ? (INT16)line->args[3] : -1;
dofloor->tag = firstone ? (INT16)line->args[3] : 0;
// flat changing ability
dofloor->texture = line->args[4] ? line->frontsector->floorpic : -1;

View file

@ -1,115 +0,0 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2021-2022 by Jaime "Lactozilla" Passos.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_haptic.c
/// \brief Haptic feedback
#include "p_haptic.h"
#include "g_game.h"
#include "d_netcmd.h"
#include "i_gamepad.h"
#include "doomstat.h"
// Helper function: Returns the gamepad index for a player if it's enabled
static INT16 GetGamepadIndex(player_t *player)
{
INT16 index = G_GetGamepadForPlayer(player);
if (index >= 0 && cv_usegamepad[index].value)
return index;
return -1;
}
// Rumbles a player's gamepad, or all gamepads
boolean P_DoRumble(player_t *player, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration)
{
if (!I_RumbleSupported())
return false;
// Rumble every gamepad
if (player == NULL)
{
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
if (cv_gamepad_rumble[i].value)
G_RumbleGamepad(i, large_magnitude, small_magnitude, duration);
}
return true;
}
INT16 which = GetGamepadIndex(player);
if (which < 0 || !cv_gamepad_rumble[which].value)
return false;
return G_RumbleGamepad((UINT8)which, large_magnitude, small_magnitude, duration);
}
// Pauses or unpauses gamepad rumble for a player (or all of them)
// Rumble is paused or unpaused regardless if it's enabled or not
static void SetRumblePaused(player_t *player, boolean pause)
{
INT16 which = GetGamepadIndex(player);
if (which >= 0)
G_SetGamepadRumblePaused((UINT8)which, pause);
else if (player == NULL)
{
// Pause or unpause every gamepad
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
G_SetGamepadRumblePaused(i, pause);
}
}
void P_PauseRumble(player_t *player)
{
SetRumblePaused(player, true);
}
void P_UnpauseRumble(player_t *player)
{
SetRumblePaused(player, false);
}
boolean P_IsRumbleEnabled(player_t *player)
{
INT16 which = GetGamepadIndex(player);
if (which < 0 || !cv_gamepad_rumble[which].value)
return false;
return G_RumbleSupported((UINT8)which);
}
boolean P_IsRumblePaused(player_t *player)
{
INT16 which = GetGamepadIndex(player);
if (which < 0 || !cv_gamepad_rumble[which].value)
return false;
return G_GetGamepadRumblePaused((UINT8)which);
}
// Stops gamepad rumble for a player (or all of them)
void P_StopRumble(player_t *player)
{
if (!I_RumbleSupported())
return;
if (player)
{
INT16 which = GetGamepadIndex(player);
if (which >= 0)
G_StopGamepadRumble((UINT8)which);
return;
}
// Stop every gamepad instead
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
G_StopGamepadRumble(i);
}

View file

@ -1,27 +0,0 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2021-2022 by Jaime "Lactozilla" Passos.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_haptic.h
/// \brief Haptic feedback
#ifndef __P_HAPTIC__
#define __P_HAPTIC__
#include "doomdef.h"
#include "p_local.h"
boolean P_DoRumble(player_t *player, fixed_t large_magnitude, fixed_t small_magnitude, tic_t duration);
void P_PauseRumble(player_t *player);
void P_UnpauseRumble(player_t *player);
boolean P_IsRumbleEnabled(player_t *player);
boolean P_IsRumblePaused(player_t *player);
void P_StopRumble(player_t *player);
#define P_DoRumbleCombined(player, magnitude, dur) P_DoRumble(player, magnitude, magnitude, dur);
#endif // __P_HAPTIC__

View file

@ -13,7 +13,6 @@
#include "doomdef.h"
#include "i_system.h"
#include "i_gamepad.h"
#include "am_map.h"
#include "g_game.h"
#include "m_random.h"
@ -25,7 +24,6 @@
#include "lua_hook.h"
#include "m_cond.h" // unlockables, emblems, etc
#include "p_setup.h"
#include "p_haptic.h"
#include "m_cheat.h" // objectplace
#include "m_misc.h"
#include "v_video.h" // video flags for CEchos
@ -35,6 +33,54 @@
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
#define CTFTEAMENDCODE(pl) pl->ctfteam ? "\x80" : ""
void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period)
{
BasicFF_t Basicfeed;
if (!player)
return;
Basicfeed.Duration = (UINT32)(duration * (100L/TICRATE));
Basicfeed.ForceX = Basicfeed.ForceY = 1;
Basicfeed.Gain = 25000;
Basicfeed.Magnitude = period*10;
Basicfeed.player = player;
/// \todo test FFB
P_RampConstant(&Basicfeed, attack, fade);
}
void P_ForceConstant(const BasicFF_t *FFInfo)
{
JoyFF_t ConstantQuake;
if (!FFInfo || !FFInfo->player)
return;
ConstantQuake.ForceX = FFInfo->ForceX;
ConstantQuake.ForceY = FFInfo->ForceY;
ConstantQuake.Duration = FFInfo->Duration;
ConstantQuake.Gain = FFInfo->Gain;
ConstantQuake.Magnitude = FFInfo->Magnitude;
if (FFInfo->player == &players[consoleplayer])
I_Tactile(ConstantForce, &ConstantQuake);
else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer])
I_Tactile2(ConstantForce, &ConstantQuake);
}
void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End)
{
JoyFF_t RampQuake;
if (!FFInfo || !FFInfo->player)
return;
RampQuake.ForceX = FFInfo->ForceX;
RampQuake.ForceY = FFInfo->ForceY;
RampQuake.Duration = FFInfo->Duration;
RampQuake.Gain = FFInfo->Gain;
RampQuake.Magnitude = FFInfo->Magnitude;
RampQuake.Start = Start;
RampQuake.End = End;
if (FFInfo->player == &players[consoleplayer])
I_Tactile(ConstantForce, &RampQuake);
else if (splitscreen && FFInfo->player == &players[secondarydisplayplayer])
I_Tactile2(ConstantForce, &RampQuake);
}
//
// GET STUFF
//
@ -3011,8 +3057,6 @@ static boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, IN
player_t *player = target->player;
(void)damage; //unused parm
P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6);
// If flashing or invulnerable, ignore the tag,
if (player->powers[pw_flashing] || player->powers[pw_invulnerability])
return false;
@ -3116,8 +3160,6 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
{
player_t *player = target->player;
(void)damage;
if (!(damagetype & DMG_CANHURTSELF))
{
// You can't kill yourself, idiot...
@ -3180,8 +3222,6 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
{
(void)damage;
player->pflags &= ~PF_SLIDING;
player->powers[pw_carry] = CR_NONE;
@ -3202,7 +3242,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
// Get rid of emeralds
player->powers[pw_emeralds] = 0;
P_DoRumbleCombined(player, FRACUNIT, TICRATE / 3);
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
P_ResetPlayer(player);
@ -3242,9 +3282,7 @@ static void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *source, I
fixed_t fallbackspeed;
angle_t ang;
(void)damage;
P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6);
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z--;
@ -3325,14 +3363,12 @@ void P_RemoveShield(player_t *player)
static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
{
(void)damage;
// Must do pain first to set flashing -- P_RemoveShield can cause damage
P_DoPlayerPain(player, source, inflictor);
P_RemoveShield(player);
P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6);
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
if (damagetype == DMG_SPIKE) // spikes
S_StartSound(player->mo, sfx_spkdth);
@ -3361,7 +3397,7 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN
{
P_DoPlayerPain(player, source, inflictor);
P_DoRumbleCombined(player, FRACUNIT, TICRATE / 6);
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
if (damagetype == DMG_SPIKE) // spikes
S_StartSound(player->mo, sfx_spkdth);
@ -3692,6 +3728,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
damage = 1;
P_KillPlayer(player, source, damage);
}
P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2);
}
// Killing dead. Just for kicks.

View file

@ -453,6 +453,18 @@ extern mobj_t **blocklinks; // for thing chains
//
// P_INTER
//
typedef struct BasicFF_s
{
INT32 ForceX; ///< The X of the Force's Vel
INT32 ForceY; ///< The Y of the Force's Vel
const player_t *player; ///< Player of Rumble
//All
UINT32 Duration; ///< The total duration of the effect, in microseconds
INT32 Gain; ///< /The gain to be applied to the effect, in the range from 0 through 10,000.
//All, CONSTANTFORCE <20>10,000 to 10,000
INT32 Magnitude; ///< Magnitude of the effect, in the range from 0 through 10,000.
} BasicFF_t;
/* Damage/death types, for P_DamageMobj and related */
//// Damage types
//#define DMG_NORMAL 0 (unneeded?)
@ -473,6 +485,9 @@ extern mobj_t **blocklinks; // for thing chains
#define DMG_CANHURTSELF 0x40 // Flag - can hurt self/team indirectly, such as through mines
#define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type
void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period);
void P_ForceConstant(const BasicFF_t *FFInfo);
void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End);
void P_RemoveShield(player_t *player);
void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source);
boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype);

View file

@ -262,13 +262,15 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
}
else
{
INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // Not identical to below...
INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING|PF_CANCARRY); // Not identical to below...
UINT8 secondjump = object->player->secondjump;
UINT16 tailsfly = object->player->powers[pw_tailsfly];
if (object->player->pflags & PF_GLIDING)
P_SetPlayerMobjState(object, S_PLAY_FALL);
P_ResetPlayer(object->player);
object->player->pflags |= pflags;
object->player->secondjump = secondjump;
object->player->powers[pw_tailsfly] = tailsfly;
}
}

View file

@ -3989,12 +3989,11 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
{
//(void)mobj;
mobj->precipflags &= ~PCF_THUNK;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
void P_SnowThinker(precipmobj_t *mobj)
{
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj);
// adjust height
@ -4007,8 +4006,6 @@ void P_SnowThinker(precipmobj_t *mobj)
void P_RainThinker(precipmobj_t *mobj)
{
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state != &states[S_RAIN1])
@ -11852,7 +11849,6 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
case MT_EMERHUNT:
case MT_EMERALDSPAWN:
case MT_TOKEN:
case MT_EMBLEM:
case MT_RING:
case MT_REDTEAMRING:
case MT_BLUETEAMRING:
@ -11864,6 +11860,10 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
offset += mthing->args[0] ? 0 : 24*FRACUNIT;
break;
case MT_EMBLEM:
offset += mthing->args[1] ? 0 : 24 * FRACUNIT;
break;
// Remaining objects.
default:
if (P_WeaponOrPanel(mobjtype))
@ -13280,6 +13280,23 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
return true;
}
// Pre-UDMF backwards compatibility stuff. Remove for 2.3
static void P_SetAmbush(mapthing_t *mthing, mobj_t *mobj)
{
if (mobj->type == MT_NIGHTSBUMPER
|| mobj->type == MT_AXIS
|| mobj->type == MT_AXISTRANSFER
|| mobj->type == MT_AXISTRANSFERLINE
|| mobj->type == MT_NIGHTSBUMPER
|| mobj->type == MT_STARPOST)
return;
if ((mthing->options & MTF_OBJECTSPECIAL) && (mobj->flags & MF_PUSHABLE))
return;
mobj->flags2 |= MF2_AMBUSH;
}
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i)
{
mobj_t *mobj = NULL;
@ -13302,6 +13319,9 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
mthing->mobj = mobj;
if (!udmf && (mthing->options & MTF_AMBUSH))
P_SetAmbush(mthing, mobj);
// Generic reverse gravity for individual objects flag.
if (mthing->options & MTF_OBJECTFLIP)
{

View file

@ -1761,7 +1761,14 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
else if (fastcmp(param, "triggertag"))
sectors[i].triggertag = atol(val);
else if (fastcmp(param, "triggerer"))
sectors[i].triggerer = atol(val);
{
if (fastcmp(val, "Player"))
sectors[i].triggerer = TO_PLAYER;
if (fastcmp(val, "AllPlayers"))
sectors[i].triggerer = TO_ALLPLAYERS;
if (fastcmp(val, "Mobj"))
sectors[i].triggerer = TO_MOBJ;
}
}
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
@ -2263,6 +2270,9 @@ static void P_WriteTextmap(void)
case 10:
CONS_Alert(CONS_WARNING, M_GetText("Sector %s has ring drainer effect, which is not supported in UDMF. Use linedef type 462 instead.\n"), sizeu1(i));
break;
case 15:
CONS_Alert(CONS_WARNING, M_GetText("Sector %s has bouncy FOF effect, which is not supported in UDMF. Use linedef type 76 instead.\n"), sizeu1(i));
break;
default:
break;
}
@ -2278,6 +2288,12 @@ static void P_WriteTextmap(void)
case 9:
CONS_Alert(CONS_WARNING, M_GetText("Sector %s has Egg Capsule type, which is not supported in UDMF. Use linedef type 464 instead.\n"), sizeu1(i));
break;
case 10:
CONS_Alert(CONS_WARNING, M_GetText("Sector %s has special stage time/spheres requirements effect, which is not supported in UDMF. Use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"), sizeu1(i));
break;
case 11:
CONS_Alert(CONS_WARNING, M_GetText("Sector %s has custom global gravity effect, which is not supported in UDMF. Use the Gravity level header option instead.\n"), sizeu1(i));
break;
default:
break;
}
@ -2633,7 +2649,22 @@ static void P_WriteTextmap(void)
if (wsectors[i].triggertag != 0)
fprintf(f, "triggertag = %d;\n", wsectors[i].triggertag);
if (wsectors[i].triggerer != 0)
fprintf(f, "triggerer = %d;\n", wsectors[i].triggerer);
{
switch (wsectors[i].triggerer)
{
case TO_PLAYER:
fprintf(f, "triggerer = \"Player\";\n");
break;
case TO_ALLPLAYERS:
fprintf(f, "triggerer = \"AllPlayers\";\n");
break;
case TO_MOBJ:
fprintf(f, "triggerer = \"Mobj\";\n");
break;
default:
break;
}
}
fprintf(f, "}\n");
fprintf(f, "\n");
}
@ -4187,7 +4218,8 @@ static void P_ConvertBinaryLinedefTypes(void)
lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS;
lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD);
P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]);
if (sides[lines[i].sidenum[0]].toptexture)
P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]);
break;
case 16: //Minecart parameters
lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
@ -5986,6 +6018,9 @@ static void P_ConvertBinarySectorTypes(void)
case 14: //Non-ramp sector
sectors[i].specialflags |= SSF_NOSTEPDOWN;
break;
case 15: //Bouncy FOF
CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n"));
break;
default:
break;
}
@ -6018,11 +6053,13 @@ static void P_ConvertBinarySectorTypes(void)
sectors[i].triggerer = TO_PLAYER;
break;
case 6: //Trigger linedef executor (Emerald check)
CONS_Alert(CONS_WARNING, M_GetText("Deprecated emerald check sector type detected. Please use linedef types 337-339 instead.\n"));
sectors[i].triggertag = tag;
sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE;
sectors[i].triggerer = TO_PLAYEREMERALDS;
break;
case 7: //Trigger linedef executor (NiGHTS mare)
CONS_Alert(CONS_WARNING, M_GetText("Deprecated NiGHTS mare sector type detected. Please use linedef types 340-342 instead.\n"));
sectors[i].triggertag = tag;
sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE;
sectors[i].triggerer = TO_PLAYERNIGHTS;
@ -6030,6 +6067,12 @@ static void P_ConvertBinarySectorTypes(void)
case 8: //Check for linedef executor on FOFs
sectors[i].flags |= MSF_TRIGGERLINE_MOBJ;
break;
case 10: //Special stage time/spheres requirements
CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for special stage requirements detected. Please use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"));
break;
case 11: //Custom global gravity
CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for global gravity detected. Please use the Gravity level header option instead.\n"));
break;
default:
break;
}
@ -6266,7 +6309,6 @@ static void P_ConvertBinaryThingTypes(void)
case 312: //Emerald token
case 320: //Emerald hunt location
case 321: //Match chaos emerald spawn
case 322: //Emblem
case 330: //Bounce ring panel
case 331: //Rail ring panel
case 332: //Automatic ring panel
@ -6279,6 +6321,9 @@ static void P_ConvertBinaryThingTypes(void)
case 1800: //Coin
mapthings[i].args[0] = !(mapthings[i].options & MTF_AMBUSH);
break;
case 322: //Emblem
mapthings[i].args[1] = !(mapthings[i].options & MTF_AMBUSH);
break;
case 409: //Extra life monitor
mapthings[i].args[2] = !(mapthings[i].options & (MTF_AMBUSH|MTF_OBJECTSPECIAL));
break;

View file

@ -1760,13 +1760,11 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
{
if (caller->triggerer == TO_PLAYEREMERALDS)
{
CONS_Alert(CONS_WARNING, M_GetText("Deprecated emerald check sector type detected. Please use linedef types 337-339 instead.\n"));
if (!(ALL7EMERALDS(emeralds)))
return false;
}
else if (caller->triggerer == TO_PLAYERNIGHTS)
{
CONS_Alert(CONS_WARNING, M_GetText("Deprecated NiGHTS mare sector type detected. Please use linedef types 340-342 instead.\n"));
if (!P_CheckPlayerMareOld(triggerline))
return false;
}
@ -4180,6 +4178,29 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number)
return NULL;
}
// Deprecated in favor of P_MobjTouchingSectorSpecial
// Kept for Lua backwards compatibility only
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
{
ffloor_t *rover;
for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{
if (!rover->master->frontsector->special)
continue;
if (!(rover->fofflags & FOF_EXISTS))
continue;
if (!P_IsMobjTouching3DFloor(mo, rover, mo->subsector->sector))
continue;
return rover->master->frontsector;
}
return NULL;
}
sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag)
{
msecnode_t *node;
@ -4375,7 +4396,7 @@ sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline)
return loopsector;
}
return false;
return NULL;
}
boolean P_IsPlayerValid(size_t playernum)
@ -4579,6 +4600,9 @@ static void P_ProcessExitSector(player_t *player, mtag_t sectag)
if (player->bot)
return;
if (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))
return;
// Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c)
P_DoPlayerFinish(player);
@ -4627,7 +4651,7 @@ static void P_ProcessTeamBase(player_t *player, boolean redteam)
// Make sure the team still has their own
// flag at their base so they can score.
if (!P_IsFlagAtBase(redteam ? MT_BLUEFLAG : MT_REDFLAG))
if (!P_IsFlagAtBase(redteam ? MT_REDFLAG : MT_BLUEFLAG))
return;
HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE);
@ -5944,8 +5968,6 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
{
elevator_t *elevator; // Why not? LOL
CONS_Alert(CONS_WARNING, M_GetText("Detected a camera scanner effect (linedef type 5). This effect is deprecated and will be removed in the future!\n"));
// create and initialize new elevator thinker
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
P_AddThinker(THINK_MAIN, &elevator->thinker);
@ -6200,22 +6222,21 @@ void P_SpawnSpecials(boolean fromnetsave)
circuitmap = true;
}
if (!sector->special)
if (sector->damagetype == SD_SPIKE) {
//Terrible hack to replace an even worse hack:
//Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH.
//Yes, this also affects other specials on the same sector. Sorry.
sector->flags |= MSF_TRIGGERSPECIAL_TOUCH;
}
// Process deprecated binary sector specials
if (udmf || !sector->special)
continue;
// Process Section 1
switch(GETSECSPECIAL(sector->special, 1))
{
case 5: // Spikes
//Terrible hack to replace an even worse hack:
//Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH.
//Yes, this also affects other specials on the same sector. Sorry.
sector->flags |= MSF_TRIGGERSPECIAL_TOUCH;
break;
case 15: // Bouncy FOF
if (udmf)
break;
CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n"));
CheckForBouncySector = true;
break;
}
@ -6224,17 +6245,11 @@ void P_SpawnSpecials(boolean fromnetsave)
switch(GETSECSPECIAL(sector->special, 2))
{
case 10: // Time for special stage
if (udmf)
break;
CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for special stage requirements detected. Please use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"));
sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish
ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage
break;
case 11: // Custom global gravity!
if (udmf)
break;
CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for global gravity detected. Please use the Gravity level header option instead.\n"));
gravity = sector->floorheight/1000;
break;
}

View file

@ -496,6 +496,7 @@ void P_SpawnSpecials(boolean fromnetsave);
// every tic
void P_UpdateSpecials(void);
sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number);
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);
sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag);
sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number);
sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag);

View file

@ -1,4 +1,3 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
@ -3108,14 +3107,25 @@ static void P_DoPlayerHeadSigns(player_t *player)
if (G_TagGametype())
{
// If you're "IT", show a big "IT" over your head for others to see.
if (player->pflags & PF_TAGIT)
if (player->pflags & PF_TAGIT && !P_IsLocalPlayer(player))
{
if (!P_IsLocalPlayer(player)) // Don't display it on your own view.
mobj_t* it = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG);
it->x = player->mo->x;
it->y = player->mo->y;
it->z = player->mo->z;
it->old_x = player->mo->old_x;
it->old_y = player->mo->old_y;
it->old_z = player->mo->old_z;
if (!(player->mo->eflags & MFE_VERTICALFLIP))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP))
P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height, MT_TAG);
else
P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z - mobjinfo[MT_TAG].height, MT_TAG)->eflags |= MFE_VERTICALFLIP;
it->z += player->mo->height;
it->old_z += player->mo->height;
}
else
{
it->z -= mobjinfo[MT_TAG].height;
it->old_z -= mobjinfo[MT_TAG].height;
}
}
}
@ -3125,15 +3135,32 @@ static void P_DoPlayerHeadSigns(player_t *player)
// has it (but not on your own screen if you have the flag).
if (splitscreen || player != &players[consoleplayer])
{
mobj_t *sign = P_SpawnMobj(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy,
player->mo->z+player->mo->momz, MT_GOTFLAG);
if (player->mo->eflags & MFE_VERTICALFLIP)
fixed_t zofs;
mobj_t *sign;
boolean player_is_flipped = (player->mo->eflags & MFE_VERTICALFLIP) > 0;
zofs = player->mo->momz;
if (player_is_flipped)
{
sign->z += player->mo->height-P_GetPlayerHeight(player)-mobjinfo[MT_GOTFLAG].height-FixedMul(16*FRACUNIT, player->mo->scale);
sign->eflags |= MFE_VERTICALFLIP;
zofs += player->mo->height - P_GetPlayerHeight(player) - mobjinfo[MT_GOTFLAG].height - FixedMul(16 * FRACUNIT, player->mo->scale);
}
else
sign->z += P_GetPlayerHeight(player)+FixedMul(16*FRACUNIT, player->mo->scale);
{
zofs += P_GetPlayerHeight(player) + FixedMul(16 * FRACUNIT, player->mo->scale);
}
sign = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_GOTFLAG);
sign->x = player->mo->x;
sign->y = player->mo->y;
sign->z = player->mo->z + zofs;
sign->old_x = player->mo->old_x;
sign->old_y = player->mo->old_y;
sign->old_z = player->mo->old_z + zofs;
if (player_is_flipped)
{
sign->eflags |= MFE_VERTICALFLIP;
}
if (player->gotflag & GF_REDFLAG)
sign->frame = 1|FF_FULLBRIGHT;
@ -5331,9 +5358,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
// disabled because it seemed to disorient people and Z-targeting exists now
/*if (!demoplayback)
{
if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(G_PlayerInputDown(0, GC_TURNLEFT) || G_PlayerInputDown(0, GC_TURNRIGHT)))
if (player == &players[consoleplayer] && cv_cam_turnfacingability[0].value > 0 && !(PLAYER1INPUTDOWN(GC_TURNLEFT) || PLAYER1INPUTDOWN(GC_TURNRIGHT)))
P_SetPlayerAngle(player, player->mo->angle);;
else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(G_PlayerInputDown(1, GC_TURNLEFT) || G_PlayerInputDown(1, GC_TURNRIGHT)))
else if (player == &players[secondarydisplayplayer] && cv_cam_turnfacingability[1].value > 0 && !(PLAYER2INPUTDOWN(GC_TURNLEFT) || PLAYER2INPUTDOWN(GC_TURNRIGHT)))
P_SetPlayerAngle(player, player->mo->angle);
}*/
}
@ -7342,7 +7369,7 @@ static void P_NiGHTSMovement(player_t *player)
else if (cmd->forwardmove < 0)
newangle = 270;
}
else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axes.
else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axises.
newangle = (INT16)FixedInt(AngleFixed(R_PointToAngle2(0,0, cmd->sidemove*FRACUNIT, cmd->forwardmove*FRACUNIT)));
newangle -= player->viewrollangle / ANG1;
@ -11038,6 +11065,21 @@ static void P_MinecartThink(player_t *player)
S_StartSound(minecart, minecart->info->activesound);
}
}
// Mark interpolation; the old positions need to be relative to the displacement from the minecart _after_ it's moved.
// This isn't quite correct (it captures the landing wobble) but it works well enough
if (detleft)
{
detleft->old_x = detleft->x - (minecart->old_x - minecart->old_x2);
detleft->old_y = detleft->y - (minecart->old_y - minecart->old_y2);
detleft->old_z = detleft->z - (minecart->old_z - minecart->old_z2);
}
if (detright)
{
detright->old_x = detright->x - (minecart->old_x - minecart->old_x2);
detright->old_y = detright->y - (minecart->old_y - minecart->old_y2);
detright->old_z = detright->z - (minecart->old_z - minecart->old_z2);
}
}
else
{
@ -11266,6 +11308,11 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails)
tails->y = player->mo->y + P_ReturnThrustY(tails, tails->angle, FixedMul(backwards, tails->scale));
tails->z = player->mo->z + zoffs;
P_SetThingPosition(tails);
if (player->mo->flags2 & MF2_SHADOW)
tails->flags2 |= MF2_SHADOW;
else
tails->flags2 &= ~MF2_SHADOW;
}
// Metal Sonic's jet fume
@ -12013,7 +12060,6 @@ void P_PlayerThink(player_t *player)
P_DoBubbleBreath(player); // Spawn Sonic's bubbles
P_CheckUnderwaterAndSpaceTimer(player); // Display the countdown drown numbers!
P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles
P_DoPlayerHeadSigns(player); // Spawn Tag/CTF signs over player's head
#if 1
// "Blur" a bit when you have speed shoes and are going fast enough
@ -12878,6 +12924,8 @@ void P_PlayerAfterThink(player_t *player)
}
}
}
P_DoPlayerHeadSigns(player); // Spawn Tag/CTF signs over player's head
}
void P_SetPlayerAngle(player_t *player, angle_t angle)

View file

@ -621,7 +621,13 @@ void SCR_ClosedCaptions(void)
y = basey-((i + 2)*10);
if (closedcaptions[i].b)
y -= (closedcaptions[i].b--)*vid.dupy;
{
y -= closedcaptions[i].b * vid.dupy;
if (renderisnewtic)
{
closedcaptions[i].b--;
}
}
if (closedcaptions[i].t < CAPTIONFADETICS)
flags |= (((CAPTIONFADETICS-closedcaptions[i].t)/2)*V_10TRANS);

View file

@ -2,7 +2,6 @@ i_net.c
i_system.c
i_main.c
i_video.c
i_gamepad.c
dosstr.c
endtxt.c
hwsym_sdl.c

View file

@ -1,963 +0,0 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file i_gamepad.c
/// \brief Gamepads
#ifdef HAVE_SDL
#include "../i_gamepad.h"
#include "../i_system.h"
#include "../doomdef.h"
#include "../d_main.h"
#include "../d_netcmd.h"
#include "../g_game.h"
#include "../m_argv.h"
#include "../m_menu.h"
#include "../z_zone.h"
#include "SDL.h"
#include "SDL_joystick.h"
#include "sdlmain.h"
static void Controller_ChangeDevice(UINT8 num);
static void Controller_Close(UINT8 num);
static void Controller_StopRumble(UINT8 num);
static ControllerInfo controllers[NUM_GAMEPADS];
static boolean rumble_supported = false;
static boolean rumble_paused = false;
// This attempts to initialize the gamepad subsystems
static boolean InitGamepadSubsystems(void)
{
if (M_CheckParm("-noxinput"))
SDL_SetHintWithPriority(SDL_HINT_XINPUT_ENABLED, "0", SDL_HINT_OVERRIDE);
#if SDL_VERSION_ATLEAST(2,0,9)
if (M_CheckParm("-nohidapi"))
SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_HIDAPI, "0", SDL_HINT_OVERRIDE);
#endif
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == 0)
{
if (SDL_InitSubSystem(GAMEPAD_INIT_FLAGS) == -1)
{
CONS_Printf(M_GetText("Couldn't initialize game controller subsystems: %s\n"), SDL_GetError());
return false;
}
}
return true;
}
void I_InitGamepads(void)
{
if (M_CheckParm("-nojoy"))
return;
CONS_Printf("I_InitGamepads()...\n");
if (!InitGamepadSubsystems())
return;
#if SDL_VERSION_ATLEAST(2,0,9)
rumble_supported = !M_CheckParm("-norumble");
#else
rumble_supported = false;
#endif
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
controllers[i].info = &gamepads[i];
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
Controller_ChangeDevice(i);
}
INT32 I_NumGamepads(void)
{
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS)
return SDL_NumJoysticks();
else
return 0;
}
// From the SDL source code
#define USB_VENDOR_MICROSOFT 0x045e
#define USB_VENDOR_PDP 0x0e6f
#define USB_VENDOR_POWERA_ALT 0x20d6
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 0x02e3
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 0x0b00
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH 0x0b05
#define USB_PRODUCT_XBOX_SERIES_X 0x0b12
#define USB_PRODUCT_XBOX_SERIES_X_BLE 0x0b13
#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT 0x02d6
#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE 0x02d9
#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW 0x02da
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002
#if SDL_VERSION_ATLEAST(2,0,6)
static boolean IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
return true;
}
}
return false;
}
static boolean IsJoystickXboxSeriesXS(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_SERIES_X ||
product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) {
return true;
}
}
else if (vendor_id == USB_VENDOR_PDP) {
if (product_id == USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT ||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE ||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW) {
return true;
}
}
else if (vendor_id == USB_VENDOR_POWERA_ALT) {
if ((product_id >= 0x2001 && product_id <= 0x201a) ||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 ||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA) {
return true;
}
}
return false;
}
#endif
// Opens a controller device
static boolean Controller_OpenDevice(UINT8 which, INT32 devindex)
{
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == 0)
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Game controller subsystems not started\n"));
return false;
}
if (devindex <= 0)
return false;
if (SDL_NumJoysticks() == 0)
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Found no controllers on this system\n"));
return false;
}
devindex--;
if (!SDL_IsGameController(devindex))
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Device index %d isn't a game controller\n"), devindex);
return false;
}
ControllerInfo *controller = &controllers[which];
SDL_GameController *newdev = SDL_GameControllerOpen(devindex);
// Handle the edge case where the device <-> controller index assignment can change due to hotplugging
// This indexing is SDL's responsibility and there's not much we can do about it.
//
// Example:
// 1. Plug Controller A -> Index 0 opened
// 2. Plug Controller B -> Index 1 opened
// 3. Unplug Controller A -> Index 0 closed, Index 1 active
// 4. Unplug Controller B -> Index 0 inactive, Index 1 closed
// 5. Plug Controller B -> Index 0 opened
// 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B
if (controller->dev)
{
if (controller->dev == newdev // same device, nothing to do
|| (newdev == NULL && SDL_GameControllerGetAttached(controller->dev))) // we failed, but already have a working device
return true;
// Else, we're changing devices, so close the controller
CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d device is changing; closing controller...\n"), which);
Controller_Close(which);
}
if (newdev == NULL)
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d: Couldn't open device - %s\n"), which, SDL_GetError());
controller->started = false;
}
else
{
controller->dev = newdev;
controller->joydev = SDL_GameControllerGetJoystick(controller->dev);
controller->started = true;
CONS_Debug(DBG_GAMELOGIC, M_GetText("Controller %d: %s\n"), which, SDL_GameControllerName(controller->dev));
#if SDL_VERSION_ATLEAST(2,0,12)
#define GAMEPAD_TYPE_CASE(ctrl) \
case SDL_CONTROLLER_TYPE_##ctrl: \
controller->info->type = GAMEPAD_TYPE_##ctrl; \
break
switch (SDL_GameControllerGetType(newdev))
{
GAMEPAD_TYPE_CASE(UNKNOWN);
GAMEPAD_TYPE_CASE(XBOX360);
GAMEPAD_TYPE_CASE(XBOXONE);
GAMEPAD_TYPE_CASE(PS3);
GAMEPAD_TYPE_CASE(PS4);
#if SDL_VERSION_ATLEAST(2,0,14)
GAMEPAD_TYPE_CASE(PS5);
#endif
GAMEPAD_TYPE_CASE(NINTENDO_SWITCH_PRO);
#if SDL_VERSION_ATLEAST(2,0,16)
GAMEPAD_TYPE_CASE(GOOGLE_STADIA);
GAMEPAD_TYPE_CASE(AMAZON_LUNA);
#endif
GAMEPAD_TYPE_CASE(VIRTUAL);
default: break;
}
#undef GAMEPAD_BUTTON_CASE
#else
// Under older versions of SDL, we aren't provided controller type information.
controller->info->type = GAMEPAD_TYPE_UNKNOWN;
#endif // SDL_VERSION_ATLEAST(2,0,12)
#if SDL_VERSION_ATLEAST(2,0,6)
// Check the device vendor and product to find out what controller this actually is
Uint16 vendor = SDL_JoystickGetDeviceVendor(devindex);
Uint16 product = SDL_JoystickGetDeviceProduct(devindex);
if (IsJoystickXboxSeriesXS(vendor, product))
controller->info->type = GAMEPAD_TYPE_XBOX_SERIES_XS;
else if (IsJoystickXboxOneElite(vendor, product))
controller->info->type = GAMEPAD_TYPE_XBOX_ELITE;
#endif
CONS_Debug(DBG_GAMELOGIC, M_GetText(" Type: %s\n"), G_GamepadTypeToString(controller->info->type));
#if SDL_VERSION_ATLEAST(2,0,12)
// Change the ring LEDs on Xbox 360 controllers
// FIXME: Doesn't seem to work?
SDL_GameControllerSetPlayerIndex(controller->dev, which);
#endif
#if SDL_VERSION_ATLEAST(2,0,18)
// Check if rumble is supported
if (SDL_GameControllerHasRumble(controller->dev) == SDL_TRUE)
{
controller->info->rumble.supported = true;
CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: Yes\n"));
}
else
{
controller->info->rumble.supported = false;
CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: No\n"));
}
#else
controller->info->rumble.supported = true;
CONS_Debug(DBG_GAMELOGIC, M_GetText(" Rumble supported: Maybe\n"));
#endif // SDL_VERSION_ATLEAST(2,0,18)
if (!controller->info->connected)
{
controller->info->connected = true;
G_OnGamepadConnect(which);
}
}
return controller->started;
}
// Initializes a controller
static INT32 Controller_Init(SDL_GameController **newcontroller, UINT8 which, INT32 *index)
{
ControllerInfo *info = &controllers[which];
SDL_GameController *controller = NULL;
INT32 device = (*index);
if (device && SDL_IsGameController(device - 1))
controller = SDL_GameControllerOpen(device - 1);
if (newcontroller)
(*newcontroller) = controller;
if (controller && info->dev == controller) // don't override an active device
(*index) = I_GetControllerIndex(info->dev) + 1;
else if (controller && Controller_OpenDevice(which, device))
{
// SDL's device indexes are unstable, so cv_usegamepad may not match
// the actual device index. So let's cheat a bit and find the device's current index.
info->lastindex = I_GetControllerIndex(info->dev) + 1;
return 1;
}
else
{
(*index) = 0;
return 0;
}
return -1;
}
// Changes a controller's device
static void Controller_ChangeDevice(UINT8 num)
{
SDL_GameController *newjoy = NULL;
if (!Controller_Init(&newjoy, num, &cv_usegamepad[num].value) && controllers[num].lastindex)
Controller_Close(num);
I_CloseInactiveController(newjoy);
}
static boolean Controller_IsAnyUsingDevice(SDL_GameController *dev)
{
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
if (controllers[i].dev == dev)
return true;
}
return false;
}
static boolean Controller_IsAnyOtherUsingDevice(SDL_GameController *dev, UINT8 thisjoy)
{
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
if (i == thisjoy)
continue;
else if (controllers[i].dev == dev)
return true;
}
return false;
}
void I_ControllerDeviceAdded(INT32 which)
{
if (!SDL_IsGameController(which))
return;
SDL_GameController *newjoy = SDL_GameControllerOpen(which);
CONS_Debug(DBG_GAMELOGIC, "Gamepad device index %d added\n", which + 1);
// Because SDL's device index is unstable, we're going to cheat here a bit:
// For the first controller setting that is NOT active:
// 1. Set cv_usegamepadX.value to the new device index (this does not change what is written to config.cfg)
// 2. Set OTHERS' cv_usegamepadX.value to THEIR new device index, because it likely changed
// * If device doesn't exist, switch cv_usegamepad back to default value (.string)
// * BUT: If that default index is being occupied, use ANOTHER cv_usegamepad's default value!
for (UINT8 this = 0; this < NUM_GAMEPADS && newjoy; this++)
{
if ((!controllers[this].dev || !SDL_GameControllerGetAttached(controllers[this].dev))
&& !Controller_IsAnyOtherUsingDevice(newjoy, this)) // don't override a currently active device
{
cv_usegamepad[this].value = which + 1;
// Go through every other device
for (UINT8 other = 0; other < NUM_GAMEPADS; other++)
{
if (other == this)
{
// Don't change this controller's index
continue;
}
else if (controllers[other].dev)
{
// Update this controller's index if the device is open
cv_usegamepad[other].value = I_GetControllerIndex(controllers[other].dev) + 1;
}
else if (atoi(cv_usegamepad[other].string) != controllers[this].lastindex
&& atoi(cv_usegamepad[other].string) != cv_usegamepad[this].value)
{
// If the user-set index for the other controller doesn't
// match this controller's current or former internal index,
// then use the other controller's internal index
cv_usegamepad[other].value = atoi(cv_usegamepad[other].string);
}
else if (atoi(cv_usegamepad[this].string) != controllers[this].lastindex
&& atoi(cv_usegamepad[this].string) != cv_usegamepad[this].value)
{
// If the user-set index for this controller doesn't match
// its current or former internal index, then use this
// controller's internal index
cv_usegamepad[other].value = atoi(cv_usegamepad[this].string);
}
else
{
// Try again
cv_usegamepad[other].value = 0;
continue;
}
break;
}
break;
}
}
// Was cv_usegamepad disabled in settings?
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
if (!strcmp(cv_usegamepad[i].string, "0") || !cv_usegamepad[i].value)
cv_usegamepad[i].value = 0;
else if (atoi(cv_usegamepad[i].string) <= I_NumGamepads() // don't mess if we intentionally set higher than NumJoys
&& cv_usegamepad[i].value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usegamepad[i], cv_usegamepad[i].value);
}
// Update all gamepads' init states
// This is a little wasteful since cv_usegamepad already calls this, but
// we need to do this in case CV_SetValue did nothing because the string was already same.
// if the device is already active, this should do nothing, effectively.
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
Controller_ChangeDevice(i);
CONS_Debug(DBG_GAMELOGIC, "Controller %d device index: %d\n", i, controllers[i].lastindex);
}
if (M_OnGamepadMenu())
M_UpdateGamepadMenu();
I_CloseInactiveController(newjoy);
}
void I_ControllerDeviceRemoved(void)
{
for (UINT8 this = 0; this < NUM_GAMEPADS; this++)
{
if (controllers[this].dev && !SDL_GameControllerGetAttached(controllers[this].dev))
{
CONS_Debug(DBG_GAMELOGIC, "Controller %d removed, device index: %d\n", this, controllers[this].lastindex);
G_OnGamepadDisconnect(this);
Controller_Close(this);
}
// Update the device indexes, because they likely changed
// * If device doesn't exist, switch cv_usegamepad back to default value (.string)
// * BUT: If that default index is being occupied, use ANOTHER cv_usegamepad's default value!
if (controllers[this].dev)
cv_usegamepad[this].value = controllers[this].lastindex = I_GetControllerIndex(controllers[this].dev) + 1;
else
{
for (UINT8 other = 0; other < NUM_GAMEPADS; other++)
{
if (other == this)
continue;
if (atoi(cv_usegamepad[this].string) != controllers[other].lastindex)
{
// Update this internal index if this user-set index
// doesn't match the other's former internal index
cv_usegamepad[this].value = atoi(cv_usegamepad[this].string);
}
else if (atoi(cv_usegamepad[other].string) != controllers[other].lastindex)
{
// Otherwise, set this internal index to the other's
// user-set index, if the other user-set index is not the
// same as the other's former internal index
cv_usegamepad[this].value = atoi(cv_usegamepad[other].string);
}
else
{
// Try again
cv_usegamepad[this].value = 0;
continue;
}
break;
}
}
// Was cv_usegamepad disabled in settings?
if (!strcmp(cv_usegamepad[this].string, "0"))
cv_usegamepad[this].value = 0;
else if (atoi(cv_usegamepad[this].string) <= I_NumGamepads() // don't mess if we intentionally set higher than NumJoys
&& cv_usegamepad[this].value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usegamepad[this], cv_usegamepad[this].value);
CONS_Debug(DBG_GAMELOGIC, "Controller %d device index: %d\n", this, controllers[this].lastindex);
}
if (M_OnGamepadMenu())
M_UpdateGamepadMenu();
}
// Close the controller device if there isn't any controller using it
void I_CloseInactiveController(SDL_GameController *dev)
{
if (!Controller_IsAnyUsingDevice(dev))
SDL_GameControllerClose(dev);
}
// Cheat to get the device index for a game controller handle
INT32 I_GetControllerIndex(SDL_GameController *dev)
{
INT32 i, count = SDL_NumJoysticks();
for (i = 0; dev && i < count; i++)
{
SDL_GameController *test = SDL_GameControllerOpen(i);
if (test && test == dev)
return i;
else
I_CloseInactiveController(test);
}
return -1;
}
// Changes a gamepad's device
void I_ChangeGamepad(UINT8 which)
{
if (which >= NUM_GAMEPADS)
return;
if (controllers[which].started)
Controller_StopRumble(which);
Controller_ChangeDevice(which);
}
// Returns the name of a controller from its index
const char *I_GetGamepadName(INT32 joyindex)
{
static char joyname[256];
joyname[0] = '\0';
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS)
{
const char *tempname = SDL_GameControllerNameForIndex(joyindex - 1);
if (tempname)
strlcpy(joyname, tempname, sizeof joyname);
}
return joyname;
}
// Toggles a gamepad's digital axis setting
void I_SetGamepadDigital(UINT8 which, boolean enable)
{
if (which >= NUM_GAMEPADS)
return;
gamepads[which].digital = enable;
}
static gamepad_t *Controller_GetFromID(SDL_JoystickID which, UINT8 *found)
{
// Determine the joystick IDs for each current open controller
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
if (which == SDL_JoystickInstanceID(controllers[i].joydev))
{
(*found) = i;
return &gamepads[i];
}
}
(*found) = UINT8_MAX;
return NULL;
}
void I_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type)
{
event_t event;
gamepad_t *gamepad = Controller_GetFromID(evt.which, &event.which);
if (gamepad == NULL)
return;
if (type == SDL_CONTROLLERBUTTONUP)
event.type = ev_gamepad_up;
else if (type == SDL_CONTROLLERBUTTONDOWN)
event.type = ev_gamepad_down;
else
return;
#define GAMEPAD_BUTTON_CASE(btn) \
case SDL_CONTROLLER_BUTTON_##btn: \
event.key = GAMEPAD_BUTTON_##btn; \
break
switch (evt.button)
{
GAMEPAD_BUTTON_CASE(A);
GAMEPAD_BUTTON_CASE(B);
GAMEPAD_BUTTON_CASE(X);
GAMEPAD_BUTTON_CASE(Y);
GAMEPAD_BUTTON_CASE(BACK);
GAMEPAD_BUTTON_CASE(GUIDE);
GAMEPAD_BUTTON_CASE(START);
GAMEPAD_BUTTON_CASE(LEFTSTICK);
GAMEPAD_BUTTON_CASE(RIGHTSTICK);
GAMEPAD_BUTTON_CASE(LEFTSHOULDER);
GAMEPAD_BUTTON_CASE(RIGHTSHOULDER);
GAMEPAD_BUTTON_CASE(DPAD_UP);
GAMEPAD_BUTTON_CASE(DPAD_DOWN);
GAMEPAD_BUTTON_CASE(DPAD_LEFT);
GAMEPAD_BUTTON_CASE(DPAD_RIGHT);
#if SDL_VERSION_ATLEAST(2,0,14)
GAMEPAD_BUTTON_CASE(MISC1);
GAMEPAD_BUTTON_CASE(PADDLE1);
GAMEPAD_BUTTON_CASE(PADDLE2);
GAMEPAD_BUTTON_CASE(PADDLE3);
GAMEPAD_BUTTON_CASE(PADDLE4);
GAMEPAD_BUTTON_CASE(TOUCHPAD);
#endif
default: return;
}
#undef GAMEPAD_BUTTON_CASE
D_PostEvent(&event);
}
void I_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt)
{
event_t event;
gamepad_t *gamepad = Controller_GetFromID(evt.which, &event.which);
if (gamepad == NULL)
return;
#define GAMEPAD_AXIS_CASE(btn) \
case SDL_CONTROLLER_AXIS_##btn: \
event.key = GAMEPAD_AXIS_##btn; \
break
switch (evt.axis)
{
GAMEPAD_AXIS_CASE(LEFTX);
GAMEPAD_AXIS_CASE(LEFTY);
GAMEPAD_AXIS_CASE(RIGHTX);
GAMEPAD_AXIS_CASE(RIGHTY);
GAMEPAD_AXIS_CASE(TRIGGERLEFT);
GAMEPAD_AXIS_CASE(TRIGGERRIGHT);
default: return;
}
#undef GAMEPAD_AXIS_CASE
event.type = ev_gamepad_axis;
event.x = evt.value;
D_PostEvent(&event);
}
static void Controller_StopRumble(UINT8 num)
{
ControllerInfo *controller = &controllers[num];
controller->rumble.large_magnitude = 0;
controller->rumble.small_magnitude = 0;
controller->rumble.time_left = 0;
controller->rumble.expiration = 0;
gamepad_t *gamepad = controller->info;
gamepad->rumble.active = false;
gamepad->rumble.paused = false;
gamepad->rumble.data.large_magnitude = 0;
gamepad->rumble.data.small_magnitude = 0;
gamepad->rumble.data.duration = 0;
#if SDL_VERSION_ATLEAST(2,0,9)
if (gamepad->rumble.supported)
SDL_GameControllerRumble(controller->dev, 0, 0, 0);
#endif
}
static void Controller_Close(UINT8 num)
{
ControllerInfo *controller = &controllers[num];
// Close the game controller device
if (controller->dev)
{
Controller_StopRumble(num);
SDL_GameControllerClose(controller->dev);
}
controller->dev = NULL;
controller->joydev = NULL;
controller->lastindex = -1;
controller->started = false;
// Reset gamepad info
gamepad_t *gamepad = controller->info;
if (gamepad)
{
gamepad->type = GAMEPAD_TYPE_UNKNOWN;
gamepad->connected = false;
gamepad->digital = false;
gamepad->rumble.supported = false;
for (UINT8 i = 0; i < NUM_GAMEPAD_BUTTONS; i++)
gamepad->buttons[i] = 0;
for (UINT8 i = 0; i < NUM_GAMEPAD_AXES; i++)
gamepad->axes[i] = 0;
}
}
void I_ShutdownGamepads(void)
{
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
Controller_Close(i);
}
boolean I_RumbleSupported(void)
{
return rumble_supported;
}
static boolean Controller_Rumble(ControllerInfo *c)
{
#if SDL_VERSION_ATLEAST(2,0,9)
if (SDL_GameControllerRumble(c->dev, c->rumble.large_magnitude, c->rumble.small_magnitude, 0) == -1)
return false;
return true;
#else
(void)c;
return false;
#endif
}
void I_ToggleControllerRumble(boolean unpause)
{
#if SDL_VERSION_ATLEAST(2,0,9)
if (!I_RumbleSupported() || rumble_paused == !unpause)
return;
rumble_paused = !unpause;
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
ControllerInfo *controller = &controllers[i];
if (!controller->started || !controller->info->rumble.supported)
continue;
if (rumble_paused)
SDL_GameControllerRumble(controller->dev, 0, 0, 0);
else if (!controller->info->rumble.paused)
{
if (!Controller_Rumble(controller))
controller->rumble.expiration = controller->rumble.time_left = 0;
}
}
#else
(void)unpause;
return;
#endif
}
void I_UpdateControllers(void)
{
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) != GAMEPAD_INIT_FLAGS)
return;
for (UINT8 i = 0; i < NUM_GAMEPADS; i++)
{
ControllerInfo *controller = &controllers[i];
if (!controller->started || !controller->info->rumble.supported || controller->info->rumble.paused)
continue;
if (controller->rumble.expiration &&
SDL_TICKS_PASSED(SDL_GetTicks(), controller->rumble.expiration))
{
// Enough time has passed, so stop the effect
Controller_StopRumble(i);
}
}
SDL_JoystickUpdate();
}
// Converts duration in tics to milliseconds
#define TICS_TO_MS(tics) ((INT32)(tics * (1000.0f/TICRATE)))
boolean I_RumbleGamepad(UINT8 which, const haptic_t *effect)
{
if (!I_RumbleSupported() || which >= NUM_GAMEPADS)
return false;
ControllerInfo *controller = &controllers[which];
if (!controller->started || !controller->info->rumble.supported)
return false;
UINT16 duration = min(TICS_TO_MS(effect->duration), UINT16_MAX);
UINT16 large_magnitude = max(0, min(effect->large_magnitude, UINT16_MAX));
UINT16 small_magnitude = max(0, min(effect->small_magnitude, UINT16_MAX));
CONS_Debug(DBG_GAMELOGIC, "Starting rumble effect for controller %d:\n", which);
CONS_Debug(DBG_GAMELOGIC, " Large motor magnitude: %f\n", large_magnitude / 65535.0f);
CONS_Debug(DBG_GAMELOGIC, " Small motor magnitude: %f\n", small_magnitude / 65535.0f);
if (!duration)
CONS_Debug(DBG_GAMELOGIC, " Duration: forever\n");
else
CONS_Debug(DBG_GAMELOGIC, " Duration: %dms\n", duration);
controller->rumble.large_magnitude = large_magnitude;
controller->rumble.small_magnitude = small_magnitude;
if (!rumble_paused && !Controller_Rumble(controller))
{
Controller_StopRumble(which);
return false;
}
controller->rumble.time_left = 0;
if (duration)
controller->rumble.expiration = SDL_GetTicks() + duration;
else
controller->rumble.expiration = 0;
// Update gamepad rumble info
gamepad_t *gamepad = controller->info;
gamepad->rumble.active = true;
gamepad->rumble.paused = false;
gamepad->rumble.data.large_magnitude = effect->large_magnitude;
gamepad->rumble.data.small_magnitude = effect->small_magnitude;
gamepad->rumble.data.duration = effect->duration;
return true;
}
#undef TICS_TO_MS
#define SET_MOTOR_FREQ(type) \
if (!I_RumbleSupported() || which >= NUM_GAMEPADS) \
return false; \
\
ControllerInfo *controller = &controllers[which]; \
if (!controller->started || !controller->info->rumble.supported) \
return false; \
\
gamepad_t *gamepad = controller->info; \
if (gamepad->rumble.data.type##_magnitude == freq) \
return true; \
\
UINT16 frequency = max(0, min(freq, UINT16_MAX)); \
\
controller->rumble.type##_magnitude = frequency; \
\
if (!rumble_paused && !gamepad->rumble.paused && !Controller_Rumble(controller)) \
{ \
Controller_StopRumble(which); \
return false; \
} \
\
gamepad->rumble.data.type##_magnitude = freq; \
gamepad->rumble.active = true; \
return true
boolean I_SetGamepadLargeMotorFreq(UINT8 which, fixed_t freq)
{
SET_MOTOR_FREQ(large);
}
boolean I_SetGamepadSmallMotorFreq(UINT8 which, fixed_t freq)
{
SET_MOTOR_FREQ(small);
}
void I_SetGamepadRumblePaused(UINT8 which, boolean pause)
{
#if SDL_VERSION_ATLEAST(2,0,9)
if (!I_RumbleSupported() || which >= NUM_GAMEPADS)
return;
ControllerInfo *controller = &controllers[which];
if (!controller->started || !controller->info->rumble.supported)
return;
if (pause == controller->info->rumble.paused)
return;
else if (pause)
{
if (!rumble_paused)
SDL_GameControllerRumble(controller->dev, 0, 0, 0);
if (controller->rumble.expiration)
{
controller->rumble.time_left = controller->rumble.expiration - SDL_GetTicks();
controller->rumble.expiration = 0;
}
}
else
{
if (!rumble_paused)
SDL_GameControllerRumble(controller->dev, controller->rumble.large_magnitude, controller->rumble.small_magnitude, 0);
if (controller->rumble.time_left)
controller->rumble.expiration = SDL_GetTicks() + controller->rumble.time_left;
}
controller->info->rumble.paused = pause;
#else
(void)which;
(void)pause;
return;
#endif
}
boolean I_GetGamepadRumbleSupported(UINT8 which)
{
if (!I_RumbleSupported() || which >= NUM_GAMEPADS)
return false;
ControllerInfo *controller = &controllers[which];
if (!controller->started)
return false;
return controller->info->rumble.supported;
}
boolean I_GetGamepadRumblePaused(UINT8 which)
{
if (!I_RumbleSupported() || which >= NUM_GAMEPADS)
return false;
ControllerInfo *controller = &controllers[which];
if (!controller->started || !controller->info->rumble.supported)
return false;
return controller->info->rumble.paused;
}
void I_StopGamepadRumble(UINT8 which)
{
if (!I_RumbleSupported() || which >= NUM_GAMEPADS)
return;
ControllerInfo *controller = &controllers[which];
if (!controller->started || !controller->info->rumble.supported)
return;
Controller_StopRumble(which);
}
#endif

View file

@ -185,7 +185,6 @@ static char returnWadPath[256];
#include "../i_video.h"
#include "../i_sound.h"
#include "../i_system.h"
#include "../i_gamepad.h"
#include "../i_threads.h"
#include "../screen.h" //vid.WndParent
#include "../d_net.h"
@ -194,6 +193,8 @@ static char returnWadPath[256];
#include "endtxt.h"
#include "sdlmain.h"
#include "../i_joy.h"
#include "../m_argv.h"
#include "../r_main.h" // Frame interpolation/uncapped
@ -211,6 +212,41 @@ static char returnWadPath[256];
#include "../byteptr.h"
#endif
/** \brief The JoyReset function
\param JoySet Joystick info to reset
\return void
*/
static void JoyReset(SDLJoyInfo_t *JoySet)
{
if (JoySet->dev)
{
SDL_JoystickClose(JoySet->dev);
}
JoySet->dev = NULL;
JoySet->oldjoy = -1;
JoySet->axises = JoySet->buttons = JoySet->hats = JoySet->balls = 0;
//JoySet->scale
}
/** \brief First joystick up and running
*/
static INT32 joystick_started = 0;
/** \brief SDL info about joystick 1
*/
SDLJoyInfo_t JoyInfo;
/** \brief Second joystick up and running
*/
static INT32 joystick2_started = 0;
/** \brief SDL inof about joystick 2
*/
SDLJoyInfo_t JoyInfo2;
#ifdef HAVE_TERMIOS
static INT32 fdmouse2 = -1;
static INT32 mouse2_started = 0;
@ -903,17 +939,721 @@ INT32 I_GetKey (void)
return rc;
}
//
// I_JoyScale
//
void I_JoyScale(void)
{
Joystick.bGamepadStyle = cv_joyscale.value==0;
JoyInfo.scale = Joystick.bGamepadStyle?1:cv_joyscale.value;
}
void I_JoyScale2(void)
{
Joystick2.bGamepadStyle = cv_joyscale2.value==0;
JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value;
}
// Cheat to get the device index for a joystick handle
INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev)
{
INT32 i, count = SDL_NumJoysticks();
for (i = 0; dev && i < count; i++)
{
SDL_Joystick *test = SDL_JoystickOpen(i);
if (test && test == dev)
return i;
else if (JoyInfo.dev != test && JoyInfo2.dev != test)
SDL_JoystickClose(test);
}
return -1;
}
/** \brief Joystick 1 buttons states
*/
static UINT64 lastjoybuttons = 0;
/** \brief Joystick 1 hats state
*/
static UINT64 lastjoyhats = 0;
/** \brief Shuts down joystick 1
\return void
*/
void I_ShutdownJoystick(void)
{
INT32 i;
event_t event;
event.type=ev_keyup;
event.x = 0;
event.y = 0;
lastjoybuttons = lastjoyhats = 0;
// emulate the up of all joystick buttons
for (i=0;i<JOYBUTTONS;i++)
{
event.key=KEY_JOY1+i;
D_PostEvent(&event);
}
// emulate the up of all joystick hats
for (i=0;i<JOYHATS*4;i++)
{
event.key=KEY_HAT1+i;
D_PostEvent(&event);
}
// reset joystick position
event.type = ev_joystick;
for (i=0;i<JOYAXISSET; i++)
{
event.key = i;
D_PostEvent(&event);
}
joystick_started = 0;
JoyReset(&JoyInfo);
// don't shut down the subsystem here, because hotplugging
}
void I_GetJoystickEvents(void)
{
static event_t event = {0,0,0,0,false};
INT32 i = 0;
UINT64 joyhats = 0;
#if 0
UINT64 joybuttons = 0;
Sint16 axisx, axisy;
#endif
if (!joystick_started) return;
if (!JoyInfo.dev) //I_ShutdownJoystick();
return;
#if 0
//faB: look for as much buttons as g_input code supports,
// we don't use the others
for (i = JoyInfo.buttons - 1; i >= 0; i--)
{
joybuttons <<= 1;
if (SDL_JoystickGetButton(JoyInfo.dev,i))
joybuttons |= 1;
}
if (joybuttons != lastjoybuttons)
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newbuttons = joybuttons ^ lastjoybuttons;
lastjoybuttons = joybuttons;
for (i = 0; i < JOYBUTTONS; i++, j <<= 1)
{
if (newbuttons & j) // button changed state?
{
if (joybuttons & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.key = KEY_JOY1 + i;
D_PostEvent(&event);
}
}
}
#endif
for (i = JoyInfo.hats - 1; i >= 0; i--)
{
Uint8 hat = SDL_JoystickGetHat(JoyInfo.dev, i);
if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i);
if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i);
if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i);
if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i);
}
if (joyhats != lastjoyhats)
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newhats = joyhats ^ lastjoyhats;
lastjoyhats = joyhats;
for (i = 0; i < JOYHATS*4; i++, j <<= 1)
{
if (newhats & j) // hat changed state?
{
if (joyhats & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.key = KEY_HAT1 + i;
D_PostEvent(&event);
}
}
}
#if 0
// send joystick axis positions
event.type = ev_joystick;
for (i = JOYAXISSET - 1; i >= 0; i--)
{
event.key = i;
if (i*2 + 1 <= JoyInfo.axises)
axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0);
else axisx = 0;
if (i*2 + 2 <= JoyInfo.axises)
axisy = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 1);
else axisy = 0;
// -32768 to 32767
axisx = axisx/32;
axisy = axisy/32;
if (Joystick.bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2))
event.x = -1;
else if (axisx > (JOYAXISRANGE/2))
event.x = 1;
else event.x = 0;
if (axisy < -(JOYAXISRANGE/2))
event.y = -1;
else if (axisy > (JOYAXISRANGE/2))
event.y = 1;
else event.y = 0;
}
else
{
axisx = JoyInfo.scale?((axisx/JoyInfo.scale)*JoyInfo.scale):axisx;
axisy = JoyInfo.scale?((axisy/JoyInfo.scale)*JoyInfo.scale):axisy;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0;
if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0;
#endif
// analog control style , just send the raw data
event.x = axisx; // x axis
event.y = axisy; // y axis
}
D_PostEvent(&event);
}
#endif
}
/** \brief Open joystick handle
\param fname name of joystick
\return axises
*/
static int joy_open(int joyindex)
{
SDL_Joystick *newdev = NULL;
int num_joy = 0;
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
{
CONS_Printf(M_GetText("Joystick subsystem not started\n"));
return -1;
}
if (joyindex <= 0)
return -1;
num_joy = SDL_NumJoysticks();
if (num_joy == 0)
{
CONS_Printf("%s", M_GetText("Found no joysticks on this system\n"));
return -1;
}
newdev = SDL_JoystickOpen(joyindex-1);
// Handle the edge case where the device <-> joystick index assignment can change due to hotplugging
// This indexing is SDL's responsibility and there's not much we can do about it.
//
// Example:
// 1. Plug Controller A -> Index 0 opened
// 2. Plug Controller B -> Index 1 opened
// 3. Unplug Controller A -> Index 0 closed, Index 1 active
// 4. Unplug Controller B -> Index 0 inactive, Index 1 closed
// 5. Plug Controller B -> Index 0 opened
// 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B
if (JoyInfo.dev)
{
if (JoyInfo.dev == newdev // same device, nothing to do
|| (newdev == NULL && SDL_JoystickGetAttached(JoyInfo.dev))) // we failed, but already have a working device
return JoyInfo.axises;
// Else, we're changing devices, so send neutral joy events
CONS_Debug(DBG_GAMELOGIC, "Joystick1 device is changing; resetting events...\n");
I_ShutdownJoystick();
}
JoyInfo.dev = newdev;
if (JoyInfo.dev == NULL)
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: Couldn't open device - %s\n"), SDL_GetError());
return -1;
}
else
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: %s\n"), SDL_JoystickName(JoyInfo.dev));
JoyInfo.axises = SDL_JoystickNumAxes(JoyInfo.dev);
if (JoyInfo.axises > JOYAXISSET*2)
JoyInfo.axises = JOYAXISSET*2;
/* if (joyaxes<2)
{
I_OutputMsg("Not enought axes?\n");
return 0;
}*/
JoyInfo.buttons = SDL_JoystickNumButtons(JoyInfo.dev);
if (JoyInfo.buttons > JOYBUTTONS)
JoyInfo.buttons = JOYBUTTONS;
JoyInfo.hats = SDL_JoystickNumHats(JoyInfo.dev);
if (JoyInfo.hats > JOYHATS)
JoyInfo.hats = JOYHATS;
JoyInfo.balls = SDL_JoystickNumBalls(JoyInfo.dev);
//Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo.dev), "pad");
return JoyInfo.axises;
}
}
//Joystick2
/** \brief Joystick 2 buttons states
*/
static UINT64 lastjoy2buttons = 0;
/** \brief Joystick 2 hats state
*/
static UINT64 lastjoy2hats = 0;
/** \brief Shuts down joystick 2
\return void
*/
void I_ShutdownJoystick2(void)
{
INT32 i;
event_t event;
event.type = ev_keyup;
event.x = 0;
event.y = 0;
lastjoy2buttons = lastjoy2hats = 0;
// emulate the up of all joystick buttons
for (i = 0; i < JOYBUTTONS; i++)
{
event.key = KEY_2JOY1 + i;
D_PostEvent(&event);
}
// emulate the up of all joystick hats
for (i = 0; i < JOYHATS*4; i++)
{
event.key = KEY_2HAT1 + i;
D_PostEvent(&event);
}
// reset joystick position
event.type = ev_joystick2;
for (i = 0; i < JOYAXISSET; i++)
{
event.key = i;
D_PostEvent(&event);
}
joystick2_started = 0;
JoyReset(&JoyInfo2);
// don't shut down the subsystem here, because hotplugging
}
void I_GetJoystick2Events(void)
{
static event_t event = {0,0,0,0,false};
INT32 i = 0;
UINT64 joyhats = 0;
#if 0
INT64 joybuttons = 0;
INT32 axisx, axisy;
#endif
if (!joystick2_started)
return;
if (!JoyInfo2.dev) //I_ShutdownJoystick2();
return;
#if 0
//faB: look for as much buttons as g_input code supports,
// we don't use the others
for (i = JoyInfo2.buttons - 1; i >= 0; i--)
{
joybuttons <<= 1;
if (SDL_JoystickGetButton(JoyInfo2.dev,i))
joybuttons |= 1;
}
if (joybuttons != lastjoy2buttons)
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newbuttons = joybuttons ^ lastjoy2buttons;
lastjoy2buttons = joybuttons;
for (i = 0; i < JOYBUTTONS; i++, j <<= 1)
{
if (newbuttons & j) // button changed state?
{
if (joybuttons & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.key = KEY_2JOY1 + i;
D_PostEvent(&event);
}
}
}
#endif
for (i = JoyInfo2.hats - 1; i >= 0; i--)
{
Uint8 hat = SDL_JoystickGetHat(JoyInfo2.dev, i);
if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i);
if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i);
if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i);
if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i);
}
if (joyhats != lastjoy2hats)
{
INT64 j = 1; // keep only bits that changed since last time
INT64 newhats = joyhats ^ lastjoy2hats;
lastjoy2hats = joyhats;
for (i = 0; i < JOYHATS*4; i++, j <<= 1)
{
if (newhats & j) // hat changed state?
{
if (joyhats & j)
event.type = ev_keydown;
else
event.type = ev_keyup;
event.key = KEY_2HAT1 + i;
D_PostEvent(&event);
}
}
}
#if 0
// send joystick axis positions
event.type = ev_joystick2;
for (i = JOYAXISSET - 1; i >= 0; i--)
{
event.key = i;
if (i*2 + 1 <= JoyInfo2.axises)
axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0);
else axisx = 0;
if (i*2 + 2 <= JoyInfo2.axises)
axisy = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 1);
else axisy = 0;
// -32768 to 32767
axisx = axisx/32;
axisy = axisy/32;
if (Joystick2.bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (axisx < -(JOYAXISRANGE/2))
event.x = -1;
else if (axisx > (JOYAXISRANGE/2))
event.x = 1;
else
event.x = 0;
if (axisy < -(JOYAXISRANGE/2))
event.y = -1;
else if (axisy > (JOYAXISRANGE/2))
event.y = 1;
else
event.y = 0;
}
else
{
axisx = JoyInfo2.scale?((axisx/JoyInfo2.scale)*JoyInfo2.scale):axisx;
axisy = JoyInfo2.scale?((axisy/JoyInfo2.scale)*JoyInfo2.scale):axisy;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0;
if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0;
#endif
// analog control style , just send the raw data
event.x = axisx; // x axis
event.y = axisy; // y axis
}
D_PostEvent(&event);
}
#endif
}
/** \brief Open joystick handle
\param fname name of joystick
\return axises
*/
static int joy_open2(int joyindex)
{
SDL_Joystick *newdev = NULL;
int num_joy = 0;
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
{
CONS_Printf(M_GetText("Joystick subsystem not started\n"));
return -1;
}
if (joyindex <= 0)
return -1;
num_joy = SDL_NumJoysticks();
if (num_joy == 0)
{
CONS_Printf("%s", M_GetText("Found no joysticks on this system\n"));
return -1;
}
newdev = SDL_JoystickOpen(joyindex-1);
// Handle the edge case where the device <-> joystick index assignment can change due to hotplugging
// This indexing is SDL's responsibility and there's not much we can do about it.
//
// Example:
// 1. Plug Controller A -> Index 0 opened
// 2. Plug Controller B -> Index 1 opened
// 3. Unplug Controller A -> Index 0 closed, Index 1 active
// 4. Unplug Controller B -> Index 0 inactive, Index 1 closed
// 5. Plug Controller B -> Index 0 opened
// 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B
if (JoyInfo2.dev)
{
if (JoyInfo2.dev == newdev // same device, nothing to do
|| (newdev == NULL && SDL_JoystickGetAttached(JoyInfo2.dev))) // we failed, but already have a working device
return JoyInfo.axises;
// Else, we're changing devices, so send neutral joy events
CONS_Debug(DBG_GAMELOGIC, "Joystick2 device is changing; resetting events...\n");
I_ShutdownJoystick2();
}
JoyInfo2.dev = newdev;
if (JoyInfo2.dev == NULL)
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: couldn't open device - %s\n"), SDL_GetError());
return -1;
}
else
{
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev));
JoyInfo2.axises = SDL_JoystickNumAxes(JoyInfo2.dev);
if (JoyInfo2.axises > JOYAXISSET*2)
JoyInfo2.axises = JOYAXISSET*2;
/* if (joyaxes<2)
{
I_OutputMsg("Not enought axes?\n");
return 0;
}*/
JoyInfo2.buttons = SDL_JoystickNumButtons(JoyInfo2.dev);
if (JoyInfo2.buttons > JOYBUTTONS)
JoyInfo2.buttons = JOYBUTTONS;
JoyInfo2.hats = SDL_JoystickNumHats(JoyInfo2.dev);
if (JoyInfo2.hats > JOYHATS)
JoyInfo2.hats = JOYHATS;
JoyInfo2.balls = SDL_JoystickNumBalls(JoyInfo2.dev);
//Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo2.dev), "pad");
return JoyInfo2.axises;
}
}
//
// I_InitJoystick
//
void I_InitJoystick(void)
{
SDL_Joystick *newjoy = NULL;
//I_ShutdownJoystick();
if (M_CheckParm("-nojoy"))
return;
if (M_CheckParm("-noxinput"))
SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
if (M_CheckParm("-nohidapi"))
SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
{
CONS_Printf("I_InitJoystick()...\n");
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
{
CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
return;
}
}
if (cv_usejoystick.value)
newjoy = SDL_JoystickOpen(cv_usejoystick.value-1);
if (newjoy && JoyInfo2.dev == newjoy) // don't override an active device
cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
else if (newjoy && joy_open(cv_usejoystick.value) != -1)
{
// SDL's device indexes are unstable, so cv_usejoystick may not match
// the actual device index. So let's cheat a bit and find the device's current index.
JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
joystick_started = 1;
}
else
{
if (JoyInfo.oldjoy)
I_ShutdownJoystick();
cv_usejoystick.value = 0;
joystick_started = 0;
}
if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy)
SDL_JoystickClose(newjoy);
}
void I_InitJoystick2(void)
{
SDL_Joystick *newjoy = NULL;
//I_ShutdownJoystick2();
if (M_CheckParm("-nojoy"))
return;
if (M_CheckParm("-noxinput"))
SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
if (M_CheckParm("-nohidapi"))
SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
{
CONS_Printf("I_InitJoystick2()...\n");
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
{
CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
return;
}
}
if (cv_usejoystick2.value)
newjoy = SDL_JoystickOpen(cv_usejoystick2.value-1);
if (newjoy && JoyInfo.dev == newjoy) // don't override an active device
cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
else if (newjoy && joy_open2(cv_usejoystick2.value) != -1)
{
// SDL's device indexes are unstable, so cv_usejoystick may not match
// the actual device index. So let's cheat a bit and find the device's current index.
JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
joystick2_started = 1;
}
else
{
if (JoyInfo2.oldjoy)
I_ShutdownJoystick2();
cv_usejoystick2.value = 0;
joystick2_started = 0;
}
if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy)
SDL_JoystickClose(newjoy);
}
static void I_ShutdownInput(void)
{
I_ShutdownGamepads();
// Yes, the name is misleading: these send neutral events to
// clean up the unplugged joystick's input
// Note these methods are internal to this file, not called elsewhere.
I_ShutdownJoystick();
I_ShutdownJoystick2();
if (SDL_WasInit(GAMEPAD_INIT_FLAGS) == GAMEPAD_INIT_FLAGS)
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{
CONS_Printf("Shutting down game controller subsystems\n");
SDL_QuitSubSystem(GAMEPAD_INIT_FLAGS);
CONS_Printf("Shutting down joy system\n");
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n");
}
}
INT32 I_NumJoys(void)
{
INT32 numjoy = 0;
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
numjoy = SDL_NumJoysticks();
return numjoy;
}
static char joyname[255]; // joystick name is straight from the driver
const char *I_GetJoyName(INT32 joyindex)
{
const char *tempname = NULL;
joyname[0] = 0;
joyindex--; //SDL's Joystick System starts at 0, not 1
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{
tempname = SDL_JoystickNameForIndex(joyindex);
if (tempname)
strncpy(joyname, tempname, 255);
}
return joyname;
}
#ifndef NOMUMBLE
#ifdef HAVE_MUMBLE
// Best Mumble positional audio settings:
@ -1373,6 +2113,23 @@ void I_StartupMouse2(void)
#endif
}
//
// I_Tactile
//
void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
{
// UNUSED.
(void)pFFType;
(void)FFEffect;
}
void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
{
// UNUSED.
(void)pFFType;
(void)FFEffect;
}
/** \brief empty ticcmd for player 1
*/
static ticcmd_t emptycmd;

View file

@ -66,7 +66,7 @@
#include "../m_menu.h"
#include "../d_main.h"
#include "../s_sound.h"
#include "../i_gamepad.h"
#include "../i_joy.h"
#include "../st_stuff.h"
#include "../hu_stuff.h"
#include "../g_game.h"
@ -449,10 +449,51 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
static void VID_Command_Info_f (void)
{
#if 0
SDL2STUB();
#else
#if 0
const SDL_VideoInfo *videoInfo;
videoInfo = SDL_GetVideoInfo(); //Alam: Double-Check
if (videoInfo)
{
CONS_Printf("%s", M_GetText("Video Interface Capabilities:\n"));
if (videoInfo->hw_available)
CONS_Printf("%s", M_GetText(" Hardware surfaces\n"));
if (videoInfo->wm_available)
CONS_Printf("%s", M_GetText(" Window manager\n"));
//UnusedBits1 :6
//UnusedBits2 :1
if (videoInfo->blit_hw)
CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW\n"));
if (videoInfo->blit_hw_CC)
CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW with Colorkey\n"));
if (videoInfo->wm_available)
CONS_Printf("%s", M_GetText(" Accelerated blits HW-2-HW with Alpha\n"));
if (videoInfo->blit_sw)
{
CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW\n"));
if (!M_CheckParm("-noblit")) videoblitok = SDL_TRUE;
}
if (videoInfo->blit_sw_CC)
CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW with Colorkey\n"));
if (videoInfo->blit_sw_A)
CONS_Printf("%s", M_GetText(" Accelerated blits SW-2-HW with Alpha\n"));
if (videoInfo->blit_fill)
CONS_Printf("%s", M_GetText(" Accelerated Color filling\n"));
//UnusedBits3 :16
if (videoInfo->video_mem)
CONS_Printf(M_GetText(" There is %i KB of video memory\n"), videoInfo->video_mem);
else
CONS_Printf("%s", M_GetText(" There no video memory for SDL\n"));
//*vfmt
}
#else
if (!M_CheckParm("-noblit")) videoblitok = SDL_TRUE;
#endif
SurfaceInfo(bufSurface, M_GetText("Current Engine Mode"));
SurfaceInfo(vidSurface, M_GetText("Current Video Mode"));
#endif
}
static void VID_Command_ModeList_f(void)
@ -487,6 +528,61 @@ static void VID_Command_Mode_f (void)
setmodeneeded = modenum+1; // request vid mode change
}
static inline void SDLJoyRemap(event_t *event)
{
(void)event;
}
static INT32 SDLJoyAxis(const Sint16 axis, evtype_t which)
{
// -32768 to 32767
INT32 raxis = axis/32;
if (which == ev_joystick)
{
if (Joystick.bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else
raxis = 0;
}
else
{
raxis = JoyInfo.scale!=1?((raxis/JoyInfo.scale)*JoyInfo.scale):raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
else if (which == ev_joystick2)
{
if (Joystick2.bGamepadStyle)
{
// gamepad control type, on or off, live or die
if (raxis < -(JOYAXISRANGE/2))
raxis = -1;
else if (raxis > (JOYAXISRANGE/2))
raxis = 1;
else raxis = 0;
}
else
{
raxis = JoyInfo2.scale!=1?((raxis/JoyInfo2.scale)*JoyInfo2.scale):raxis;
#ifdef SDL_JDEADZONE
if (-SDL_JDEADZONE <= raxis && raxis <= SDL_JDEADZONE)
raxis = 0;
#endif
}
}
return raxis;
}
static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
{
static SDL_bool firsttimeonmouse = SDL_TRUE;
@ -518,13 +614,13 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
// Tell game we got focus back, resume music if necessary
window_notinfocus = false;
if (!paused)
S_ResumeAudio();
S_ResumeAudio(); //resume it
I_ToggleControllerRumble(true);
P_UnpauseRumble(NULL);
if (!firsttimeonmouse && cv_usemouse.value)
I_StartupMouse();
if (!firsttimeonmouse)
{
if (cv_usemouse.value) I_StartupMouse();
}
//else firsttimeonmouse = SDL_FALSE;
if (USE_MOUSEINPUT && !IgnoreMouse())
SDLdoGrabMouse();
@ -533,45 +629,43 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
{
// Tell game we lost focus, pause music
window_notinfocus = true;
if (!cv_playmusicifunfocused.value)
if (! cv_playmusicifunfocused.value)
S_PauseAudio();
if (!cv_playsoundsifunfocused.value)
if (! cv_playsoundsifunfocused.value)
S_StopSounds();
if (!disable_mouse)
{
SDLforceUngrabMouse();
}
memset(gamekeydown, 0, NUMKEYS); // TODO this is a scary memset
I_ToggleControllerRumble(false);
if (P_AutoPause())
P_PauseRumble(NULL);
if (MOUSE_MENU)
{
SDLdoUngrabMouse();
}
}
}
static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
{
event_t event;
if (type == SDL_KEYUP)
{
event.type = ev_keyup;
}
else if (type == SDL_KEYDOWN)
{
event.type = ev_keydown;
}
else
{
return;
}
event.key = Impl_SDL_Scancode_To_Keycode(evt.keysym.scancode);
if (!event.key)
return;
event.repeated = (evt.repeat != 0);
event.which = 0;
D_PostEvent(&event);
if (event.key) D_PostEvent(&event);
}
static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
@ -636,35 +730,32 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
if (SDL_GetMouseFocus() != window || IgnoreMouse())
return;
/// \todo inputEvent.button.which
if (USE_MOUSEINPUT)
{
if (type == SDL_MOUSEBUTTONUP)
event.type = ev_keyup;
else if (type == SDL_MOUSEBUTTONDOWN)
event.type = ev_keydown;
else
return;
switch (evt.button)
{
case SDL_BUTTON_LEFT:
event.key = KEY_MOUSE1+0;
break;
case SDL_BUTTON_RIGHT:
event.key = KEY_MOUSE1+1;
break;
case SDL_BUTTON_MIDDLE:
event.key = KEY_MOUSE1+2;
break;
case SDL_BUTTON_X1:
event.key = KEY_MOUSE1+3;
break;
case SDL_BUTTON_X2:
event.key = KEY_MOUSE1+4;
break;
event.type = ev_keyup;
}
else if (type == SDL_MOUSEBUTTONDOWN)
{
event.type = ev_keydown;
}
else return;
if (evt.button == SDL_BUTTON_MIDDLE)
event.key = KEY_MOUSE1+2;
else if (evt.button == SDL_BUTTON_RIGHT)
event.key = KEY_MOUSE1+1;
else if (evt.button == SDL_BUTTON_LEFT)
event.key = KEY_MOUSE1;
else if (evt.button == SDL_BUTTON_X1)
event.key = KEY_MOUSE1+3;
else if (evt.button == SDL_BUTTON_X2)
event.key = KEY_MOUSE1+4;
if (event.type == ev_keyup || event.type == ev_keydown)
{
D_PostEvent(&event);
}
D_PostEvent(&event);
}
}
@ -695,6 +786,111 @@ static void Impl_HandleMouseWheelEvent(SDL_MouseWheelEvent evt)
}
}
static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt)
{
event_t event;
SDL_JoystickID joyid[2];
// Determine the Joystick IDs for each current open joystick
joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
evt.axis++;
event.key = event.x = event.y = INT32_MAX;
if (evt.which == joyid[0])
{
event.type = ev_joystick;
}
else if (evt.which == joyid[1])
{
event.type = ev_joystick2;
}
else return;
//axis
if (evt.axis > JOYAXISSET*2)
return;
//vaule
if (evt.axis%2)
{
event.key = evt.axis / 2;
event.x = SDLJoyAxis(evt.value, event.type);
}
else
{
evt.axis--;
event.key = evt.axis / 2;
event.y = SDLJoyAxis(evt.value, event.type);
}
D_PostEvent(&event);
}
#if 0
static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt)
{
event_t event;
SDL_JoystickID joyid[2];
// Determine the Joystick IDs for each current open joystick
joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
if (evt.hat >= JOYHATS)
return; // ignore hats with too high an index
if (evt.which == joyid[0])
{
event.key = KEY_HAT1 + (evt.hat*4);
}
else if (evt.which == joyid[1])
{
event.key = KEY_2HAT1 + (evt.hat*4);
}
else return;
// NOTE: UNFINISHED
}
#endif
static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type)
{
event_t event;
SDL_JoystickID joyid[2];
// Determine the Joystick IDs for each current open joystick
joyid[0] = SDL_JoystickInstanceID(JoyInfo.dev);
joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev);
if (evt.which == joyid[0])
{
event.key = KEY_JOY1;
}
else if (evt.which == joyid[1])
{
event.key = KEY_2JOY1;
}
else return;
if (type == SDL_JOYBUTTONUP)
{
event.type = ev_keyup;
}
else if (type == SDL_JOYBUTTONDOWN)
{
event.type = ev_keydown;
}
else return;
if (evt.button < JOYBUTTONS)
{
event.key += evt.button;
}
else return;
SDLJoyRemap(&event);
if (event.type != ev_console) D_PostEvent(&event);
}
void I_GetEvent(void)
{
SDL_Event evt;
@ -732,18 +928,147 @@ void I_GetEvent(void)
case SDL_MOUSEWHEEL:
Impl_HandleMouseWheelEvent(evt.wheel);
break;
case SDL_CONTROLLERAXISMOTION:
I_HandleControllerAxisEvent(evt.caxis);
case SDL_JOYAXISMOTION:
Impl_HandleJoystickAxisEvent(evt.jaxis);
break;
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERBUTTONDOWN:
I_HandleControllerButtonEvent(evt.cbutton, evt.type);
#if 0
case SDL_JOYHATMOTION:
Impl_HandleJoystickHatEvent(evt.jhat)
break;
case SDL_CONTROLLERDEVICEADDED:
I_ControllerDeviceAdded(evt.cdevice.which);
#endif
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type);
break;
case SDL_CONTROLLERDEVICEREMOVED:
I_ControllerDeviceRemoved();
case SDL_JOYDEVICEADDED:
{
SDL_Joystick *newjoy = SDL_JoystickOpen(evt.jdevice.which);
CONS_Debug(DBG_GAMELOGIC, "Joystick device index %d added\n", evt.jdevice.which + 1);
// Because SDL's device index is unstable, we're going to cheat here a bit:
// For the first joystick setting that is NOT active:
// 1. Set cv_usejoystickX.value to the new device index (this does not change what is written to config.cfg)
// 2. Set OTHERS' cv_usejoystickX.value to THEIR new device index, because it likely changed
// * If device doesn't exist, switch cv_usejoystick back to default value (.string)
// * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value!
if (newjoy && (!JoyInfo.dev || !SDL_JoystickGetAttached(JoyInfo.dev))
&& JoyInfo2.dev != newjoy) // don't override a currently active device
{
cv_usejoystick.value = evt.jdevice.which + 1;
if (JoyInfo2.dev)
cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy
&& atoi(cv_usejoystick2.string) != cv_usejoystick.value)
cv_usejoystick2.value = atoi(cv_usejoystick2.string);
else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy
&& atoi(cv_usejoystick.string) != cv_usejoystick.value)
cv_usejoystick2.value = atoi(cv_usejoystick.string);
else // we tried...
cv_usejoystick2.value = 0;
}
else if (newjoy && (!JoyInfo2.dev || !SDL_JoystickGetAttached(JoyInfo2.dev))
&& JoyInfo.dev != newjoy) // don't override a currently active device
{
cv_usejoystick2.value = evt.jdevice.which + 1;
if (JoyInfo.dev)
cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy
&& atoi(cv_usejoystick.string) != cv_usejoystick2.value)
cv_usejoystick.value = atoi(cv_usejoystick.string);
else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy
&& atoi(cv_usejoystick2.string) != cv_usejoystick2.value)
cv_usejoystick.value = atoi(cv_usejoystick2.string);
else // we tried...
cv_usejoystick.value = 0;
}
// Was cv_usejoystick disabled in settings?
if (!strcmp(cv_usejoystick.string, "0") || !cv_usejoystick.value)
cv_usejoystick.value = 0;
else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
&& cv_usejoystick.value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usejoystick, cv_usejoystick.value);
if (!strcmp(cv_usejoystick2.string, "0") || !cv_usejoystick2.value)
cv_usejoystick2.value = 0;
else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
&& cv_usejoystick2.value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value);
// Update all joysticks' init states
// This is a little wasteful since cv_usejoystick already calls this, but
// we need to do this in case CV_SetValue did nothing because the string was already same.
// if the device is already active, this should do nothing, effectively.
I_InitJoystick();
I_InitJoystick2();
CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy);
CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy);
// update the menu
if (currentMenu == &OP_JoystickSetDef)
M_SetupJoystickMenu(0);
if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy)
SDL_JoystickClose(newjoy);
}
break;
case SDL_JOYDEVICEREMOVED:
if (JoyInfo.dev && !SDL_JoystickGetAttached(JoyInfo.dev))
{
CONS_Debug(DBG_GAMELOGIC, "Joystick1 removed, device index: %d\n", JoyInfo.oldjoy);
I_ShutdownJoystick();
}
if (JoyInfo2.dev && !SDL_JoystickGetAttached(JoyInfo2.dev))
{
CONS_Debug(DBG_GAMELOGIC, "Joystick2 removed, device index: %d\n", JoyInfo2.oldjoy);
I_ShutdownJoystick2();
}
// Update the device indexes, because they likely changed
// * If device doesn't exist, switch cv_usejoystick back to default value (.string)
// * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value!
if (JoyInfo.dev)
cv_usejoystick.value = JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy)
cv_usejoystick.value = atoi(cv_usejoystick.string);
else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy)
cv_usejoystick.value = atoi(cv_usejoystick2.string);
else // we tried...
cv_usejoystick.value = 0;
if (JoyInfo2.dev)
cv_usejoystick2.value = JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy)
cv_usejoystick2.value = atoi(cv_usejoystick2.string);
else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy)
cv_usejoystick2.value = atoi(cv_usejoystick.string);
else // we tried...
cv_usejoystick2.value = 0;
// Was cv_usejoystick disabled in settings?
if (!strcmp(cv_usejoystick.string, "0"))
cv_usejoystick.value = 0;
else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
&& cv_usejoystick.value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usejoystick, cv_usejoystick.value);
if (!strcmp(cv_usejoystick2.string, "0"))
cv_usejoystick2.value = 0;
else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
&& cv_usejoystick2.value) // update the cvar ONLY if a device exists
CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value);
CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy);
CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy);
// update the menu
if (currentMenu == &OP_JoystickSetDef)
M_SetupJoystickMenu(0);
break;
case SDL_QUIT:
LUA_HookBool(true, HOOK(GameQuit));
@ -761,7 +1086,6 @@ void I_GetEvent(void)
//SDL_memset(&event, 0, sizeof(event_t));
event.type = ev_mouse;
event.key = 0;
event.which = 0;
event.x = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth));
event.y = (INT32)lround(mousemovey * ((float)wheight / (float)realheight));
D_PostEvent(&event);
@ -800,9 +1124,15 @@ void I_OsPolling(void)
if (consolevent)
I_GetConsoleEvents();
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{
SDL_JoystickUpdate();
I_GetJoystickEvents();
I_GetJoystick2Events();
}
I_UpdateControllers();
I_GetMouseEvents();
I_GetEvent();
mod = SDL_GetModState();

View file

@ -23,41 +23,59 @@ extern SDL_bool consolevent;
extern SDL_bool framebuffer;
#include "../m_fixed.h"
#include "../i_gamepad.h"
// SDL info about all controllers
typedef struct
// SDL2 stub macro
#ifdef _MSC_VER
#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __FUNCTION__, __LINE__)
#else
#define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__)
#endif
// So m_menu knows whether to store cv_usejoystick value or string
#define JOYSTICK_HOTPLUG
/** \brief The JoyInfo_s struct
info about joystick
*/
typedef struct SDLJoyInfo_s
{
boolean started; // started
int lastindex; // last gamepad ID
/// Joystick handle
SDL_Joystick *dev;
/// number of old joystick
int oldjoy;
/// number of axies
int axises;
/// scale of axises
INT32 scale;
/// number of buttons
int buttons;
/// number of hats
int hats;
/// number of balls
int balls;
SDL_GameController *dev;
SDL_Joystick *joydev;
} SDLJoyInfo_t;
gamepad_t *info; // pointer to gamepad info
/** \brief SDL info about joystick 1
*/
extern SDLJoyInfo_t JoyInfo;
struct {
Uint16 large_magnitude;
Uint16 small_magnitude;
Uint32 expiration, time_left;
} rumble;
} ControllerInfo;
/** \brief joystick axis deadzone
*/
#define SDL_JDEADZONE 153
#undef SDL_JDEADZONE
#define GAMEPAD_INIT_FLAGS (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER)
/** \brief SDL inof about joystick 2
*/
extern SDLJoyInfo_t JoyInfo2;
void I_UpdateControllers(void);
// So we can call this from i_video event loop
void I_ShutdownJoystick(void);
void I_ShutdownJoystick2(void);
void I_ControllerDeviceAdded(INT32 which);
void I_ControllerDeviceRemoved(void);
void I_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint32 type);
void I_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt);
INT32 I_GetControllerIndex(SDL_GameController *dev);
void I_CloseInactiveController(SDL_GameController *dev);
void I_CloseInactiveHapticDevice(SDL_Haptic *dev);
void I_ToggleControllerRumble(boolean unpause);
// Cheat to get the device index for a joystick handle
INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev);
void I_GetConsoleEvents(void);

View file

@ -164,7 +164,7 @@ hudinfo_t hudinfo[NUMHUDITEMS] =
{ 288, 176, V_SNAPTORIGHT|V_SNAPTOBOTTOM}, // HUD_POWERUPS
};
static huddrawlist_h luahuddrawlist_game;
static huddrawlist_h luahuddrawlist_game[2];
static huddrawlist_h luahuddrawlist_titlecard;
//
@ -427,7 +427,8 @@ void ST_Init(void)
ST_LoadGraphics();
luahuddrawlist_game = LUA_HUD_CreateDrawList();
luahuddrawlist_game[0] = LUA_HUD_CreateDrawList();
luahuddrawlist_game[1] = LUA_HUD_CreateDrawList();
luahuddrawlist_titlecard = LUA_HUD_CreateDrawList();
}
@ -2757,10 +2758,13 @@ static void ST_overlayDrawer(void)
if (!(netgame || multiplayer) || !hu_showscores)
{
INT32 hooklistindex = splitscreen && stplyr == &players[secondarydisplayplayer] ? 1 : 0;
if (renderisnewtic)
{
LUA_HUDHOOK(game, luahuddrawlist_game);
LUA_HUD_ClearDrawList(luahuddrawlist_game[hooklistindex]);
LUA_HUDHOOK(game, luahuddrawlist_game[hooklistindex]);
}
LUA_HUD_DrawList(luahuddrawlist_game[hooklistindex]);
}
// draw level title Tails
@ -2839,10 +2843,6 @@ void ST_Drawer(void)
if (st_overlay)
{
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_game);
}
// No deadview!
stplyr = &players[displayplayer];
ST_overlayDrawer();
@ -2852,7 +2852,5 @@ void ST_Drawer(void)
stplyr = &players[secondarydisplayplayer];
ST_overlayDrawer();
}
LUA_HUD_DrawList(luahuddrawlist_game);
}
}

View file

@ -472,5 +472,5 @@ mtag_t Tag_NextUnused(mtag_t start)
start++;
}
return MAXTAGS;
return (mtag_t)MAXTAGS;
}