mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-30 19:52:43 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into conditions-cascading
# Conflicts: # src/k_battle.c # src/k_hud_track.cpp # src/k_kart.c # src/p_inter.c
This commit is contained in:
commit
2e1efaff0c
50 changed files with 1243 additions and 1263 deletions
|
|
@ -449,7 +449,7 @@ boolean AM_Responder(event_t *ev)
|
|||
{
|
||||
//faB: prevent alt-tab in win32 version to activate automap just before
|
||||
// minimizing the app; doesn't do any harm to the DOS version
|
||||
if (!gamekeydown[0][KEY_LALT] && !gamekeydown[0][KEY_RALT])
|
||||
if (!G_GetDeviceGameKeyDownArray(0)[KEY_LALT] && !G_GetDeviceGameKeyDownArray(0)[KEY_RALT])
|
||||
{
|
||||
bigstate = 0; //added : 24-01-98 : toggle off large view
|
||||
AM_Start();
|
||||
|
|
@ -1069,7 +1069,7 @@ static void AM_drawWalls(UINT8 pass)
|
|||
else if (backc1 != frontc1 || backc2 != frontc2)
|
||||
{
|
||||
if (!(pass & PASS_INTANGIBLE))
|
||||
;
|
||||
;
|
||||
else if (abs(backc1 - frontc1) < maxstep
|
||||
|| abs(backc2 - frontc2) < maxstep)
|
||||
{
|
||||
|
|
@ -1115,7 +1115,7 @@ static void AM_drawWalls(UINT8 pass)
|
|||
else
|
||||
{
|
||||
ffloor_t *rover = NULL;
|
||||
|
||||
|
||||
if (lines[i].frontsector->ffloors || lines[i].backsector->ffloors)
|
||||
{
|
||||
if (lines[i].backsector->ffloors == NULL)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ size_t Gain<C>::filter(tcb::span<Sample<C>> input_buffer, tcb::span<Sample<C>> b
|
|||
template <size_t C>
|
||||
void Gain<C>::gain(float new_gain)
|
||||
{
|
||||
new_gain_ = std::clamp(new_gain, 0.0f, 1.0f);
|
||||
new_gain_ = std::max(new_gain, 0.f);
|
||||
}
|
||||
|
||||
template <size_t C>
|
||||
|
|
|
|||
|
|
@ -1485,7 +1485,7 @@ void CL_UpdateServerList (void)
|
|||
|
||||
static void M_ConfirmConnect(void)
|
||||
{
|
||||
if (G_PlayerInputDown(0, gc_a, 1) || gamekeydown[0][KEY_ENTER])
|
||||
if (G_PlayerInputDown(0, gc_a, 1) || G_GetDeviceGameKeyDownArray(0)[KEY_ENTER])
|
||||
{
|
||||
if (totalfilesrequestednum > 0)
|
||||
{
|
||||
|
|
@ -1512,7 +1512,7 @@ static void M_ConfirmConnect(void)
|
|||
|
||||
M_StopMessage(0);
|
||||
}
|
||||
else if (G_PlayerInputDown(0, gc_b, 1) || G_PlayerInputDown(0, gc_x, 1) || gamekeydown[0][KEY_ESCAPE])
|
||||
else if (G_PlayerInputDown(0, gc_b, 1) || G_PlayerInputDown(0, gc_x, 1) || G_GetDeviceGameKeyDownArray(0)[KEY_ESCAPE])
|
||||
{
|
||||
cl_mode = CL_ABORTED;
|
||||
M_StopMessage(0);
|
||||
|
|
@ -1962,7 +1962,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
|||
renderdeltatics = FRACUNIT;
|
||||
rendertimefrac = FRACUNIT;
|
||||
|
||||
memset(deviceResponding, false, sizeof (deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
|
|
@ -1979,7 +1979,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
|||
{
|
||||
if (G_PlayerInputDown(0, gc_b, 1)
|
||||
|| G_PlayerInputDown(0, gc_x, 1)
|
||||
|| gamekeydown[0][KEY_ESCAPE])
|
||||
|| G_GetDeviceGameKeyDownArray(0)[KEY_ESCAPE])
|
||||
cl_mode = CL_ABORTED;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ typedef enum
|
|||
ev_keyup,
|
||||
ev_console,
|
||||
ev_mouse,
|
||||
ev_joystick,
|
||||
ev_gamepad_axis,
|
||||
ev_gamepad_device_added,
|
||||
ev_gamepad_device_removed,
|
||||
} evtype_t;
|
||||
|
||||
// Event structure.
|
||||
|
|
@ -38,7 +40,7 @@ struct event_t
|
|||
INT32 data1; // keys / mouse/joystick buttons
|
||||
INT32 data2; // mouse/joystick x move
|
||||
INT32 data3; // mouse/joystick y move
|
||||
INT32 device; // which player's device it belongs to
|
||||
INT32 device; // which device ID it belongs to (controller ID)
|
||||
};
|
||||
|
||||
//
|
||||
|
|
|
|||
56
src/d_main.c
56
src/d_main.c
|
|
@ -172,6 +172,54 @@ UINT8 ctrldown = 0; // 0x1 left, 0x2 right
|
|||
UINT8 altdown = 0; // 0x1 left, 0x2 right
|
||||
boolean capslock = 0; // gee i wonder what this does.
|
||||
|
||||
static void HandleGamepadDeviceAdded(event_t *ev)
|
||||
{
|
||||
I_Assert(ev != NULL);
|
||||
I_Assert(ev->type == ev_gamepad_device_added);
|
||||
|
||||
G_RegisterAvailableGamepad(ev->device);
|
||||
CONS_Debug(DBG_GAMELOGIC, "Registered available gamepad device %d\n", ev->device);
|
||||
}
|
||||
|
||||
static void HandleGamepadDeviceRemoved(event_t *ev)
|
||||
{
|
||||
int i = 0;
|
||||
I_Assert(ev != NULL);
|
||||
I_Assert(ev->type == ev_gamepad_device_removed);
|
||||
|
||||
G_UnregisterAvailableGamepad(ev->device);
|
||||
CONS_Debug(DBG_GAMELOGIC, "Unregistered available gamepad device %d\n", ev->device);
|
||||
|
||||
// Downstream responders need to update player gamepad assignments, pause, etc
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
INT32 device = G_GetDeviceForPlayer(i);
|
||||
if (device == ev->device)
|
||||
{
|
||||
G_SetDeviceForPlayer(i, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Respond to added/removed device events, for bookkeeping available gamepads.
|
||||
static void HandleGamepadDeviceEvents(event_t *ev)
|
||||
{
|
||||
I_Assert(ev != NULL);
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
case ev_gamepad_device_added:
|
||||
HandleGamepadDeviceAdded(ev);
|
||||
break;
|
||||
case ev_gamepad_device_removed:
|
||||
HandleGamepadDeviceRemoved(ev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// D_ProcessEvents
|
||||
// Send all the events of the given timestamp down the responder chain
|
||||
|
|
@ -184,11 +232,13 @@ void D_ProcessEvents(void)
|
|||
boolean eaten;
|
||||
boolean menuresponse = false;
|
||||
|
||||
memset(deviceResponding, false, sizeof (deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1))
|
||||
{
|
||||
ev = &events[eventtail];
|
||||
|
||||
HandleGamepadDeviceEvents(ev);
|
||||
|
||||
// Screenshots over everything so that they can be taken anywhere.
|
||||
if (M_ScreenshotResponder(ev))
|
||||
continue; // ate the event
|
||||
|
|
@ -989,7 +1039,7 @@ void D_ClearState(void)
|
|||
|
||||
// clear cmd building stuff
|
||||
memset(gamekeydown, 0, sizeof (gamekeydown));
|
||||
memset(deviceResponding, false, sizeof (deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
|
||||
// Reset the palette
|
||||
if (rendermode != render_none)
|
||||
|
|
@ -1524,6 +1574,8 @@ void D_SRB2Main(void)
|
|||
CONS_Printf("I_StartupGraphics()...\n");
|
||||
I_StartupGraphics();
|
||||
|
||||
I_StartupInput();
|
||||
|
||||
if (rendermode != render_none)
|
||||
{
|
||||
I_NewTwodeeFrame();
|
||||
|
|
|
|||
|
|
@ -237,9 +237,6 @@ static CV_PossibleValue_t usemouse_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Force
|
|||
#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
|
||||
static CV_PossibleValue_t usejoystick_cons_t[] = {{-1, "MIN"}, {MAXGAMEPADS, "MAX"}, {0, NULL}};
|
||||
#endif
|
||||
|
||||
static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}};
|
||||
|
|
@ -332,13 +329,6 @@ consvar_t cv_skipmapcheck = CVAR_INIT ("skipmapcheck", "Off", CV_SAVE, CV_OnOff,
|
|||
|
||||
consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse);
|
||||
|
||||
consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS] = {
|
||||
CVAR_INIT ("use_device", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1),
|
||||
CVAR_INIT ("use_device2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2),
|
||||
CVAR_INIT ("use_device3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3),
|
||||
CVAR_INIT ("use_device4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4)
|
||||
};
|
||||
|
||||
#if (defined (LJOYSTICK) || defined (HAVE_SDL))
|
||||
consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = {
|
||||
CVAR_INIT ("padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale),
|
||||
|
|
@ -1040,7 +1030,6 @@ void D_RegisterClientCommands(void)
|
|||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
CV_RegisterVar(&cv_usejoystick[i]);
|
||||
CV_RegisterVar(&cv_joyscale[i]);
|
||||
#ifdef LJOYSTICK
|
||||
CV_RegisterVar(&cv_joyport[i]);
|
||||
|
|
@ -3374,7 +3363,7 @@ static void Got_Respawn(UINT8 **cp, INT32 playernum)
|
|||
if (!P_IsObjectOnGround(players[respawnplayer].mo))
|
||||
return;
|
||||
|
||||
K_DoIngameRespawn(&players[respawnplayer]);
|
||||
P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 1, DMG_DEATHPIT);
|
||||
demo_extradata[playernum] |= DXD_RESPAWN;
|
||||
}
|
||||
}
|
||||
|
|
@ -6231,6 +6220,7 @@ static void FollowerAny_OnChange(UINT8 pnum)
|
|||
return; // don't send anything there.
|
||||
|
||||
SendNameAndColor(pnum);
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(pnum);
|
||||
}
|
||||
|
||||
// sends the follower change for players
|
||||
|
|
@ -6382,6 +6372,8 @@ static void Color_OnChange(void)
|
|||
}
|
||||
}
|
||||
lastgoodcolor[0] = cv_playercolor[0].value;
|
||||
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(0);
|
||||
}
|
||||
|
||||
/** Sends a color change for the secondary splitscreen player, unless that
|
||||
|
|
@ -6410,6 +6402,8 @@ static void Color2_OnChange(void)
|
|||
}
|
||||
}
|
||||
lastgoodcolor[1] = cv_playercolor[1].value;
|
||||
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(1);
|
||||
}
|
||||
|
||||
static void Color3_OnChange(void)
|
||||
|
|
@ -6433,6 +6427,8 @@ static void Color3_OnChange(void)
|
|||
}
|
||||
}
|
||||
lastgoodcolor[2] = cv_playercolor[2].value;
|
||||
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(2);
|
||||
}
|
||||
|
||||
static void Color4_OnChange(void)
|
||||
|
|
@ -6456,6 +6452,8 @@ static void Color4_OnChange(void)
|
|||
}
|
||||
}
|
||||
lastgoodcolor[3] = cv_playercolor[3].value;
|
||||
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(3);
|
||||
}
|
||||
|
||||
/** Displays the result of the chat being muted or unmuted.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ extern consvar_t cv_splitplayers;
|
|||
|
||||
extern consvar_t cv_seenames;
|
||||
extern consvar_t cv_usemouse;
|
||||
extern consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS];
|
||||
extern consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS];
|
||||
#ifdef LJOYSTICK
|
||||
extern consvar_t cv_joyport[MAXSPLITSCREENPLAYERS];
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ struct player_t
|
|||
UINT16 spinouttimer; // Spin-out from a banana peel or oil slick (was "pw_bananacam")
|
||||
UINT8 spinouttype; // Determines the mode of spinout/wipeout, see kartspinoutflags_t
|
||||
UINT8 instashield; // Instashield no-damage animation timer
|
||||
INT32 invulnhitlag; // Numbers of tics of hitlag added this tic for "potential" damage -- not real damage
|
||||
INT32 nullHitlag; // Numbers of tics of hitlag that will ultimately be ignored by subtracting from hitlag
|
||||
UINT8 wipeoutslow; // Timer before you slowdown when getting wiped out
|
||||
UINT8 justbumped; // Prevent players from endlessly bumping into each other
|
||||
UINT8 tumbleBounces;
|
||||
|
|
@ -625,9 +625,7 @@ struct player_t
|
|||
|
||||
UINT32 roundscore; // battle score this round
|
||||
UINT8 emeralds;
|
||||
UINT8 bumpers;
|
||||
INT16 karmadelay;
|
||||
tic_t overtimekarma; // time to live in overtime comeback
|
||||
INT16 spheres;
|
||||
tic_t spheredigestion;
|
||||
|
||||
|
|
@ -666,8 +664,10 @@ struct player_t
|
|||
|
||||
INT16 lastsidehit, lastlinehit;
|
||||
|
||||
// These track how many things tried to damage you, not
|
||||
// whether you actually took damage.
|
||||
// TimesHit tracks how many times something tried to
|
||||
// damage you or how many times you tried to damage
|
||||
// something else. It does not track whether damage was
|
||||
// actually dealt.
|
||||
UINT8 timeshit; // times hit this tic
|
||||
UINT8 timeshitprev; // times hit before
|
||||
// That's TIMES HIT, not TIME SHIT, you doofus! -- in memoriam
|
||||
|
|
|
|||
|
|
@ -5730,7 +5730,7 @@ const char *const MOBJFLAG2_LIST[] = {
|
|||
"JUSTATTACKED", // can be pushed by other moving mobjs
|
||||
"FIRING", // turret fire
|
||||
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
|
||||
"\x01", // free: 1<<20 (name un-matchable)
|
||||
"ALREADYHIT", // This object was already damaged THIS tic, resets even during hitlag
|
||||
"STRONGBOX", // Flag used for "strong" random monitors.
|
||||
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
|
||||
"SKULLFLY", // Special handling: skull in flight.
|
||||
|
|
|
|||
|
|
@ -748,10 +748,10 @@ extern int
|
|||
/// Render flats on walls
|
||||
#define WALLFLATS
|
||||
|
||||
/// Divide volume of music and sounds by this much (loudest sounds on earth)
|
||||
#define VOLUME_DIVIDER 4
|
||||
#define USER_VOLUME_SCALE 2
|
||||
#define MAX_VOLUME ( 100 * VOLUME_DIVIDER / USER_VOLUME_SCALE )
|
||||
// Volume scale is 0-100 in new mixer. 100 is treated as -0dB or 100% gain. No more weirdness to work around SDL_mixer
|
||||
// problems
|
||||
|
||||
#define MAX_VOLUME 100
|
||||
|
||||
#ifdef HAVE_CURL
|
||||
#define MASTERSERVER
|
||||
|
|
|
|||
17
src/g_demo.c
17
src/g_demo.c
|
|
@ -96,7 +96,8 @@ static struct {
|
|||
|
||||
// EZT_ITEMDATA
|
||||
SINT8 itemtype;
|
||||
UINT8 itemamount, bumpers;
|
||||
UINT8 itemamount;
|
||||
INT32 health;
|
||||
|
||||
// EZT_STATDATA
|
||||
UINT8 skinid, kartspeed, kartweight;
|
||||
|
|
@ -356,7 +357,7 @@ void G_ReadDemoExtraData(void)
|
|||
if (players[p].mo)
|
||||
{
|
||||
// Is this how this should work..?
|
||||
K_DoIngameRespawn(&players[p]);
|
||||
P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_DEATHPIT);
|
||||
}
|
||||
}
|
||||
if (extradata & DXD_WEAPONPREF)
|
||||
|
|
@ -814,13 +815,13 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
|
|||
if (ghost->player && (
|
||||
ghostext[playernum].itemtype != ghost->player->itemtype ||
|
||||
ghostext[playernum].itemamount != ghost->player->itemamount ||
|
||||
ghostext[playernum].bumpers != ghost->player->bumpers
|
||||
ghostext[playernum].health < ghost->health
|
||||
))
|
||||
{
|
||||
ghostext[playernum].flags |= EZT_ITEMDATA;
|
||||
ghostext[playernum].itemtype = ghost->player->itemtype;
|
||||
ghostext[playernum].itemamount = ghost->player->itemamount;
|
||||
ghostext[playernum].bumpers = ghost->player->bumpers;
|
||||
ghostext[playernum].health = ghost->health;
|
||||
}
|
||||
|
||||
if (ghost->player && (
|
||||
|
|
@ -882,7 +883,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
|
|||
{
|
||||
WRITESINT8(demobuf.p, ghostext[playernum].itemtype);
|
||||
WRITEUINT8(demobuf.p, ghostext[playernum].itemamount);
|
||||
WRITEUINT8(demobuf.p, ghostext[playernum].bumpers);
|
||||
WRITEINT32(demobuf.p, ghostext[playernum].health);
|
||||
}
|
||||
if (ghostext[playernum].flags & EZT_STATDATA)
|
||||
{
|
||||
|
|
@ -1065,7 +1066,7 @@ void G_ConsGhostTic(INT32 playernum)
|
|||
{
|
||||
ghostext[playernum].itemtype = READSINT8(demobuf.p);
|
||||
ghostext[playernum].itemamount = READUINT8(demobuf.p);
|
||||
ghostext[playernum].bumpers = READUINT8(demobuf.p);
|
||||
ghostext[playernum].health = READINT32(demobuf.p);
|
||||
}
|
||||
if (xziptic & EZT_STATDATA)
|
||||
{
|
||||
|
|
@ -1135,7 +1136,7 @@ void G_ConsGhostTic(INT32 playernum)
|
|||
|
||||
if (players[playernum].itemtype != ghostext[playernum].itemtype
|
||||
|| players[playernum].itemamount != ghostext[playernum].itemamount
|
||||
|| players[playernum].bumpers != ghostext[playernum].bumpers)
|
||||
|| testmo->health < ghostext[playernum].health)
|
||||
{
|
||||
if (demosynced)
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (item/bumpers)!\n"));
|
||||
|
|
@ -1143,7 +1144,7 @@ void G_ConsGhostTic(INT32 playernum)
|
|||
|
||||
players[playernum].itemtype = ghostext[playernum].itemtype;
|
||||
players[playernum].itemamount = ghostext[playernum].itemamount;
|
||||
players[playernum].bumpers = ghostext[playernum].bumpers;
|
||||
testmo->health = ghostext[playernum].health;
|
||||
}
|
||||
|
||||
if (players[playernum].kartspeed != ghostext[playernum].kartspeed
|
||||
|
|
|
|||
245
src/g_game.c
245
src/g_game.c
|
|
@ -523,7 +523,7 @@ void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord)
|
|||
break;
|
||||
}
|
||||
case ET_MAP:
|
||||
{
|
||||
{
|
||||
if (emblem->flags & ME_SPBATTACK && cv_dummyspbattack.value)
|
||||
break;
|
||||
goto bademblem;
|
||||
|
|
@ -873,32 +873,49 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming)
|
|||
return (INT16)((*aiming)>>16);
|
||||
}
|
||||
|
||||
// Default controls for keyboard. These are hardcoded and cannot be changed.
|
||||
static INT32 keyboardMenuDefaults[][2] = {
|
||||
{gc_a, KEY_ENTER},
|
||||
{gc_c, KEY_BACKSPACE},
|
||||
{gc_x, KEY_ESCAPE},
|
||||
{gc_left, KEY_LEFTARROW},
|
||||
{gc_right, KEY_RIGHTARROW},
|
||||
{gc_up, KEY_UPARROW},
|
||||
{gc_down, KEY_DOWNARROW},
|
||||
static INT32 G_GetValueFromControlTable(INT32 deviceID, INT32 deadzone, INT32 *controltable)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
// special control
|
||||
{gc_start, KEY_ESCAPE},
|
||||
// 8 total controls*
|
||||
};
|
||||
if (deviceID <= UNASSIGNED_DEVICE)
|
||||
{
|
||||
// An invalid device can't have any binds!
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KEYBOARDDEFAULTSSPLIT 7
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
{
|
||||
INT32 key = controltable[i];
|
||||
INT32 value = 0;
|
||||
|
||||
// Invalid key number.
|
||||
if (G_KeyIsAvailable(key, deviceID) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
value = G_GetDeviceGameKeyDownArray(deviceID)[key];
|
||||
|
||||
if (value >= deadzone)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Not pressed.
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers)
|
||||
{
|
||||
INT32 deviceID;
|
||||
INT32 i, j;
|
||||
INT32 deadzone = 0;
|
||||
boolean trydefaults = true;
|
||||
boolean tryingotherID = false;
|
||||
INT32 *controltable = &(gamecontrol[p][gc][0]);
|
||||
const INT32 deadzone = (JOYAXISRANGE * cv_deadzone[p].value) / FRACUNIT;
|
||||
const INT32 keyboard_player = G_GetPlayerForDevice(KEYBOARD_MOUSE_DEVICE);
|
||||
const boolean in_menu = (menuPlayers > 0);
|
||||
const boolean main_player = (p == 0);
|
||||
INT32 deviceID = UNASSIGNED_DEVICE;
|
||||
INT32 value = -1;
|
||||
INT32 avail_gamepad_id = 0;
|
||||
INT32 i;
|
||||
|
||||
if (p >= MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
|
|
@ -908,118 +925,96 @@ INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers)
|
|||
return 0;
|
||||
}
|
||||
|
||||
deadzone = (JOYAXISRANGE * cv_deadzone[p].value) / FRACUNIT;
|
||||
deviceID = G_GetDeviceForPlayer(p);
|
||||
|
||||
deviceID = cv_usejoystick[p].value;
|
||||
|
||||
retrygetcontrol:
|
||||
for (i = 0; i < MAXINPUTMAPPING; i++)
|
||||
if ((in_menu == true && G_KeyBindIsNecessary(gc) == true) // In menu: check for all unoverrideable menu default controls.
|
||||
|| (in_menu == false && gc == gc_start)) // In gameplay: check for the unoverrideable start button to be able to bring up the menu.
|
||||
{
|
||||
INT32 key = controltable[i];
|
||||
INT32 menukey = KEY_NULL;
|
||||
INT32 value = 0;
|
||||
boolean processinput = true;
|
||||
|
||||
|
||||
// for menus, keyboards have defaults!
|
||||
if (deviceID == 0)
|
||||
value = G_GetValueFromControlTable(KEYBOARD_MOUSE_DEVICE, JOYAXISRANGE/4, &(menucontrolreserved[gc][0]));
|
||||
if (value > 0) // Check for press instead of bound.
|
||||
{
|
||||
|
||||
// In menus, check indexes 0 through 5 (everything besides gc_start)
|
||||
// Outside of menus, only consider the hardcoded input for gc_start at index 6
|
||||
|
||||
INT32 maxj = menuactive ? KEYBOARDDEFAULTSSPLIT : KEYBOARDDEFAULTSSPLIT+1;
|
||||
j = (!menuactive) ? KEYBOARDDEFAULTSSPLIT : 0;
|
||||
|
||||
for (; j < maxj; j++) // check keyboardMenuDefaults
|
||||
{
|
||||
// the gc we're looking for
|
||||
if (gc == keyboardMenuDefaults[j][0])
|
||||
{
|
||||
menukey = keyboardMenuDefaults[j][1];
|
||||
break;
|
||||
}
|
||||
|
||||
// The key is mapped to *something else*...?
|
||||
// Then don't process that as it would conflict with our hardcoded inputs.
|
||||
else if (key == keyboardMenuDefaults[j][1])
|
||||
{
|
||||
processinput = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid key number.
|
||||
if (!G_KeyIsAvailable(key, deviceID) && !G_KeyIsAvailable(menukey, deviceID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (processinput)
|
||||
{
|
||||
// It's possible to access this control right now, so let's disable the default control backup for later.
|
||||
trydefaults = false;
|
||||
|
||||
value = gamekeydown[deviceID][key];
|
||||
if (menukey && gamekeydown[deviceID][menukey])
|
||||
value = gamekeydown[deviceID][menukey];
|
||||
|
||||
if (value >= deadzone)
|
||||
// This is only intended for P1.
|
||||
if (main_player == true)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you're on controller, try your keyboard-based binds as an immediate backup.
|
||||
// Do not do this if there are more than 1 local player.
|
||||
if (p == 0 && deviceID > 0 && !tryingotherID && menuPlayers < 2 && !splitscreen)
|
||||
// Player 1 is always allowed to use the keyboard in 1P, even if they got disconnected.
|
||||
if (main_player == true && keyboard_player == -1 && deviceID == UNASSIGNED_DEVICE)
|
||||
{
|
||||
deviceID = 0;
|
||||
goto retrygetcontrol;
|
||||
deviceID = KEYBOARD_MOUSE_DEVICE;
|
||||
}
|
||||
|
||||
if (menuPlayers == 0)
|
||||
// First, try our actual binds.
|
||||
value = G_GetValueFromControlTable(deviceID, deadzone, &(gamecontrol[p][gc][0]));
|
||||
if (value > 0)
|
||||
{
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
// We don't want menus to become unnavigable if people unbind
|
||||
// all of their controls, so we do several things in this scenario.
|
||||
// First: try other controllers.
|
||||
|
||||
if (!tryingotherID)
|
||||
// If you're on gamepad in 1P, and you didn't have a gamepad bind for this, then try your keyboard binds.
|
||||
if (main_player == true && keyboard_player == -1 && deviceID > KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
deviceID = MAXDEVICES;
|
||||
tryingotherID = true;
|
||||
}
|
||||
loweringid:
|
||||
deviceID--;
|
||||
if (deviceID > 0)
|
||||
{
|
||||
for (i = 0; i < menuPlayers; i++)
|
||||
value = G_GetValueFromControlTable(KEYBOARD_MOUSE_DEVICE, deadzone, &(gamecontrol[p][gc][0]));
|
||||
if (value > 0)
|
||||
{
|
||||
if (deviceID != cv_usejoystick[i].value)
|
||||
continue;
|
||||
// Controller taken? Try again...
|
||||
goto loweringid;
|
||||
return value;
|
||||
}
|
||||
goto retrygetcontrol;
|
||||
}
|
||||
|
||||
if (trydefaults && G_KeyBindIsNecessary(gc))
|
||||
if (in_menu == true)
|
||||
{
|
||||
// If we still haven't found anything and the keybind is necessary,
|
||||
// try it all again but with default binds.
|
||||
trydefaults = false;
|
||||
controltable = &(gamecontroldefault[gc][0]);
|
||||
tryingotherID = false;
|
||||
deviceID = cv_usejoystick[p].value;
|
||||
goto retrygetcontrol;
|
||||
if (main_player == true)
|
||||
{
|
||||
// We are P1 controlling menus. We should be able to
|
||||
// control the menu with any unused gamepads, so
|
||||
// that gamepads are able to navigate to the player
|
||||
// setup menu in the first place.
|
||||
for (avail_gamepad_id = 0; avail_gamepad_id < G_GetNumAvailableGamepads(); avail_gamepad_id++)
|
||||
{
|
||||
INT32 tryDevice = G_GetAvailableGamepadDevice(avail_gamepad_id);
|
||||
if (tryDevice <= KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < menuPlayers; i++)
|
||||
{
|
||||
if (tryDevice == G_GetDeviceForPlayer(i))
|
||||
{
|
||||
// Don't do this for already taken devices.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == menuPlayers)
|
||||
{
|
||||
// This gamepad isn't being used, so we can
|
||||
// use it for P1 menu navigation.
|
||||
value = G_GetValueFromControlTable(tryDevice, deadzone, &(gamecontrol[p][gc][0]));
|
||||
if (value > 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still nothing bound after everything. Try default gamepad controls.
|
||||
value = G_GetValueFromControlTable(deviceID, deadzone, &(gamecontroldefault[gc][0]));
|
||||
if (value > 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Literally not bound at all, so it can't be pressed at all.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1542,7 +1537,7 @@ void G_DoLoadLevelEx(boolean resetplayer, gamestate_t newstate)
|
|||
|
||||
// clear cmd building stuff
|
||||
memset(gamekeydown, 0, sizeof (gamekeydown));
|
||||
memset(deviceResponding, false, sizeof (deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
|
||||
// clear hud messages remains (usually from game startup)
|
||||
CON_ClearHUD();
|
||||
|
|
@ -1862,7 +1857,7 @@ boolean G_Responder(event_t *ev)
|
|||
case ev_mouse:
|
||||
return true; // eat events
|
||||
|
||||
case ev_joystick:
|
||||
case ev_gamepad_axis:
|
||||
return true; // eat events
|
||||
|
||||
default:
|
||||
|
|
@ -1897,13 +1892,6 @@ boolean G_CouldView(INT32 playernum)
|
|||
if (( player->pflags & PF_NOCONTEST ))
|
||||
return false;
|
||||
|
||||
// I don't know if we want this actually, but I'll humor the suggestion anyway
|
||||
if ((gametyperules & GTR_BUMPERS) && !demo.playback)
|
||||
{
|
||||
if (player->bumpers <= 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// SRB2Kart: we have no team-based modes, YET...
|
||||
if (G_GametypeHasTeams())
|
||||
{
|
||||
|
|
@ -2145,7 +2133,19 @@ void G_Ticker(boolean run)
|
|||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
K_PlayerLoseLife(&players[i]);
|
||||
if (players[i].bot == true && grandprixinfo.gp == true && grandprixinfo.masterbots == false)
|
||||
{
|
||||
players[i].botvars.difficulty--;
|
||||
|
||||
if (players[i].botvars.difficulty < 1)
|
||||
{
|
||||
players[i].botvars.difficulty = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
K_PlayerLoseLife(&players[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2421,7 +2421,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
INT32 itemtype;
|
||||
INT32 itemamount;
|
||||
INT32 growshrinktimer;
|
||||
INT32 bumper;
|
||||
boolean songcredit = false;
|
||||
UINT16 nocontrol;
|
||||
INT32 khudfault;
|
||||
|
|
@ -2496,7 +2495,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
itemtype = 0;
|
||||
itemamount = 0;
|
||||
growshrinktimer = 0;
|
||||
bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0);
|
||||
if (gametyperules & GTR_SPHERES)
|
||||
{
|
||||
rings = 0;
|
||||
|
|
@ -2543,7 +2541,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
else
|
||||
growshrinktimer = 0;
|
||||
|
||||
bumper = players[player].bumpers;
|
||||
rings = players[player].rings;
|
||||
spheres = players[player].spheres;
|
||||
kickstartaccel = players[player].kickstartaccel;
|
||||
|
|
@ -2644,9 +2641,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
p->itemtype = itemtype;
|
||||
p->itemamount = itemamount;
|
||||
p->growshrinktimer = growshrinktimer;
|
||||
p->bumpers = bumper;
|
||||
p->karmadelay = comebacktime;
|
||||
p->overtimekarma = 0;
|
||||
p->karmadelay = 0;
|
||||
p->eggmanblame = -1;
|
||||
p->lastdraft = -1;
|
||||
p->karthud[khud_fault] = khudfault;
|
||||
|
|
|
|||
373
src/g_input.c
373
src/g_input.c
|
|
@ -19,6 +19,9 @@
|
|||
#include "d_net.h"
|
||||
#include "console.h"
|
||||
#include "i_joy.h" // JOYAXISRANGE
|
||||
#include "r_draw.h" // GTC_ macros for assigning gamepad indicator colors
|
||||
#include "v_video.h" // V_GetColor for assigning gamepad indictaor colors
|
||||
#include "z_zone.h"
|
||||
|
||||
#define MAXMOUSESENSITIVITY 100 // sensitivity steps
|
||||
|
||||
|
|
@ -35,11 +38,11 @@ consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecont
|
|||
// current state of the keys
|
||||
// FRACUNIT for fully pressed, 0 for not pressed
|
||||
INT32 gamekeydown[MAXDEVICES][NUMINPUTS];
|
||||
boolean deviceResponding[MAXDEVICES];
|
||||
|
||||
// two key codes (or virtual key) per game control
|
||||
INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][MAXINPUTMAPPING];
|
||||
INT32 gamecontroldefault[num_gamecontrols][MAXINPUTMAPPING]; // default control storage
|
||||
INT32 menucontrolreserved[num_gamecontrols][MAXINPUTMAPPING];
|
||||
|
||||
// lists of GC codes for selective operation
|
||||
/*
|
||||
|
|
@ -68,13 +71,82 @@ const INT32 gcl_full[num_gcl_full] = {
|
|||
};
|
||||
*/
|
||||
|
||||
INT32 G_GetDevicePlayer(INT32 deviceID)
|
||||
static INT32 g_gamekeydown_device0[NUMINPUTS];
|
||||
|
||||
static INT32 g_available_gamepad_devices;
|
||||
static INT32 g_gamepad_device_ids[MAXGAMEPADS];
|
||||
static INT32* g_gamepad_gamekeydown[MAXGAMEPADS];
|
||||
static boolean g_device0_responding;
|
||||
static boolean g_gamepad_responding[MAXGAMEPADS];
|
||||
static INT32 g_player_devices[MAXSPLITSCREENPLAYERS] = {-1, -1, -1, -1};
|
||||
|
||||
void G_RegisterAvailableGamepad(INT32 device_id)
|
||||
{
|
||||
I_Assert(device_id >= 1);
|
||||
|
||||
if (g_available_gamepad_devices == MAXGAMEPADS)
|
||||
{
|
||||
// too many!
|
||||
return;
|
||||
}
|
||||
|
||||
g_gamepad_device_ids[g_available_gamepad_devices] = device_id;
|
||||
|
||||
g_gamepad_gamekeydown[g_available_gamepad_devices] = Z_CallocAlign(NUMINPUTS * sizeof(INT32), PU_STATIC, NULL, 4);
|
||||
|
||||
g_gamepad_responding[g_available_gamepad_devices] = false;
|
||||
|
||||
g_available_gamepad_devices += 1;
|
||||
}
|
||||
|
||||
void G_UnregisterAvailableGamepad(INT32 device_id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
I_Assert(device_id >= 1);
|
||||
|
||||
if (g_available_gamepad_devices <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_available_gamepad_devices; i++)
|
||||
{
|
||||
if (g_gamepad_device_ids[i] == device_id)
|
||||
{
|
||||
int32_t *old_gamekeydown = g_gamepad_gamekeydown[i];
|
||||
g_gamepad_device_ids[i] = g_gamepad_device_ids[g_available_gamepad_devices - 1];
|
||||
g_gamepad_gamekeydown[i] = g_gamepad_gamekeydown[g_available_gamepad_devices - 1];
|
||||
g_gamepad_responding[i] = g_gamepad_responding[g_available_gamepad_devices - 1];
|
||||
Z_Free(old_gamekeydown);
|
||||
g_available_gamepad_devices -= 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INT32 G_GetNumAvailableGamepads(void)
|
||||
{
|
||||
return g_available_gamepad_devices;
|
||||
}
|
||||
|
||||
INT32 G_GetAvailableGamepadDevice(INT32 available_index)
|
||||
{
|
||||
if (available_index < 0 || available_index >= G_GetNumAvailableGamepads())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return g_gamepad_device_ids[available_index];
|
||||
}
|
||||
|
||||
INT32 G_GetPlayerForDevice(INT32 device_id)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (deviceID == cv_usejoystick[i].value)
|
||||
if (device_id == g_player_devices[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
|
@ -83,6 +155,203 @@ INT32 G_GetDevicePlayer(INT32 deviceID)
|
|||
return -1;
|
||||
}
|
||||
|
||||
INT32 G_GetDeviceForPlayer(INT32 player)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (G_GetPlayerForDevice(KEYBOARD_MOUSE_DEVICE) == player)
|
||||
{
|
||||
return KEYBOARD_MOUSE_DEVICE;
|
||||
}
|
||||
|
||||
for (i = 0; i < G_GetNumAvailableGamepads() + 1; i++)
|
||||
{
|
||||
INT32 device = G_GetAvailableGamepadDevice(i);
|
||||
if (G_GetPlayerForDevice(device) == player)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void G_SetDeviceForPlayer(INT32 player, INT32 device)
|
||||
{
|
||||
int i;
|
||||
|
||||
I_Assert(player >= 0 && player < MAXSPLITSCREENPLAYERS);
|
||||
I_Assert(device >= -1);
|
||||
|
||||
g_player_devices[player] = device;
|
||||
|
||||
if (device == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (device != KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
I_SetGamepadPlayerIndex(device, player);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (i == player)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g_player_devices[i] == device)
|
||||
{
|
||||
g_player_devices[i] = -1;
|
||||
if (device > 0)
|
||||
{
|
||||
I_SetGamepadPlayerIndex(device, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G_SetPlayerGamepadIndicatorToPlayerColor(INT32 player)
|
||||
{
|
||||
INT32 device;
|
||||
INT32 skin;
|
||||
UINT16 skincolor;
|
||||
UINT8 *colormap;
|
||||
byteColor_t byte_color;
|
||||
|
||||
I_Assert(player >= 0 && player < MAXSPLITSCREENPLAYERS);
|
||||
|
||||
device = G_GetDeviceForPlayer(player);
|
||||
|
||||
if (device <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
skin = cv_skin[player].value;
|
||||
skincolor = cv_playercolor[player].value;
|
||||
colormap = R_GetTranslationColormap(skin, skincolor, GTC_MENUCACHE);
|
||||
|
||||
if (colormap == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
byte_color = V_GetColor(colormap[104]).s;
|
||||
|
||||
I_SetGamepadIndicatorColor(device, byte_color.red, byte_color.green, byte_color.blue);
|
||||
}
|
||||
|
||||
INT32* G_GetDeviceGameKeyDownArray(INT32 device)
|
||||
{
|
||||
int i;
|
||||
|
||||
I_Assert(device >= 0);
|
||||
|
||||
if (device == KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
return g_gamekeydown_device0;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_available_gamepad_devices; i++)
|
||||
{
|
||||
if (g_gamepad_device_ids[i] == device)
|
||||
{
|
||||
return g_gamepad_gamekeydown[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
boolean G_IsDeviceResponding(INT32 device)
|
||||
{
|
||||
int i;
|
||||
|
||||
I_Assert(device >= 0);
|
||||
|
||||
if (device == KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
return g_device0_responding;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_available_gamepad_devices; i++)
|
||||
{
|
||||
INT32 device_id = G_GetAvailableGamepadDevice(i);
|
||||
if (device_id == device)
|
||||
{
|
||||
return g_gamepad_responding[i];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void G_SetDeviceResponding(INT32 device, boolean responding)
|
||||
{
|
||||
int i;
|
||||
|
||||
I_Assert(device >= 0);
|
||||
|
||||
if (device == KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
g_device0_responding = responding;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_available_gamepad_devices; i++)
|
||||
{
|
||||
INT32 device_id = G_GetAvailableGamepadDevice(i);
|
||||
if (device_id == device)
|
||||
{
|
||||
g_gamepad_responding[i] = responding;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G_ResetAllDeviceResponding(void)
|
||||
{
|
||||
int i;
|
||||
int num_gamepads;
|
||||
|
||||
g_device0_responding = false;
|
||||
|
||||
num_gamepads = G_GetNumAvailableGamepads();
|
||||
|
||||
for (i = 0; i < num_gamepads; i++)
|
||||
{
|
||||
g_gamepad_responding[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean AutomaticControllerReassignmentIsAllowed(INT32 device)
|
||||
{
|
||||
boolean device_is_gamepad = device > 0;
|
||||
boolean device_is_unassigned = G_GetPlayerForDevice(device) == -1;
|
||||
boolean gamestate_is_in_level = gamestate == GS_LEVEL;
|
||||
|
||||
return device_is_gamepad && device_is_unassigned && gamestate_is_in_level;
|
||||
}
|
||||
|
||||
static INT32 AssignDeviceToFirstUnassignedPlayer(INT32 device)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < splitscreen + 1; i++)
|
||||
{
|
||||
if (G_GetDeviceForPlayer(i) == -1)
|
||||
{
|
||||
G_SetDeviceForPlayer(i, device);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Remaps the inputs to game controls.
|
||||
//
|
||||
|
|
@ -94,15 +363,15 @@ void G_MapEventsToControls(event_t *ev)
|
|||
{
|
||||
INT32 i;
|
||||
|
||||
if (ev->device >= 0 && ev->device < MAXDEVICES)
|
||||
if (ev->device >= 0)
|
||||
{
|
||||
switch (ev->type)
|
||||
{
|
||||
case ev_keydown:
|
||||
//case ev_keyup:
|
||||
//case ev_mouse:
|
||||
//case ev_joystick:
|
||||
deviceResponding[ev->device] = true;
|
||||
//case ev_gamepad_axis:
|
||||
G_SetDeviceResponding(ev->device, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -119,7 +388,16 @@ void G_MapEventsToControls(event_t *ev)
|
|||
case ev_keydown:
|
||||
if (ev->data1 < NUMINPUTS)
|
||||
{
|
||||
gamekeydown[ev->device][ev->data1] = JOYAXISRANGE;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[ev->data1] = JOYAXISRANGE;
|
||||
|
||||
if (AutomaticControllerReassignmentIsAllowed(ev->device))
|
||||
{
|
||||
INT32 assigned = AssignDeviceToFirstUnassignedPlayer(ev->device);
|
||||
if (assigned >= 0)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, "Player %d device was reassigned\n", assigned + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef PARANOIA
|
||||
else
|
||||
|
|
@ -132,7 +410,7 @@ void G_MapEventsToControls(event_t *ev)
|
|||
case ev_keyup:
|
||||
if (ev->data1 < NUMINPUTS)
|
||||
{
|
||||
gamekeydown[ev->device][ev->data1] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[ev->data1] = 0;
|
||||
}
|
||||
#ifdef PARANOIA
|
||||
else
|
||||
|
|
@ -147,32 +425,32 @@ void G_MapEventsToControls(event_t *ev)
|
|||
if (ev->data2 < 0)
|
||||
{
|
||||
// Left
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 2] = abs(ev->data2);
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 3] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 2] = abs(ev->data2);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 2] = 0;
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 3] = abs(ev->data2);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 2] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 3] = abs(ev->data2);
|
||||
}
|
||||
|
||||
// Y axis
|
||||
if (ev->data3 < 0)
|
||||
{
|
||||
// Up
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE] = abs(ev->data3);
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 1] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE] = abs(ev->data3);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Down
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE] = 0;
|
||||
gamekeydown[ev->device][KEY_MOUSEMOVE + 1] = abs(ev->data3);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_MOUSEMOVE + 1] = abs(ev->data3);
|
||||
}
|
||||
break;
|
||||
|
||||
case ev_joystick: // buttons are virtual keys
|
||||
case ev_gamepad_axis: // buttons are virtual keys
|
||||
if (ev->data1 >= JOYAXISSETS)
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
|
|
@ -190,12 +468,12 @@ void G_MapEventsToControls(event_t *ev)
|
|||
|
||||
if (ev->data2 != INT32_MAX)
|
||||
{
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2)] = max(0, ev->data2);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2)] = max(0, ev->data2);
|
||||
}
|
||||
|
||||
if (ev->data3 != INT32_MAX)
|
||||
{
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2) + 1] = max(0, ev->data3);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (JOYANALOGS * 4) + (i * 2) + 1] = max(0, ev->data3);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -206,14 +484,14 @@ void G_MapEventsToControls(event_t *ev)
|
|||
if (ev->data2 < 0)
|
||||
{
|
||||
// Left
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4)] = abs(ev->data2);
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 1] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4)] = abs(ev->data2);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4)] = 0;
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 1] = abs(ev->data2);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4)] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 1] = abs(ev->data2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,14 +500,14 @@ void G_MapEventsToControls(event_t *ev)
|
|||
if (ev->data3 < 0)
|
||||
{
|
||||
// Up
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 2] = abs(ev->data3);
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 3] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 2] = abs(ev->data3);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Down
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 2] = 0;
|
||||
gamekeydown[ev->device][KEY_AXIS1 + (i * 4) + 3] = abs(ev->data3);
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 2] = 0;
|
||||
G_GetDeviceGameKeyDownArray(ev->device)[KEY_AXIS1 + (i * 4) + 3] = abs(ev->data3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -405,12 +683,13 @@ boolean G_KeyBindIsNecessary(INT32 gc)
|
|||
switch (gc)
|
||||
{
|
||||
case gc_a:
|
||||
case gc_b:
|
||||
case gc_c:
|
||||
case gc_x:
|
||||
case gc_up:
|
||||
case gc_down:
|
||||
case gc_left:
|
||||
case gc_right:
|
||||
case gc_start:
|
||||
//case gc_start: // Is necessary, but handled special.
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -421,25 +700,31 @@ boolean G_KeyBindIsNecessary(INT32 gc)
|
|||
// Returns false if a key is deemed unreachable for this device.
|
||||
boolean G_KeyIsAvailable(INT32 key, INT32 deviceID)
|
||||
{
|
||||
boolean gamepad_key = false;
|
||||
|
||||
// Invalid key number.
|
||||
if (key <= 0 || key >= NUMINPUTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Valid controller-specific virtual key, but no controller attached for player.
|
||||
if (key >= KEY_JOY1 && key < JOYINPUTEND && deviceID <= 0)
|
||||
// Only allow gamepad keys for gamepad devices,
|
||||
// and vice versa.
|
||||
gamepad_key = (key >= KEY_JOY1 && key < JOYINPUTEND);
|
||||
if (deviceID == KEYBOARD_MOUSE_DEVICE)
|
||||
{
|
||||
return false;
|
||||
if (gamepad_key == true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Valid mouse-specific virtual key, but no mouse attached for player. TODO HOW TO DETECT ACTIVE MOUSE CONNECTION
|
||||
/*
|
||||
if (key >= KEY_MOUSE1 && key < MOUSEINPUTEND && ????????)
|
||||
else
|
||||
{
|
||||
return false;
|
||||
if (gamepad_key == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -538,7 +823,7 @@ void G_DefineDefaultControls(void)
|
|||
gamecontroldefault[gc_z ][0] = 'd';
|
||||
gamecontroldefault[gc_l ][0] = 'q';
|
||||
gamecontroldefault[gc_r ][0] = 'e';
|
||||
gamecontroldefault[gc_start ][0] = KEY_ESCAPE; // *
|
||||
gamecontroldefault[gc_start ][0] = KEY_ESCAPE;
|
||||
gamecontroldefault[gc_rankings][0] = KEY_TAB;
|
||||
|
||||
// Gamepad controls
|
||||
|
|
@ -560,6 +845,16 @@ void G_DefineDefaultControls(void)
|
|||
gamecontroldefault[gc_down ][2] = KEY_AXIS1+3; // Axis Y+
|
||||
gamecontroldefault[gc_left ][2] = KEY_AXIS1+0; // Axis X-
|
||||
gamecontroldefault[gc_right][2] = KEY_AXIS1+1; // Axis X+
|
||||
|
||||
// Menu reserved controls
|
||||
menucontrolreserved[gc_up ][0] = KEY_UPARROW;
|
||||
menucontrolreserved[gc_down ][0] = KEY_DOWNARROW;
|
||||
menucontrolreserved[gc_left ][0] = KEY_LEFTARROW;
|
||||
menucontrolreserved[gc_right][0] = KEY_RIGHTARROW;
|
||||
menucontrolreserved[gc_a ][0] = KEY_ENTER;
|
||||
menucontrolreserved[gc_c ][0] = KEY_BACKSPACE;
|
||||
menucontrolreserved[gc_x ][0] = KEY_ESCAPE;
|
||||
menucontrolreserved[gc_start][0] = KEY_ESCAPE; // Handled special
|
||||
}
|
||||
|
||||
void G_CopyControls(INT32 (*setupcontrols)[MAXINPUTMAPPING], INT32 (*fromcontrols)[MAXINPUTMAPPING], const INT32 *gclist, INT32 gclen)
|
||||
|
|
|
|||
|
|
@ -107,12 +107,14 @@ extern consvar_t cv_controlperkey;
|
|||
// current state of the keys: JOYAXISRANGE or 0 when boolean.
|
||||
// Or anything inbetween for analog values
|
||||
#define MAXDEVICES (MAXGAMEPADS + 1) // Gamepads + keyboard & mouse
|
||||
#define KEYBOARD_MOUSE_DEVICE (0)
|
||||
#define UNASSIGNED_DEVICE (-1)
|
||||
extern INT32 gamekeydown[MAXDEVICES][NUMINPUTS];
|
||||
extern boolean deviceResponding[MAXDEVICES];
|
||||
|
||||
// several key codes (or virtual key) per game control
|
||||
extern INT32 gamecontrol[MAXSPLITSCREENPLAYERS][num_gamecontrols][MAXINPUTMAPPING];
|
||||
extern INT32 gamecontroldefault[num_gamecontrols][MAXINPUTMAPPING]; // default control storage
|
||||
extern INT32 menucontrolreserved[num_gamecontrols][MAXINPUTMAPPING];
|
||||
|
||||
/*
|
||||
#define num_gcl_accelerate 1
|
||||
|
|
@ -135,7 +137,33 @@ extern const INT32 gcl_full[num_gcl_full];
|
|||
// peace to my little coder fingers!
|
||||
// check a gamecontrol being active or not
|
||||
|
||||
INT32 G_GetDevicePlayer(INT32 deviceID);
|
||||
/*
|
||||
*/
|
||||
|
||||
/// Register a device index (from ev_gamepad_device_added) as an Available Gamepad
|
||||
void G_RegisterAvailableGamepad(INT32 device_id);
|
||||
/// Unregister a device index (from ev_gamepad_device_removed) as an Available Gamepad
|
||||
void G_UnregisterAvailableGamepad(INT32 device_id);
|
||||
/// Get the number of Available Gamepads registered.
|
||||
INT32 G_GetNumAvailableGamepads(void);
|
||||
/// Get the device ID for a given Available Gamepad Index, or -1. 0 <= available_index < G_GetNumAvailableGamepads()
|
||||
INT32 G_GetAvailableGamepadDevice(INT32 available_index);
|
||||
|
||||
INT32 G_GetPlayerForDevice(INT32 deviceID);
|
||||
/// Get gamepad device for given player, or -1.
|
||||
INT32 G_GetDeviceForPlayer(INT32 player);
|
||||
|
||||
/// Set the given player index's assigned device. If the device is in use by another player, that player is unassigned.
|
||||
void G_SetDeviceForPlayer(INT32 player, INT32 device);
|
||||
|
||||
void G_SetPlayerGamepadIndicatorToPlayerColor(INT32 player);
|
||||
|
||||
/// Get the gamekeydown array (NUMINPUTS values) for the given device, or NULL if the device id is invalid.
|
||||
INT32* G_GetDeviceGameKeyDownArray(INT32 device);
|
||||
|
||||
boolean G_IsDeviceResponding(INT32 device);
|
||||
void G_SetDeviceResponding(INT32 device, boolean responding);
|
||||
void G_ResetAllDeviceResponding(void);
|
||||
|
||||
// remaps the input event to a game control.
|
||||
void G_MapEventsToControls(event_t *ev);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ struct JoyType_t
|
|||
|
||||
extern JoyType_t Joystick[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
void I_SetGamepadPlayerIndex(INT32 device_id, INT32 index);
|
||||
void I_SetGamepadIndicatorColor(INT32 device_id, UINT8 red, UINT8 green, UINT8 blue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -214,7 +214,8 @@ void I_PauseSong(void);
|
|||
*/
|
||||
void I_ResumeSong(void);
|
||||
|
||||
/** \brief The I_SetMusicVolume function
|
||||
/** \brief Sets the volume of the Music mixing channel. Distinguished from the song's individual volume. The scale of
|
||||
the volume is determined by the interface implementation.
|
||||
|
||||
\param volume volume to set at
|
||||
|
||||
|
|
@ -222,6 +223,13 @@ void I_ResumeSong(void);
|
|||
*/
|
||||
void I_SetMusicVolume(int volume);
|
||||
|
||||
/** \brief Sets the current song's volume, independent of the overall music channel volume. The volume scale is 0-100,
|
||||
* as a linear gain multiplier. This is distinguished from SetMusicVolume which may or may not be linear.
|
||||
*/
|
||||
void I_SetCurrentSongVolume(int volume);
|
||||
|
||||
// TODO refactor fades to control Song Volume exclusively in tandem with RR musicdef volume multiplier.
|
||||
|
||||
boolean I_SetSongTrack(INT32 track);
|
||||
|
||||
/// ------------------------
|
||||
|
|
|
|||
|
|
@ -205,9 +205,8 @@ void I_JoyScale4(void);
|
|||
|
||||
// Called by D_SRB2Main.
|
||||
|
||||
/** \brief to startup a joystick
|
||||
*/
|
||||
void I_InitJoystick(UINT8 index);
|
||||
/// Startup input subsystems.
|
||||
void I_StartupInput(void);
|
||||
|
||||
/** \brief to startup the first joystick
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -23907,7 +23907,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
16, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
MF_SOLID|MF_NOCLIP|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ UINT8 numtargets = 0; // Capsules busted
|
|||
INT32 K_StartingBumperCount(void)
|
||||
{
|
||||
if (battleprisons)
|
||||
return 1; // always 1 hit in Break the Capsules
|
||||
return 0; // always 1 hit in Prison Break
|
||||
|
||||
return cv_kartbumpers.value;
|
||||
}
|
||||
|
|
@ -95,8 +95,6 @@ void K_CheckBumpers(void)
|
|||
UINT8 nobumpers = 0;
|
||||
UINT8 eliminated = 0;
|
||||
|
||||
const boolean singleplayer = (battleprisons || bossinfo.valid);
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
return;
|
||||
|
||||
|
|
@ -113,7 +111,7 @@ void K_CheckBumpers(void)
|
|||
|
||||
numingame++;
|
||||
|
||||
if (players[i].bumpers <= 0) // if you don't have any bumpers, you're probably not a winner
|
||||
if (!P_MobjWasRemoved(players[i].mo) && players[i].mo->health <= 0) // if you don't have any bumpers, you're probably not a winner
|
||||
{
|
||||
nobumpers++;
|
||||
}
|
||||
|
|
@ -124,7 +122,7 @@ void K_CheckBumpers(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (singleplayer
|
||||
if (K_Cooperative()
|
||||
? nobumpers > 0 && nobumpers >= numingame
|
||||
: eliminated >= numingame - 1)
|
||||
{
|
||||
|
|
@ -135,7 +133,7 @@ void K_CheckBumpers(void)
|
|||
if (players[i].spectator)
|
||||
continue;
|
||||
|
||||
if (singleplayer)
|
||||
if (K_Cooperative())
|
||||
players[i].pflags |= PF_NOCONTEST;
|
||||
|
||||
P_DoPlayerExit(&players[i]);
|
||||
|
|
@ -170,7 +168,7 @@ void K_CheckEmeralds(player_t *player)
|
|||
return;
|
||||
}
|
||||
|
||||
player->roundscore++; // lol
|
||||
player->roundscore = 100; // lmao
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -179,11 +177,6 @@ void K_CheckEmeralds(player_t *player)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (&players[i] == player)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
P_DoPlayerExit(&players[i]);
|
||||
}
|
||||
}
|
||||
|
|
@ -319,6 +312,21 @@ static inline boolean IsOnInterval(tic_t interval)
|
|||
return ((leveltime - starttime) % interval) == 0;
|
||||
}
|
||||
|
||||
static UINT32 CountEmeraldsSpawned(const mobj_t *mo)
|
||||
{
|
||||
switch (mo->type)
|
||||
{
|
||||
case MT_EMERALD:
|
||||
return mo->extravalue1;
|
||||
|
||||
case MT_MONITOR:
|
||||
return Obj_MonitorGetEmerald(mo);
|
||||
|
||||
default:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void K_RunPaperItemSpawners(void)
|
||||
{
|
||||
const boolean overtime = (battleovertime.enabled >= 10*TICRATE);
|
||||
|
|
@ -362,7 +370,7 @@ void K_RunPaperItemSpawners(void)
|
|||
emeraldsSpawned |= players[i].emeralds;
|
||||
|
||||
if ((players[i].exiting > 0 || (players[i].pflags & PF_ELIMINATED))
|
||||
|| ((gametyperules & GTR_BUMPERS) && players[i].bumpers <= 0))
|
||||
|| ((gametyperules & GTR_BUMPERS) && !P_MobjWasRemoved(players[i].mo) && players[i].mo->health <= 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -382,10 +390,7 @@ void K_RunPaperItemSpawners(void)
|
|||
|
||||
mo = (mobj_t *)th;
|
||||
|
||||
if (mo->type == MT_EMERALD)
|
||||
{
|
||||
emeraldsSpawned |= mo->extravalue1;
|
||||
}
|
||||
emeraldsSpawned |= CountEmeraldsSpawned(mo);
|
||||
}
|
||||
|
||||
if (canmakeemeralds)
|
||||
|
|
@ -444,15 +449,7 @@ void K_RunPaperItemSpawners(void)
|
|||
|
||||
mo = (mobj_t *)th;
|
||||
|
||||
if (mo->type == MT_EMERALD)
|
||||
{
|
||||
emeraldsSpawned |= mo->extravalue1;
|
||||
}
|
||||
|
||||
if (mo->type == MT_MONITOR)
|
||||
{
|
||||
emeraldsSpawned |= Obj_MonitorGetEmerald(mo);
|
||||
}
|
||||
emeraldsSpawned |= CountEmeraldsSpawned(mo);
|
||||
|
||||
if (mo->type != MT_PAPERITEMSPOT)
|
||||
continue;
|
||||
|
|
@ -738,16 +735,20 @@ void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj)
|
|||
|
||||
void K_SpawnPlayerBattleBumpers(player_t *p)
|
||||
{
|
||||
if (!p->mo || p->bumpers <= 0)
|
||||
const UINT8 bumpers = K_Bumpers(p);
|
||||
|
||||
if (bumpers <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
INT32 i;
|
||||
angle_t diff = FixedAngle(360*FRACUNIT/p->bumpers);
|
||||
angle_t diff = FixedAngle(360*FRACUNIT / bumpers);
|
||||
angle_t newangle = p->mo->angle;
|
||||
mobj_t *bump;
|
||||
|
||||
for (i = 0; i < p->bumpers; i++)
|
||||
for (i = 0; i < bumpers; i++)
|
||||
{
|
||||
bump = P_SpawnMobjFromMobj(p->mo,
|
||||
P_ReturnThrustX(p->mo, newangle + ANGLE_180, 64*FRACUNIT),
|
||||
|
|
@ -784,21 +785,49 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
INT32 maxbumpers = K_StartingBumperCount();
|
||||
const INT32 startingHealth = K_BumpersToHealth(K_StartingBumperCount());
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
|
||||
players[i].bumpers = maxbumpers;
|
||||
|
||||
if (players[i].mo)
|
||||
{
|
||||
players[i].mo->health = maxbumpers;
|
||||
players[i].mo->health = startingHealth;
|
||||
}
|
||||
|
||||
K_SpawnPlayerBattleBumpers(players+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 K_Bumpers(player_t *player)
|
||||
{
|
||||
if ((gametyperules & GTR_BUMPERS) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (player->mo->health < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (player->mo->health > UINT8_MAX)
|
||||
{
|
||||
return UINT8_MAX;
|
||||
}
|
||||
|
||||
return (player->mo->health - 1);
|
||||
}
|
||||
|
||||
INT32 K_BumpersToHealth(UINT8 bumpers)
|
||||
{
|
||||
return (bumpers + 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ void K_RunBattleOvertime(void);
|
|||
void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj);
|
||||
void K_SpawnPlayerBattleBumpers(player_t *p);
|
||||
void K_BattleInit(boolean singleplayercontext);
|
||||
UINT8 K_Bumpers(player_t *player);
|
||||
INT32 K_BumpersToHealth(UINT8 bumpers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
|
|||
{
|
||||
boolean damageitem = false;
|
||||
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
|
||||
return true;
|
||||
|
||||
|
|
@ -133,9 +130,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
// Push fakes out of other item boxes
|
||||
if (t2->type == MT_RANDOMITEM || t2->type == MT_EGGMANITEM)
|
||||
{
|
||||
|
|
@ -154,14 +148,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
|
|||
if (!P_CanPickupItem(t2->player, 2))
|
||||
return true;
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && t2->player->bumpers <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
K_StartEggmanRoulette(t2->player);
|
||||
}
|
||||
K_StartEggmanRoulette(t2->player);
|
||||
|
||||
if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD)
|
||||
{
|
||||
|
|
@ -182,10 +169,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
if (t1->target && t1->target->player)
|
||||
{
|
||||
if ((gametyperules & GTR_CIRCUIT) || t1->target->player->bumpers > 0)
|
||||
t2->player->eggmanblame = t1->target->player-players;
|
||||
else
|
||||
t2->player->eggmanblame = t2->player-players;
|
||||
t2->player->eggmanblame = t1->target->player - players;
|
||||
|
||||
if (t1->target->hnext == t1)
|
||||
{
|
||||
|
|
@ -323,6 +307,10 @@ tic_t K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin)
|
|||
// Set this flag to ensure that the inital action won't be triggered twice.
|
||||
actor->flags2 |= MF2_DEBRIS;
|
||||
|
||||
// Set this flag to ensure the hitbox timer doesn't get extended with every player hit
|
||||
actor->flags |= MF_NOHITLAGFORME;
|
||||
actor->hitlag = 0; // same deal
|
||||
|
||||
if (!spin)
|
||||
{
|
||||
if (minehitlag == 0)
|
||||
|
|
@ -340,9 +328,6 @@ tic_t K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin)
|
|||
|
||||
boolean K_MineCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
|
||||
return true;
|
||||
|
||||
|
|
@ -394,9 +379,6 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
|
||||
return true;
|
||||
|
||||
|
|
@ -483,9 +465,6 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2)
|
|||
{
|
||||
mobj_t *draggeddroptarget = (t1->type == MT_DROPTARGET_SHIELD) ? t1->target : NULL;
|
||||
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
if (((t1->target == t2) || (t1->target == t2->target)) && ((t1->threshold > 0 && t2->type == MT_PLAYER) || (t2->type != MT_PLAYER && t2->threshold > 0)))
|
||||
return true;
|
||||
|
||||
|
|
@ -696,6 +675,17 @@ void K_LightningShieldAttack(mobj_t *actor, fixed_t size)
|
|||
|
||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if (t1->type == MT_PLAYER)
|
||||
{
|
||||
// Bubble Shield already has a hitbox, and it gets
|
||||
// teleported every tic so the Bubble itself will
|
||||
// always make contact with other objects.
|
||||
//
|
||||
// Therefore, we don't need a second, smaller hitbox
|
||||
// on the player. It'll just cause unwanted hitlag.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t2->type == MT_PLAYER)
|
||||
{
|
||||
// Counter desyncs
|
||||
|
|
@ -715,8 +705,13 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
|||
}
|
||||
|
||||
// Player Damage
|
||||
P_DamageMobj(t2, ((t1->type == MT_BUBBLESHIELD) ? t1->target : t1), t1, 1, DMG_NORMAL|DMG_WOMBO);
|
||||
S_StartSound(t1, sfx_s3k44);
|
||||
P_DamageMobj(t2, t1->target, t1, 1, DMG_NORMAL|DMG_WOMBO);
|
||||
|
||||
if (t2->player->timeshit > t2->player->timeshitprev)
|
||||
{
|
||||
// Don't play from t1 else it gets cut out... for some reason.
|
||||
S_StartSound(t2, sfx_s3k44);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -746,9 +741,6 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
|
||||
return true;
|
||||
|
||||
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
|
||||
return true;
|
||||
|
||||
|
|
|
|||
62
src/k_hud.c
62
src/k_hud.c
|
|
@ -1995,10 +1995,12 @@ static boolean K_drawKartPositionFaces(void)
|
|||
|
||||
if (LUA_HudEnabled(hud_battlebumpers))
|
||||
{
|
||||
if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumpers > 0)
|
||||
const UINT8 bumpers = K_Bumpers(&players[rankplayer[i]]);
|
||||
|
||||
if (bumpers > 0)
|
||||
{
|
||||
V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[0], colormap);
|
||||
for (j = 1; j < players[rankplayer[i]].bumpers; j++)
|
||||
for (j = 1; j < bumpers; j++)
|
||||
{
|
||||
bumperx += 5;
|
||||
V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[1], colormap);
|
||||
|
|
@ -2023,7 +2025,7 @@ static boolean K_drawKartPositionFaces(void)
|
|||
if (i == strank)
|
||||
V_DrawScaledPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_facehighlight[(leveltime / 4) % 8]);
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumpers <= 0)
|
||||
if ((gametyperules & GTR_BUMPERS) && (players[rankplayer[i]].pflags & PF_ELIMINATED))
|
||||
V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_ranknobumpers);
|
||||
else
|
||||
{
|
||||
|
|
@ -2356,7 +2358,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
|
|||
if (tab[i].num == whiteplayer)
|
||||
V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]);
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && players[tab[i].num].bumpers <= 0)
|
||||
if ((gametyperules & GTR_BUMPERS) && (players[tab[i].num].pflags & PF_ELIMINATED))
|
||||
V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers);
|
||||
else
|
||||
{
|
||||
|
|
@ -2866,14 +2868,16 @@ static void K_drawKartBumpersOrKarma(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
INT32 maxbumper = K_StartingBumperCount();
|
||||
const INT32 maxbumper = K_StartingBumperCount();
|
||||
const UINT8 bumpers = K_Bumpers(stplyr);
|
||||
|
||||
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
|
||||
|
||||
if (stplyr->bumpers > 9 || maxbumper > 9)
|
||||
if (bumpers > 9 || maxbumper > 9)
|
||||
{
|
||||
UINT8 ln[2];
|
||||
ln[0] = (stplyr->bumpers / 10 % 10);
|
||||
ln[1] = (stplyr->bumpers % 10);
|
||||
ln[0] = (bumpers / 10 % 10);
|
||||
ln[1] = (bumpers % 10);
|
||||
|
||||
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
|
||||
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
|
||||
|
|
@ -2886,7 +2890,7 @@ static void K_drawKartBumpersOrKarma(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->bumpers) % 10]);
|
||||
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(bumpers) % 10]);
|
||||
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]);
|
||||
}
|
||||
}
|
||||
|
|
@ -2903,17 +2907,15 @@ static void K_drawKartBumpersOrKarma(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
INT32 maxbumper = K_StartingBumperCount();
|
||||
const INT32 maxbumper = K_StartingBumperCount();
|
||||
const UINT8 bumpers = K_Bumpers(stplyr);
|
||||
|
||||
if (stplyr->bumpers > 9 && maxbumper > 9)
|
||||
if (bumpers > 9 && maxbumper > 9)
|
||||
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap);
|
||||
else
|
||||
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap);
|
||||
|
||||
if (gametyperules & GTR_KARMA) // TODO BETTER HUD
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d %d", stplyr->bumpers, maxbumper, stplyr->overtimekarma / TICRATE));
|
||||
else
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->bumpers, maxbumper));
|
||||
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", bumpers, maxbumper));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3366,12 +3368,6 @@ static void K_drawKartNameTags(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && (ntplayer->bumpers <= 0))
|
||||
{
|
||||
// Dead in Battle
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!P_CheckSight(stplyr->mo, ntplayer->mo))
|
||||
{
|
||||
// Can't see
|
||||
|
|
@ -3644,6 +3640,10 @@ static void K_drawKartMinimap(void)
|
|||
if (!players[i].mo || players[i].spectator || !players[i].mo->skin || players[i].exiting)
|
||||
continue;
|
||||
|
||||
// This player is out of the game!
|
||||
if ((gametyperules & GTR_BUMPERS) && (players[i].pflags & PF_ELIMINATED))
|
||||
continue;
|
||||
|
||||
if (i == displayplayers[0] || i == displayplayers[1] || i == displayplayers[2] || i == displayplayers[3])
|
||||
{
|
||||
// Draw display players on top of everything else
|
||||
|
|
@ -3651,10 +3651,6 @@ static void K_drawKartMinimap(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Now we know it's not a display player, handle non-local player exceptions.
|
||||
if ((gametyperules & GTR_BUMPERS) && players[i].bumpers <= 0)
|
||||
continue;
|
||||
|
||||
if (players[i].hyudorotimer > 0)
|
||||
{
|
||||
if (!((players[i].hyudorotimer < TICRATE/2
|
||||
|
|
@ -3866,19 +3862,22 @@ static void K_drawKartFinish(boolean finish)
|
|||
|
||||
//else -- 1/2p, scrolling FINISH
|
||||
{
|
||||
INT32 x, xval, ox, interpx;
|
||||
INT32 x, xval, ox, interpx, pwidth;
|
||||
|
||||
x = ((vid.width<<FRACBITS)/vid.dupx);
|
||||
xval = (SHORT(kptodraw[pnum]->width)<<FRACBITS);
|
||||
x = ((TICRATE - timer)*(xval > x ? xval : x))/TICRATE;
|
||||
ox = ((TICRATE - (timer - 1))*(xval > x ? xval : x))/TICRATE;
|
||||
|
||||
pwidth = max(xval, x);
|
||||
|
||||
x = ((TICRATE - timer) * pwidth) / TICRATE;
|
||||
ox = ((TICRATE - (timer - 1)) * pwidth) / TICRATE;
|
||||
|
||||
interpx = R_InterpolateFixed(ox, x);
|
||||
|
||||
if (r_splitscreen && stplyr == &players[displayplayers[1]])
|
||||
interpx = -interpx;
|
||||
|
||||
V_DrawFixedPatch(interpx + (STCD_X<<FRACBITS) - (xval>>1),
|
||||
V_DrawFixedPatch(interpx + (STCD_X<<FRACBITS) - (pwidth / 2),
|
||||
(STCD_Y<<FRACBITS) - (SHORT(kptodraw[pnum]->height)<<(FRACBITS-1)),
|
||||
FRACUNIT,
|
||||
splitflags, kptodraw[pnum], NULL);
|
||||
|
|
@ -4160,7 +4159,7 @@ static void K_drawBattleFullscreen(void)
|
|||
|
||||
K_drawKartFinish(true);
|
||||
}
|
||||
else if (stplyr->bumpers <= 0 && stplyr->karmadelay && !stplyr->spectator && drawcomebacktimer)
|
||||
else if (stplyr->karmadelay && !stplyr->spectator && drawcomebacktimer)
|
||||
{
|
||||
UINT16 t = stplyr->karmadelay/(10*TICRATE);
|
||||
INT32 txoff, adjust = (r_splitscreen > 1) ? 4 : 6; // normal string is 8, kart string is 12, half of that for ease
|
||||
|
|
@ -4894,8 +4893,7 @@ void K_drawKartHUD(void)
|
|||
|
||||
battlefullscreen = (!(gametyperules & GTR_CIRCUIT)
|
||||
&& (stplyr->exiting
|
||||
|| ((gametyperules & GTR_BUMPERS) && (stplyr->bumpers <= 0)
|
||||
&& ((gametyperules & GTR_KARMA) && (stplyr->karmadelay > 0))
|
||||
|| (((gametyperules & GTR_KARMA) && (stplyr->karmadelay > 0))
|
||||
&& !(stplyr->pflags & PF_ELIMINATED)
|
||||
&& stplyr->playerstate == PST_LIVE)));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
#include "core/static_vec.hpp"
|
||||
|
||||
#include "k_battle.h"
|
||||
#include "k_boss.h"
|
||||
#include "k_hud.h"
|
||||
#include "k_kart.h"
|
||||
#include "k_objects.h"
|
||||
#include "m_fixed.h"
|
||||
#include "p_local.h"
|
||||
|
|
@ -314,7 +314,7 @@ bool is_player_tracking_target(player_t *player = stplyr)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (battleprisons || bossinfo.valid)
|
||||
if (K_Cooperative())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -338,6 +338,23 @@ bool is_player_tracking_target(player_t *player = stplyr)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (player->emeralds != 0 && K_IsPlayerWanted(stplyr))
|
||||
{
|
||||
// The player who is about to win because of emeralds
|
||||
// gets a TARGET on them
|
||||
if (K_NumEmeralds(player) == 6) // 6 out of 7
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// WANTED player sees TARGETs on players holding
|
||||
// emeralds
|
||||
if (K_IsPlayerWanted(stplyr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return K_IsPlayerWanted(player);
|
||||
}
|
||||
|
||||
|
|
|
|||
242
src/k_kart.c
242
src/k_kart.c
|
|
@ -374,9 +374,6 @@ boolean K_IsPlayerLosing(player_t *player)
|
|||
if (battleprisons && numtargets == 0)
|
||||
return true; // Didn't even TRY?
|
||||
|
||||
if (battleprisons || (gametyperules & GTR_BOSS))
|
||||
return (player->bumpers <= 0); // anything short of DNF is COOL
|
||||
|
||||
if (player->position == 1)
|
||||
return false;
|
||||
|
||||
|
|
@ -3269,11 +3266,6 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower, boolean dorubberb
|
|||
{
|
||||
finalspeed = K_GetKartSpeedFromStat(player->kartspeed);
|
||||
|
||||
if (gametyperules & GTR_BUMPERS && player->bumpers <= 0)
|
||||
{
|
||||
finalspeed = 3 * finalspeed / 2;
|
||||
}
|
||||
|
||||
if (player->spheres > 0)
|
||||
{
|
||||
fixed_t sphereAdd = (FRACUNIT/40); // 100% at max
|
||||
|
|
@ -3333,12 +3325,6 @@ fixed_t K_GetKartAccel(player_t *player)
|
|||
return FixedMul(k_accel, FRACUNIT / 4);
|
||||
}
|
||||
|
||||
// karma bomb gets 2x acceleration
|
||||
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
|
||||
{
|
||||
k_accel *= 2;
|
||||
}
|
||||
|
||||
// Marble Garden Top gets 1200% accel
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
|
|
@ -3654,7 +3640,7 @@ void K_DoPowerClash(player_t *t1, player_t *t2) {
|
|||
P_SetScale(clash, 3*clash->destscale/2);
|
||||
}
|
||||
|
||||
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved)
|
||||
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 damage)
|
||||
{
|
||||
UINT8 points = 1;
|
||||
boolean trapItem = false;
|
||||
|
|
@ -3692,7 +3678,7 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
|
|||
}
|
||||
else if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
if ((victim->bumpers > 0) && (victim->bumpers <= bumpersRemoved))
|
||||
if ((victim->mo->health > 0) && (victim->mo->health <= damage))
|
||||
{
|
||||
// +2 points for finishing off a player
|
||||
points = 2;
|
||||
|
|
@ -4071,10 +4057,14 @@ void K_UpdateStumbleIndicator(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
#define MIN_WAVEDASH_CHARGE (5*TICRATE/8)
|
||||
|
||||
static boolean K_IsLosingSliptideZip(player_t *player)
|
||||
{
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
return true;
|
||||
if (!K_Sliptiding(player) && player->sliptideZip < MIN_WAVEDASH_CHARGE)
|
||||
return true;
|
||||
if (!K_Sliptiding(player) && player->drift == 0
|
||||
&& P_IsObjectOnGround(player->mo) && player->sneakertimer == 0
|
||||
&& player->driftboost == 0)
|
||||
|
|
@ -4341,81 +4331,22 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source)
|
|||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
}
|
||||
|
||||
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers)
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
{
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
// Bumpers aren't being used
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: replace all console text print-outs with a real visual
|
||||
|
||||
if (player->bumpers > 0 && prevBumpers == 0)
|
||||
{
|
||||
K_DoInvincibility(player, 8 * TICRATE);
|
||||
|
||||
if (netgame)
|
||||
{
|
||||
CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]);
|
||||
}
|
||||
}
|
||||
else if (player->bumpers == 0 && prevBumpers > 0)
|
||||
{
|
||||
if (battleprisons || bossinfo.valid)
|
||||
{
|
||||
player->pflags |= (PF_NOCONTEST|PF_ELIMINATED);
|
||||
}
|
||||
}
|
||||
|
||||
K_CalculateBattleWanted();
|
||||
K_CheckBumpers();
|
||||
}
|
||||
|
||||
UINT8 K_DestroyBumpers(player_t *player, UINT8 amount)
|
||||
{
|
||||
UINT8 oldBumpers = player->bumpers;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount = min(amount, player->bumpers);
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
player->bumpers -= amount;
|
||||
K_HandleBumperChanges(player, oldBumpers);
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
UINT8 K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
{
|
||||
UINT8 oldPlayerBumpers = player->bumpers;
|
||||
UINT8 oldVictimBumpers = victim->bumpers;
|
||||
const UINT8 oldPlayerBumpers = K_Bumpers(player);
|
||||
|
||||
UINT8 tookBumpers = 0;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
amount = min(amount, victim->bumpers);
|
||||
amount = min(amount, K_Bumpers(victim));
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((tookBumpers < amount) && (victim->bumpers > 0))
|
||||
while (tookBumpers < amount)
|
||||
{
|
||||
UINT8 newbumper = player->bumpers;
|
||||
const UINT8 newbumper = (oldPlayerBumpers + tookBumpers);
|
||||
|
||||
angle_t newangle, diff;
|
||||
fixed_t newx, newy;
|
||||
|
|
@ -4457,24 +4388,14 @@ UINT8 K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
P_SetMobjState(newmo, S_BATTLEBUMPER1);
|
||||
}
|
||||
|
||||
player->bumpers++;
|
||||
victim->bumpers--;
|
||||
tookBumpers++;
|
||||
}
|
||||
|
||||
if (tookBumpers == 0)
|
||||
{
|
||||
// No change occured.
|
||||
return 0;
|
||||
}
|
||||
// :jartcookiedance:
|
||||
player->mo->health += tookBumpers;
|
||||
|
||||
// Play steal sound
|
||||
S_StartSound(player->mo, sfx_3db06);
|
||||
|
||||
K_HandleBumperChanges(player, oldPlayerBumpers);
|
||||
K_HandleBumperChanges(victim, oldVictimBumpers);
|
||||
|
||||
return tookBumpers;
|
||||
}
|
||||
|
||||
#define MINEQUAKEDIST 4096
|
||||
|
|
@ -5138,8 +5059,7 @@ void K_SpawnBoostTrail(player_t *player)
|
|||
I_Assert(!P_MobjWasRemoved(player->mo));
|
||||
|
||||
if (!P_IsObjectOnGround(player->mo)
|
||||
|| player->hyudorotimer != 0
|
||||
|| ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0 && player->karmadelay))
|
||||
|| player->hyudorotimer != 0)
|
||||
return;
|
||||
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
|
|
@ -7098,12 +7018,6 @@ mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (player->bumpers <= 0)
|
||||
{
|
||||
// Don't pay attention to dead players
|
||||
continue;
|
||||
}
|
||||
|
||||
// Z pos too high/low
|
||||
if (abs(player->mo->z - (actor->z + actor->momz)) > FixedMul(RING_DIST/8, mapobjectscale))
|
||||
{
|
||||
|
|
@ -7809,13 +7723,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->spheres = 40;
|
||||
// where's the < 0 check? see below the following block!
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
|
||||
{
|
||||
// Deplete 1 every tic when removed from the game.
|
||||
player->spheres--;
|
||||
player->spheredigestion = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tic_t spheredigestion = TICRATE; // Base rate of 1 every second when playing.
|
||||
tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17
|
||||
|
|
@ -7860,12 +7767,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (!(gametyperules & GTR_KARMA) || (player->pflags & PF_ELIMINATED))
|
||||
{
|
||||
player->karmadelay = comebacktime;
|
||||
player->karmadelay = 0;
|
||||
}
|
||||
else if (player->karmadelay > 0 && !P_PlayerInPain(player))
|
||||
{
|
||||
player->karmadelay--;
|
||||
if (P_IsDisplayPlayer(player) && player->bumpers <= 0 && player->karmadelay <= 0)
|
||||
if (P_IsDisplayPlayer(player) && player->karmadelay <= 0)
|
||||
comebackshowninfo = true; // client has already seen the message
|
||||
}
|
||||
|
||||
|
|
@ -8029,14 +7936,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
K_UpdateTripwire(player);
|
||||
|
||||
if (battleovertime.enabled && !(player->pflags & PF_ELIMINATED) && player->bumpers <= 0 && player->karmadelay <= 0)
|
||||
{
|
||||
if (player->overtimekarma)
|
||||
player->overtimekarma--;
|
||||
else
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER);
|
||||
}
|
||||
|
||||
if ((battleovertime.enabled >= 10*TICRATE) && !(player->pflags & PF_ELIMINATED) && !player->exiting)
|
||||
{
|
||||
fixed_t distanceToBarrier = 0;
|
||||
|
|
@ -8066,7 +7965,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->eggmanexplode)
|
||||
{
|
||||
if (player->spectator || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0))
|
||||
if (player->spectator)
|
||||
player->eggmanexplode = 0;
|
||||
else
|
||||
{
|
||||
|
|
@ -8407,30 +8306,14 @@ void K_KartPlayerAfterThink(player_t *player)
|
|||
K_LookForRings(player->mo);
|
||||
}
|
||||
|
||||
if (player->invulnhitlag > 0)
|
||||
if (player->nullHitlag > 0)
|
||||
{
|
||||
// Hitlag from what would normally be damage but the
|
||||
// player was invulnerable.
|
||||
//
|
||||
// If we're constantly getting hit the same number of
|
||||
// times, we're probably standing on a damage floor.
|
||||
//
|
||||
// Checking if we're hit more than before ensures
|
||||
// that:
|
||||
//
|
||||
// 1) repeating damage doesn't count
|
||||
// 2) new damage sources still count
|
||||
|
||||
if (player->timeshit <= player->timeshitprev)
|
||||
if (!P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
if (!P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
player->mo->hitlag -= player->invulnhitlag;
|
||||
player->mo->eflags &= ~(MFE_DAMAGEHITLAG);
|
||||
}
|
||||
player->mo->hitlag -= player->nullHitlag;
|
||||
}
|
||||
|
||||
player->invulnhitlag = 0;
|
||||
player->nullHitlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9405,6 +9288,8 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
K_SpawnAIZDust(player);
|
||||
|
||||
player->sliptideZip++;
|
||||
if (player->sliptideZip == MIN_WAVEDASH_CHARGE)
|
||||
S_StartSound(player->mo, sfx_waved5);
|
||||
|
||||
if (abs(player->aizdrifttilt) < ANGLE_22h)
|
||||
{
|
||||
|
|
@ -9432,35 +9317,38 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
player->sliptideZipDelay++;
|
||||
if (player->sliptideZipDelay > TICRATE/2)
|
||||
{
|
||||
fixed_t maxZipPower = 2*FRACUNIT;
|
||||
fixed_t minZipPower = 1*FRACUNIT;
|
||||
fixed_t powerSpread = maxZipPower - minZipPower;
|
||||
if (player->sliptideZip >= MIN_WAVEDASH_CHARGE)
|
||||
{
|
||||
fixed_t maxZipPower = 2*FRACUNIT;
|
||||
fixed_t minZipPower = 1*FRACUNIT;
|
||||
fixed_t powerSpread = maxZipPower - minZipPower;
|
||||
|
||||
int minPenalty = 2*1 + (9-9); // Kinda doing a similar thing to driftspark stage timers here.
|
||||
int maxPenalty = 2*9 + (9-1); // 1/9 gets max, 9/1 gets min, everyone else gets something in between.
|
||||
int penaltySpread = maxPenalty - minPenalty;
|
||||
int yourPenalty = 2*player->kartspeed + (9 - player->kartweight); // And like driftsparks, speed hurts double.
|
||||
int minPenalty = 2*1 + (9-9); // Kinda doing a similar thing to driftspark stage timers here.
|
||||
int maxPenalty = 2*9 + (9-1); // 1/9 gets max, 9/1 gets min, everyone else gets something in between.
|
||||
int penaltySpread = maxPenalty - minPenalty;
|
||||
int yourPenalty = 2*player->kartspeed + (9 - player->kartweight); // And like driftsparks, speed hurts double.
|
||||
|
||||
yourPenalty -= minPenalty; // Normalize; minimum penalty should take away 0 power.
|
||||
yourPenalty -= minPenalty; // Normalize; minimum penalty should take away 0 power.
|
||||
|
||||
fixed_t yourPowerReduction = FixedDiv(yourPenalty * FRACUNIT, penaltySpread * FRACUNIT);
|
||||
fixed_t yourPower = maxZipPower - FixedMul(yourPowerReduction, powerSpread);
|
||||
int yourBoost = FixedInt(FixedMul(yourPower, player->sliptideZip * FRACUNIT));
|
||||
fixed_t yourPowerReduction = FixedDiv(yourPenalty * FRACUNIT, penaltySpread * FRACUNIT);
|
||||
fixed_t yourPower = maxZipPower - FixedMul(yourPowerReduction, powerSpread);
|
||||
int yourBoost = FixedInt(FixedMul(yourPower, player->sliptideZip * FRACUNIT));
|
||||
|
||||
/*
|
||||
CONS_Printf("SZ %d MZ %d mZ %d pwS %d mP %d MP %d peS %d yPe %d yPR %d yPw %d yB %d\n",
|
||||
player->sliptideZip, maxZipPower, minZipPower, powerSpread, minPenalty, maxPenalty, penaltySpread, yourPenalty, yourPowerReduction, yourPower, yourBoost);
|
||||
*/
|
||||
/*
|
||||
CONS_Printf("SZ %d MZ %d mZ %d pwS %d mP %d MP %d peS %d yPe %d yPR %d yPw %d yB %d\n",
|
||||
player->sliptideZip, maxZipPower, minZipPower, powerSpread, minPenalty, maxPenalty, penaltySpread, yourPenalty, yourPowerReduction, yourPower, yourBoost);
|
||||
*/
|
||||
|
||||
player->sliptideZipBoost += yourBoost;
|
||||
player->sliptideZipBoost += yourBoost;
|
||||
|
||||
K_SpawnDriftBoostExplosion(player, 0);
|
||||
player->sliptideZip = 0;
|
||||
player->sliptideZipDelay = 0;
|
||||
K_SpawnDriftBoostExplosion(player, 0);
|
||||
S_StartSoundAtVolume(player->mo, sfx_waved3, 2*255/3); // Boost
|
||||
}
|
||||
S_StopSoundByID(player->mo, sfx_waved1);
|
||||
S_StopSoundByID(player->mo, sfx_waved2);
|
||||
S_StopSoundByID(player->mo, sfx_waved4);
|
||||
S_StartSoundAtVolume(player->mo, sfx_waved3, 2*255/3); // Boost
|
||||
player->sliptideZip = 0;
|
||||
player->sliptideZipDelay = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -9586,7 +9474,7 @@ void K_KartUpdatePosition(player_t *player)
|
|||
else if (yourEmeralds == myEmeralds)
|
||||
{
|
||||
// Bumpers are the second tier tie breaker
|
||||
if (players[i].bumpers > player->bumpers)
|
||||
if (K_Bumpers(&players[i]) > K_Bumpers(player))
|
||||
{
|
||||
position++;
|
||||
}
|
||||
|
|
@ -11210,18 +11098,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->mo->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS) || player->bumpers > 0)
|
||||
{
|
||||
player->mo->renderflags &= ~(RF_TRANSMASK|RF_BRIGHTMASK);
|
||||
}
|
||||
else // dead in match? you da bomb
|
||||
{
|
||||
K_DropItems(player); //K_StripItems(player);
|
||||
K_StripOther(player);
|
||||
player->mo->renderflags |= RF_GHOSTLY;
|
||||
player->flashing = player->karmadelay;
|
||||
}
|
||||
|
||||
if (player->trickpanel == 1)
|
||||
{
|
||||
const angle_t lr = ANGLE_45;
|
||||
|
|
@ -11469,8 +11345,9 @@ void K_CheckSpectateStatus(void)
|
|||
P_SpectatorJoinGame(&players[respawnlist[i]]);
|
||||
}
|
||||
|
||||
// Reset the match if you're in an empty server
|
||||
if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (numingame < 2 && numingame+i >= 2)) // use previous i value
|
||||
// Reset the match when 2P joins 1P, DUEL mode
|
||||
// Reset the match when 3P joins 1P and 2P, DUEL mode must be disabled
|
||||
if (!mapreset && gamestate == GS_LEVEL && (numingame < 3 && numingame+i >= 2)) // use previous i value
|
||||
{
|
||||
S_ChangeMusicInternal("chalng", false); // COME ON
|
||||
mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD
|
||||
|
|
@ -11720,7 +11597,7 @@ UINT32 K_PointLimitForGametype(void)
|
|||
return cv_pointlimit.value;
|
||||
}
|
||||
|
||||
if (battleprisons || bossinfo.valid)
|
||||
if (K_Cooperative())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -11744,4 +11621,19 @@ UINT32 K_PointLimitForGametype(void)
|
|||
return ptsCap;
|
||||
}
|
||||
|
||||
boolean K_Cooperative(void)
|
||||
{
|
||||
if (battleprisons)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bossinfo.valid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -104,9 +104,7 @@ void K_UpdateStumbleIndicator(player_t *player);
|
|||
void K_UpdateSliptideZipIndicator(player_t *player);
|
||||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
void K_DebtStingPlayer(player_t *player, mobj_t *source);
|
||||
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
|
||||
UINT8 K_DestroyBumpers(player_t *player, UINT8 amount);
|
||||
UINT8 K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
void K_MineFlashScreen(mobj_t *source);
|
||||
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay);
|
||||
void K_RunFinishLineBeam(void);
|
||||
|
|
@ -210,6 +208,8 @@ void K_EggmanTransfer(player_t *source, player_t *victim);
|
|||
tic_t K_TimeLimitForGametype(void);
|
||||
UINT32 K_PointLimitForGametype(void);
|
||||
|
||||
boolean K_Cooperative(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -60,13 +60,6 @@
|
|||
// And just some randomness for the exits.
|
||||
#include "m_random.h"
|
||||
|
||||
#if defined(HAVE_SDL)
|
||||
#include "SDL.h"
|
||||
#if SDL_VERSION_ATLEAST(2,0,0)
|
||||
#include "sdl/sdlmain.h" // JOYSTICK_HOTPLUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PC_DOS
|
||||
#include <stdio.h> // for snprintf
|
||||
int snprintf(char *str, size_t n, const char *fmt, ...);
|
||||
|
|
@ -3500,11 +3493,18 @@ void M_DrawProfileControls(void)
|
|||
// Get userbound controls...
|
||||
for (k = 0; k < MAXINPUTMAPPING; k++)
|
||||
{
|
||||
int device;
|
||||
keys[k] = optionsmenu.tempcontrols[gc][k];
|
||||
if (keys[k] == KEY_NULL)
|
||||
continue;
|
||||
set++;
|
||||
if (!G_KeyIsAvailable(keys[k], cv_usejoystick[0].value))
|
||||
|
||||
device = G_GetDeviceForPlayer(0);
|
||||
if (device == -1)
|
||||
{
|
||||
device = 0;
|
||||
}
|
||||
if (!G_KeyIsAvailable(keys[k], device))
|
||||
continue;
|
||||
available++;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -240,6 +240,22 @@ boolean M_Responder(event_t *ev)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (gamestate == GS_MENU && ev->type == ev_gamepad_device_removed && G_GetPlayerForDevice(ev->device) != -1)
|
||||
{
|
||||
int i;
|
||||
INT32 player = G_GetPlayerForDevice(ev->device);
|
||||
|
||||
// Unassign all controllers
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
G_SetDeviceForPlayer(i, -1);
|
||||
}
|
||||
|
||||
// Return to the title because a controller was removed at the menu.
|
||||
CONS_Alert(CONS_NOTICE, "Player %d's assigned gamepad was removed. Returning to the title screen.", player);
|
||||
D_StartTitle();
|
||||
}
|
||||
|
||||
if (ev->type == ev_keydown && ev->data1 < NUMKEYS)
|
||||
{
|
||||
// Record keyboard presses
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->spinouttimer);
|
||||
else if (fastcmp(field,"instashield"))
|
||||
lua_pushinteger(L, plr->instashield);
|
||||
else if (fastcmp(field,"invulnhitlag"))
|
||||
lua_pushinteger(L, plr->invulnhitlag);
|
||||
else if (fastcmp(field,"nullHitlag"))
|
||||
lua_pushinteger(L, plr->nullHitlag);
|
||||
else if (fastcmp(field,"wipeoutslow"))
|
||||
lua_pushinteger(L, plr->wipeoutslow);
|
||||
else if (fastcmp(field,"justbumped"))
|
||||
|
|
@ -398,8 +398,6 @@ static int player_get(lua_State *L)
|
|||
plr->roundscore = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"emeralds"))
|
||||
lua_pushinteger(L, plr->emeralds);
|
||||
else if (fastcmp(field,"bumpers"))
|
||||
lua_pushinteger(L, plr->bumpers);
|
||||
else if (fastcmp(field,"karmadelay"))
|
||||
lua_pushinteger(L, plr->karmadelay);
|
||||
else if (fastcmp(field,"spheres"))
|
||||
|
|
@ -616,8 +614,8 @@ static int player_set(lua_State *L)
|
|||
plr->spinouttimer = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"instashield"))
|
||||
plr->instashield = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"invulnhitlag"))
|
||||
plr->invulnhitlag = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"nullHitlag"))
|
||||
plr->nullHitlag = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"wipeoutslow"))
|
||||
plr->wipeoutslow = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"justbumped"))
|
||||
|
|
@ -782,8 +780,6 @@ static int player_set(lua_State *L)
|
|||
lua_pushinteger(L, plr->roundscore);
|
||||
else if (fastcmp(field,"emeralds"))
|
||||
plr->emeralds = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"bumpers"))
|
||||
plr->bumpers = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"karmadelay"))
|
||||
plr->karmadelay = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"spheres"))
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ static void SetDeviceOnPress(void)
|
|||
{
|
||||
if (deviceResponding[i])
|
||||
{
|
||||
CV_SetValue(&cv_usejoystick[0], i); // Force-set this joystick as the current joystick we're using for P1 (which is the only one controlling menus)
|
||||
G_SetDeviceForPlayer(0, i); // Force-set this joystick as the current joystick we're using for P1 (which is the only one controlling menus)
|
||||
CONS_Printf("SetDeviceOnPress: Device for %d set to %d\n", 0, i);
|
||||
return;
|
||||
}
|
||||
|
|
@ -307,7 +307,7 @@ void M_MapProfileControl(event_t *ev)
|
|||
UINT8 where = n; // By default, we'll save the bind where we're supposed to map.
|
||||
INT32 i;
|
||||
|
||||
//SetDeviceOnPress(); // Update cv_usejoystick
|
||||
//SetDeviceOnPress(); // Update player gamepad assignments
|
||||
|
||||
// Only consider keydown and joystick events to make sure we ignore ev_mouse and other events
|
||||
// See also G_MapEventsToControls
|
||||
|
|
@ -325,11 +325,11 @@ void M_MapProfileControl(event_t *ev)
|
|||
}
|
||||
#endif
|
||||
break;
|
||||
case ev_joystick:
|
||||
case ev_gamepad_axis:
|
||||
if (ev->data1 >= JOYAXES)
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
CONS_Debug(DBG_GAMELOGIC, "Bad joystick axis event %d\n", ev->data1);
|
||||
CONS_Debug(DBG_GAMELOGIC, "Bad gamepad axis event %d\n", ev->data1);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,10 +381,10 @@ void M_CharacterSelectInit(void)
|
|||
{
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
// Un-set devices for other players.
|
||||
if (i != 0 || optionsmenu.profile)
|
||||
// Un-set devices for all players if not editing profile
|
||||
if (!optionsmenu.profile)
|
||||
{
|
||||
CV_SetValue(&cv_usejoystick[i], -1);
|
||||
G_SetDeviceForPlayer(i, -1);
|
||||
CONS_Printf("M_CharacterSelectInit: Device for %d set to %d\n", i, -1);
|
||||
}
|
||||
}
|
||||
|
|
@ -527,7 +527,12 @@ static boolean M_DeviceAvailable(INT32 deviceID, UINT8 numPlayers)
|
|||
|
||||
for (i = 0; i < numPlayers; i++)
|
||||
{
|
||||
if (cv_usejoystick[i].value == deviceID)
|
||||
int player_device = G_GetDeviceForPlayer(i);
|
||||
if (player_device == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (player_device == deviceID)
|
||||
{
|
||||
// This one's already being used.
|
||||
return false;
|
||||
|
|
@ -541,6 +546,7 @@ static boolean M_DeviceAvailable(INT32 deviceID, UINT8 numPlayers)
|
|||
static boolean M_HandlePressStart(setup_player_t *p, UINT8 num)
|
||||
{
|
||||
INT32 i, j;
|
||||
INT32 num_gamepads_available;
|
||||
|
||||
if (optionsmenu.profile)
|
||||
return false; // Don't allow for the possibility of SOMEHOW another player joining in.
|
||||
|
|
@ -569,24 +575,38 @@ static boolean M_HandlePressStart(setup_player_t *p, UINT8 num)
|
|||
}
|
||||
|
||||
// Now detect new devices trying to join.
|
||||
for (i = 0; i < MAXDEVICES; i++)
|
||||
num_gamepads_available = G_GetNumAvailableGamepads();
|
||||
for (i = 0; i < num_gamepads_available + 1; i++)
|
||||
{
|
||||
if (deviceResponding[i] != true)
|
||||
INT32 device = 0;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
device = G_GetAvailableGamepadDevice(i - 1);
|
||||
}
|
||||
|
||||
if (device == KEYBOARD_MOUSE_DEVICE && num != 0)
|
||||
{
|
||||
// Only player 1 can be assigned to the KBM device.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (G_IsDeviceResponding(device) != true)
|
||||
{
|
||||
// No buttons are being pushed.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (M_DeviceAvailable(i, setup_numplayers) == true)
|
||||
if (M_DeviceAvailable(device, setup_numplayers) == true)
|
||||
{
|
||||
// Available!! Let's use this one!!
|
||||
|
||||
// if P1 is setting up using keyboard (device 0), save their last used device.
|
||||
// this is to allow them to retain controller usage when they play alone.
|
||||
// Because let's face it, when you test mods, you're often lazy to grab your controller for menuing :)
|
||||
if (!i && !num)
|
||||
if (i == 0 && num == 0)
|
||||
{
|
||||
setup_player[num].ponedevice = cv_usejoystick[num].value;
|
||||
setup_player[num].ponedevice = G_GetDeviceForPlayer(num);
|
||||
}
|
||||
else if (num)
|
||||
{
|
||||
|
|
@ -594,14 +614,13 @@ static boolean M_HandlePressStart(setup_player_t *p, UINT8 num)
|
|||
memcpy(&gamecontrol[num], gamecontroldefault, sizeof(gamecontroldefault));
|
||||
}
|
||||
|
||||
G_SetDeviceForPlayer(num, device);
|
||||
CONS_Printf("M_HandlePressStart: Device for %d set to %d\n", num, device);
|
||||
|
||||
CV_SetValue(&cv_usejoystick[num], i);
|
||||
CONS_Printf("M_HandlePressStart: Device for %d set to %d\n", num, i);
|
||||
|
||||
for (j = num+1; j < MAXSPLITSCREENPLAYERS; j++)
|
||||
for (j = num + 1; j < MAXSPLITSCREENPLAYERS; j++)
|
||||
{
|
||||
// Un-set devices for other players.
|
||||
CV_SetValue(&cv_usejoystick[j], -1);
|
||||
G_SetDeviceForPlayer(j, -1);
|
||||
CONS_Printf("M_HandlePressStart: Device for %d set to %d\n", j, -1);
|
||||
}
|
||||
|
||||
|
|
@ -617,7 +636,7 @@ static boolean M_HandlePressStart(setup_player_t *p, UINT8 num)
|
|||
menucmd[j].buttonsHeld |= MBT_X;
|
||||
}
|
||||
|
||||
memset(deviceResponding, false, sizeof(deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -669,11 +688,8 @@ static boolean M_HandleCSelectProfile(setup_player_t *p, UINT8 num)
|
|||
menucmd[i].buttonsHeld |= MBT_X;
|
||||
}
|
||||
|
||||
if (num > 0)
|
||||
{
|
||||
CV_StealthSetValue(&cv_usejoystick[num], -1);
|
||||
CONS_Printf("M_HandleCSelectProfile: Device for %d set to %d\n", num, -1);
|
||||
}
|
||||
G_SetDeviceForPlayer(num, -1);
|
||||
CONS_Printf("M_HandleCSelectProfile: Device for %d set to %d\n", num, -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1479,22 +1495,18 @@ void M_CharacterSelectTick(void)
|
|||
else
|
||||
CV_StealthSet(&cv_follower[i], followers[setup_player[i].followern].name);
|
||||
CV_StealthSetValue(&cv_followercolor[i], setup_player[i].followercolor);
|
||||
|
||||
G_SetPlayerGamepadIndicatorToPlayerColor(i);
|
||||
}
|
||||
|
||||
CV_StealthSetValue(&cv_splitplayers, setup_numplayers);
|
||||
|
||||
// P1 is alone, set their old device just in case.
|
||||
if (setup_numplayers < 2 && setup_player[0].ponedevice)
|
||||
{
|
||||
CV_StealthSetValue(&cv_usejoystick[0], setup_player[0].ponedevice);
|
||||
}
|
||||
|
||||
#if defined (TESTERS)
|
||||
M_MPOptSelectInit(0);
|
||||
#else
|
||||
M_SetupPlayMenu(0);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else // In a game
|
||||
|
|
|
|||
|
|
@ -167,12 +167,6 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
boolean tumbleitem = false;
|
||||
boolean sprung = false;
|
||||
|
||||
if ((orbinaut_selfdelay(t1) > 0 && t2->hitlag > 0)
|
||||
|| (orbinaut_selfdelay(t2) > 0 && t1->hitlag > 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t1->health <= 0 || t2->health <= 0)
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -13595,7 +13595,7 @@ void A_ReaperThinker(mobj_t *actor)
|
|||
continue;
|
||||
|
||||
player = &players[i];
|
||||
if (player && player->mo && player->bumpers && player->score >= maxscore)
|
||||
if (player && player->mo && K_Bumpers(player) && player->score >= maxscore)
|
||||
{
|
||||
targetplayermo = player->mo;
|
||||
maxscore = player->score;
|
||||
|
|
|
|||
209
src/p_inter.c
209
src/p_inter.c
|
|
@ -39,6 +39,7 @@
|
|||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_boss.h"
|
||||
|
||||
// CTF player names
|
||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||
|
|
@ -114,13 +115,6 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
|
|||
if (player->exiting || mapreset || (player->pflags & PF_ELIMINATED))
|
||||
return false;
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) // No bumpers in Match
|
||||
#ifndef OTHERKARMAMODES
|
||||
&& !weapon
|
||||
#endif
|
||||
&& player->bumpers <= 0)
|
||||
return false;
|
||||
|
||||
if (weapon)
|
||||
{
|
||||
// Item slot already taken up
|
||||
|
|
@ -285,9 +279,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
|
||||
return;
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
|
|
@ -320,9 +311,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
P_KillMobj(special, toucher, toucher, DMG_NORMAL);
|
||||
return;
|
||||
case MT_ITEMCAPSULE:
|
||||
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
|
||||
return;
|
||||
|
||||
if (special->scale < special->extravalue1) // don't break it while it's respawning
|
||||
return;
|
||||
|
||||
|
|
@ -350,8 +338,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
if (player == special->target->player)
|
||||
return;
|
||||
if (player->bumpers <= 0)
|
||||
return;
|
||||
if (special->target->player->exiting || player->exiting)
|
||||
return;
|
||||
|
||||
|
|
@ -452,7 +438,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
S_StartSound(special, sfx_s1a2);
|
||||
return;
|
||||
case MT_CDUFO: // SRB2kart
|
||||
if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0))
|
||||
if (special->fuse || !P_CanPickupItem(player, 1))
|
||||
return;
|
||||
|
||||
K_StartItemRoulette(player);
|
||||
|
|
@ -1395,6 +1381,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
|
||||
P_PlayDeathSound(target);
|
||||
}
|
||||
|
||||
if (K_Cooperative())
|
||||
{
|
||||
target->player->pflags |= (PF_NOCONTEST|PF_ELIMINATED);
|
||||
}
|
||||
break;
|
||||
|
||||
case MT_METALSONIC_RACE:
|
||||
|
|
@ -1937,18 +1928,30 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
switch (type)
|
||||
{
|
||||
case DMG_DEATHPIT:
|
||||
// Respawn kill types
|
||||
// Fell off the stage
|
||||
if (player->roundconditions.fell_off == true)
|
||||
{
|
||||
player->roundconditions.fell_off = true;
|
||||
player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
K_DoIngameRespawn(player);
|
||||
player->mo->health -= K_DestroyBumpers(player, 1);
|
||||
return false;
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
player->mo->health--;
|
||||
}
|
||||
|
||||
if (player->mo->health <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Quick respawn; does not kill
|
||||
return K_DoIngameRespawn(player), false;
|
||||
|
||||
case DMG_SPECTATOR:
|
||||
// disappearifies, but still gotta put items back in play
|
||||
break;
|
||||
|
||||
default:
|
||||
// Everything else REALLY kills
|
||||
if (leveltime < starttime)
|
||||
|
|
@ -2004,11 +2007,46 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
player->pflags |= PF_ELIMINATED;
|
||||
}
|
||||
|
||||
K_DestroyBumpers(player, player->bumpers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void AddTimesHit(player_t *player)
|
||||
{
|
||||
const INT32 oldtimeshit = player->timeshit;
|
||||
|
||||
player->timeshit++;
|
||||
|
||||
// overflow prevention
|
||||
if (player->timeshit < oldtimeshit)
|
||||
{
|
||||
player->timeshit = oldtimeshit;
|
||||
}
|
||||
}
|
||||
|
||||
static void AddNullHitlag(player_t *player, tic_t oldHitlag)
|
||||
{
|
||||
if (player == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Hitlag from what would normally be damage but the
|
||||
// player was invulnerable.
|
||||
//
|
||||
// If we're constantly getting hit the same number of
|
||||
// times, we're probably standing on a damage floor.
|
||||
//
|
||||
// Checking if we're hit more than before ensures that:
|
||||
//
|
||||
// 1) repeating damage doesn't count
|
||||
// 2) new damage sources still count
|
||||
|
||||
if (player->timeshit <= player->timeshitprev)
|
||||
{
|
||||
player->nullHitlag += (player->mo->hitlag - oldHitlag);
|
||||
}
|
||||
}
|
||||
|
||||
/** Damages an object, which may or may not be a player.
|
||||
* For melee attacks, source and inflictor are the same.
|
||||
*
|
||||
|
|
@ -2029,6 +2067,7 @@ static boolean P_KillPlayer(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)
|
||||
{
|
||||
player_t *player;
|
||||
player_t *playerInflictor;
|
||||
boolean force = false;
|
||||
boolean spbpop = false;
|
||||
|
||||
|
|
@ -2097,9 +2136,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (!(target->flags & MF_SHOOTABLE))
|
||||
return false; // shouldn't happen...
|
||||
}
|
||||
|
||||
if (!(damagetype & DMG_DEATHMASK) && (target->eflags & MFE_PAUSED))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->flags2 & MF2_SKULLFLY)
|
||||
|
|
@ -2118,20 +2154,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
|
||||
player = target->player;
|
||||
playerInflictor = inflictor ? inflictor->player : NULL;
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
AddTimesHit(playerInflictor);
|
||||
}
|
||||
|
||||
if (player) // Player is the target
|
||||
{
|
||||
{
|
||||
const INT32 oldtimeshit = player->timeshit;
|
||||
|
||||
player->timeshit++;
|
||||
|
||||
// overflow prevention
|
||||
if (player->timeshit < oldtimeshit)
|
||||
{
|
||||
player->timeshit = oldtimeshit;
|
||||
}
|
||||
}
|
||||
AddTimesHit(player);
|
||||
|
||||
if (player->pflags & PF_GODMODE)
|
||||
return false;
|
||||
|
|
@ -2174,9 +2206,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
|
||||
// Do not die from damage outside of bumpers health system
|
||||
damage = 0;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
if (!force)
|
||||
|
|
@ -2184,16 +2213,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
boolean invincible = true;
|
||||
sfxenum_t sfx = sfx_None;
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
if (player->bumpers <= 0 && player->karmadelay)
|
||||
{
|
||||
// No bumpers & in WAIT, can't be hurt
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
|
|
@ -2220,12 +2240,32 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
if (invincible && type != DMG_STUMBLE)
|
||||
{
|
||||
const INT32 oldhitlag = target->hitlag;
|
||||
const INT32 oldHitlag = target->hitlag;
|
||||
const INT32 oldHitlagInflictor = inflictor ? inflictor->hitlag : 0;
|
||||
|
||||
// Damage during hitlag should be a no-op
|
||||
// for invincibility states because there
|
||||
// are no flashing tics. If the damage is
|
||||
// from a constant source, a deadlock
|
||||
// would occur.
|
||||
|
||||
if (target->eflags & MFE_PAUSED)
|
||||
{
|
||||
player->timeshit--; // doesn't count
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
playerInflictor->timeshit--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
laglength = max(laglength / 2, 1);
|
||||
K_SetHitLagForObjects(target, inflictor, laglength, false);
|
||||
|
||||
player->invulnhitlag += (target->hitlag - oldhitlag);
|
||||
AddNullHitlag(player, oldHitlag);
|
||||
AddNullHitlag(playerInflictor, oldHitlagInflictor);
|
||||
|
||||
if (player->timeshit > player->timeshitprev)
|
||||
{
|
||||
|
|
@ -2255,6 +2295,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
allowcombo = false;
|
||||
}
|
||||
|
||||
if (allowcombo == false && (target->eflags & MFE_PAUSED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout
|
||||
if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE)
|
||||
{
|
||||
|
|
@ -2262,31 +2307,35 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
else if (target->flags2 & MF2_ALREADYHIT) // do not deal extra damage in the same tic
|
||||
{
|
||||
K_SetHitLagForObjects(target, inflictor, laglength, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We successfully damaged them! Give 'em some bumpers!
|
||||
if (type != DMG_STING && type != DMG_STUMBLE)
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
UINT8 takeBumpers = 1;
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
takeBumpers = 2;
|
||||
// Steals 2 bumpers
|
||||
damage = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not die from damage outside of bumpers health system
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
if (type == DMG_KARMA)
|
||||
{
|
||||
takeBumpers = player->bumpers;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == DMG_KARMA)
|
||||
{
|
||||
// Take half of their bumpers for karma comeback damage
|
||||
takeBumpers = max(1, player->bumpers / 2);
|
||||
}
|
||||
}
|
||||
if (type == DMG_STING || type == DMG_STUMBLE)
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We successfully damaged them! Give 'em some bumpers!
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
|
|
@ -2305,18 +2354,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
K_TryHurtSoundExchange(target, source);
|
||||
|
||||
K_BattleAwardHit(source->player, player, inflictor, takeBumpers);
|
||||
damage = K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
|
||||
if (K_Cooperative() == false)
|
||||
{
|
||||
K_BattleAwardHit(source->player, player, inflictor, damage);
|
||||
}
|
||||
|
||||
if (type == DMG_KARMA)
|
||||
{
|
||||
// Destroy any remainder bumpers from the player for karma comeback damage
|
||||
damage = K_DestroyBumpers(player, player->bumpers);
|
||||
}
|
||||
else
|
||||
{
|
||||
source->player->overtimekarma += 5*TICRATE;
|
||||
}
|
||||
K_TakeBumpersFromPlayer(source->player, player, damage);
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
|
|
@ -2332,10 +2375,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
Obj_GardenTopDestroy(source->player);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = K_DestroyBumpers(player, takeBumpers);
|
||||
}
|
||||
|
||||
if (!(damagetype & DMG_STEAL))
|
||||
{
|
||||
|
|
@ -2453,6 +2492,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
K_SetHitLagForObjects(target, inflictor, laglength, true);
|
||||
|
||||
target->flags2 |= MF2_ALREADYHIT;
|
||||
|
||||
if (target->health <= 0)
|
||||
{
|
||||
P_KillMobj(target, inflictor, source, damagetype);
|
||||
|
|
|
|||
11
src/p_map.c
11
src/p_map.c
|
|
@ -956,6 +956,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
|| tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG
|
||||
|| tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK
|
||||
|| tm.thing->type == MT_GARDENTOP
|
||||
|| tm.thing->type == MT_MONITOR
|
||||
|| tm.thing->type == MT_BATTLECAPSULE
|
||||
|| (tm.thing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -971,6 +973,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|
||||
|| thing->type == MT_SSMINE || thing->type == MT_LANDMINE || thing->type == MT_SINK
|
||||
|| thing->type == MT_GARDENTOP
|
||||
|| thing->type == MT_MONITOR
|
||||
|| thing->type == MT_BATTLECAPSULE
|
||||
|| (thing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -1390,13 +1394,6 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS)
|
||||
&& ((thing->player->bumpers && !tm.thing->player->bumpers)
|
||||
|| (tm.thing->player->bumpers && !thing->player->bumpers)))
|
||||
{
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (!P_MobjWasRemoved(thing) && !P_MobjWasRemoved(tm.thing))
|
||||
{
|
||||
if (thing->player->eggmanexplode)
|
||||
|
|
|
|||
66
src/p_mobj.c
66
src/p_mobj.c
|
|
@ -4602,9 +4602,6 @@ boolean P_SupermanLook4Players(mobj_t *actor)
|
|||
if (players[c].mo->health <= 0)
|
||||
continue; // dead
|
||||
|
||||
if ((gametyperules & GTR_BUMPERS) && players[c].bumpers <= 0)
|
||||
continue; // other dead
|
||||
|
||||
playersinthegame[stop] = &players[c];
|
||||
stop++;
|
||||
}
|
||||
|
|
@ -6143,6 +6140,8 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player
|
||||
&& mobj->target->health > 0 && !mobj->target->player->spectator)
|
||||
{
|
||||
const UINT8 bumpers = K_Bumpers(mobj->target->player);
|
||||
|
||||
fixed_t rad = 32*mobj->target->scale;
|
||||
fixed_t offz;
|
||||
angle_t ang, diff;
|
||||
|
|
@ -6152,10 +6151,10 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
else
|
||||
ang = FixedAngle(mobj->info->speed);
|
||||
|
||||
if (mobj->target->player->bumpers <= 1)
|
||||
if (bumpers <= 1)
|
||||
diff = 0;
|
||||
else
|
||||
diff = FixedAngle(360*FRACUNIT/mobj->target->player->bumpers);
|
||||
diff = FixedAngle(360*FRACUNIT / bumpers);
|
||||
|
||||
ang = (ang*leveltime) + (diff * (mobj->threshold-1));
|
||||
|
||||
|
|
@ -6192,9 +6191,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->color = mobj->target->color;
|
||||
}
|
||||
|
||||
if (mobj->target->player->bumpers < 2)
|
||||
if (bumpers < 2)
|
||||
P_SetMobjState(mobj, S_BATTLEBUMPER3);
|
||||
else if (mobj->target->player->bumpers < 3)
|
||||
else if (bumpers < 3)
|
||||
P_SetMobjState(mobj, S_BATTLEBUMPER2);
|
||||
else
|
||||
P_SetMobjState(mobj, S_BATTLEBUMPER1);
|
||||
|
|
@ -6211,7 +6210,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
P_SetThingPosition(mobj);
|
||||
}
|
||||
|
||||
if (mobj->target->player->bumpers <= mobj->threshold)
|
||||
if (bumpers <= mobj->threshold)
|
||||
{
|
||||
// Do bumper destruction
|
||||
P_KillMobj(mobj, NULL, NULL, DMG_NORMAL);
|
||||
|
|
@ -6245,7 +6244,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
mobj->color = mobj->target->color;
|
||||
K_MatchGenericExtraFlags(mobj, mobj->target);
|
||||
|
||||
if ((!(gametyperules & GTR_BUMPERS) || mobj->target->player->bumpers <= 0)
|
||||
if (!(gametyperules & GTR_BUMPERS)
|
||||
#if 1 // Set to 0 to test without needing to host
|
||||
|| (P_IsDisplayPlayer(mobj->target->player))
|
||||
#endif
|
||||
|
|
@ -8261,7 +8260,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
desty = mobj->target->y;
|
||||
}
|
||||
|
||||
mobj->flags &= ~(MF_NOCLIPTHING);
|
||||
P_MoveOrigin(mobj, destx, desty, mobj->target->z);
|
||||
mobj->flags |= MF_NOCLIPTHING;
|
||||
break;
|
||||
}
|
||||
case MT_FLAMESHIELD:
|
||||
|
|
@ -8442,7 +8443,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
statenum_t state = (mobj->state-states);
|
||||
|
||||
if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator
|
||||
|| (!(gametyperules & GTR_BUMPERS) || mobj->target->player->bumpers))
|
||||
|| !(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return false;
|
||||
|
|
@ -9857,8 +9858,10 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->args[0])))
|
||||
return;
|
||||
|
||||
mobj->flags2 &= ~(MF2_ALREADYHIT);
|
||||
|
||||
// Don't run any thinker code while in hitlag
|
||||
if (mobj->hitlag > 0)
|
||||
if ((mobj->player ? mobj->hitlag - mobj->player->nullHitlag : mobj->hitlag) > 0)
|
||||
{
|
||||
mobj->eflags |= MFE_PAUSED;
|
||||
mobj->hitlag--;
|
||||
|
|
@ -11890,38 +11893,15 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
P_SetScale(overheadarrow, mobj->destscale);
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
if ((gametyperules & GTR_BUMPERS) && !p->spectator)
|
||||
{
|
||||
if (p->spectator)
|
||||
// At leveltime == 2, K_TimerInit will get called and reset
|
||||
// the bumpers to the initial value for the level.
|
||||
if (leveltime > 2) // Reset those bumpers!
|
||||
{
|
||||
// HEY! No being cheap...
|
||||
p->bumpers = 0;
|
||||
}
|
||||
else if ((p->bumpers > 0) || (leveltime < starttime) || (pcount <= 1))
|
||||
{
|
||||
if ((leveltime < starttime) || (pcount <= 1)) // Start of the map?
|
||||
{
|
||||
if (leveltime > 2) // Reset those bumpers!
|
||||
{
|
||||
p->bumpers = K_StartingBumperCount();
|
||||
K_SpawnPlayerBattleBumpers(p);
|
||||
}
|
||||
else // temp, will get overwritten in K_BattleInit
|
||||
{
|
||||
p->bumpers = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p->bumpers <= 0)
|
||||
{
|
||||
p->bumpers = K_StartingBumperCount();
|
||||
mobj->health = K_BumpersToHealth(K_StartingBumperCount());
|
||||
K_SpawnPlayerBattleBumpers(p);
|
||||
}
|
||||
|
||||
if (p->bumpers > 0)
|
||||
{
|
||||
mobj->health = p->bumpers;
|
||||
}
|
||||
}
|
||||
|
||||
// I'm not refactoring the loop at the top of this file.
|
||||
|
|
@ -11936,9 +11916,13 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
}
|
||||
|
||||
// Spectating when there is literally any other player in
|
||||
// the level enables director cam.
|
||||
// the level enables director cam. Or if the first player
|
||||
// enters the game, spectate them.
|
||||
// TODO: how do we support splitscreen?
|
||||
K_ToggleDirector(players[consoleplayer].spectator && pcount > 0);
|
||||
if (playernum == consoleplayer || pcount == 1)
|
||||
{
|
||||
K_ToggleDirector(players[consoleplayer].spectator && pcount > 0);
|
||||
}
|
||||
}
|
||||
|
||||
void P_AfterPlayerSpawn(INT32 playernum)
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ typedef enum
|
|||
MF2_JUSTATTACKED = 1<<16, // can be pushed by other moving mobjs
|
||||
MF2_FIRING = 1<<17, // turret fire
|
||||
MF2_SUPERFIRE = 1<<18, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
|
||||
// free: 1<<19
|
||||
MF2_ALREADYHIT = 1<<19, // This object was already damaged THIS tic, resets even during hitlag
|
||||
MF2_STRONGBOX = 1<<20, // Flag used for "strong" random monitors.
|
||||
MF2_OBJECTFLIP = 1<<21, // Flag for objects that always have flipped gravity.
|
||||
MF2_SKULLFLY = 1<<22, // Special handling: skull in flight.
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT16(save->p, players[i].spinouttimer);
|
||||
WRITEUINT8(save->p, players[i].spinouttype);
|
||||
WRITEUINT8(save->p, players[i].instashield);
|
||||
WRITEINT32(save->p, players[i].invulnhitlag);
|
||||
WRITEINT32(save->p, players[i].nullHitlag);
|
||||
WRITEUINT8(save->p, players[i].wipeoutslow);
|
||||
WRITEUINT8(save->p, players[i].justbumped);
|
||||
WRITEUINT8(save->p, players[i].tumbleBounces);
|
||||
|
|
@ -381,9 +381,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
|
||||
WRITEUINT32(save->p, players[i].roundscore);
|
||||
WRITEUINT8(save->p, players[i].emeralds);
|
||||
WRITEUINT8(save->p, players[i].bumpers);
|
||||
WRITEINT16(save->p, players[i].karmadelay);
|
||||
WRITEUINT32(save->p, players[i].overtimekarma);
|
||||
WRITEINT16(save->p, players[i].spheres);
|
||||
WRITEUINT32(save->p, players[i].spheredigestion);
|
||||
|
||||
|
|
@ -653,7 +651,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].spinouttimer = READUINT16(save->p);
|
||||
players[i].spinouttype = READUINT8(save->p);
|
||||
players[i].instashield = READUINT8(save->p);
|
||||
players[i].invulnhitlag = READINT32(save->p);
|
||||
players[i].nullHitlag = READINT32(save->p);
|
||||
players[i].wipeoutslow = READUINT8(save->p);
|
||||
players[i].justbumped = READUINT8(save->p);
|
||||
players[i].tumbleBounces = READUINT8(save->p);
|
||||
|
|
@ -758,9 +756,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
|
||||
players[i].roundscore = READUINT32(save->p);
|
||||
players[i].emeralds = READUINT8(save->p);
|
||||
players[i].bumpers = READUINT8(save->p);
|
||||
players[i].karmadelay = READINT16(save->p);
|
||||
players[i].overtimekarma = READUINT32(save->p);
|
||||
players[i].spheres = READINT16(save->p);
|
||||
players[i].spheredigestion = READUINT32(save->p);
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ unsigned char mapmd5[16];
|
|||
|
||||
boolean udmf;
|
||||
size_t numvertexes, numsegs, numsectors, numsubsectors, numnodes, numlines, numsides, nummapthings;
|
||||
size_t num_orig_vertexes;
|
||||
vertex_t *vertexes;
|
||||
seg_t *segs;
|
||||
sector_t *sectors;
|
||||
|
|
@ -1921,6 +1922,7 @@ static void P_WriteTextmap(void)
|
|||
side_t *wsides;
|
||||
mtag_t freetag;
|
||||
sectorspecialthings_t *specialthings;
|
||||
boolean *wusedvertexes;
|
||||
|
||||
f = fopen(filepath, "w");
|
||||
if (!f)
|
||||
|
|
@ -1930,14 +1932,15 @@ static void P_WriteTextmap(void)
|
|||
}
|
||||
|
||||
wmapthings = Z_Calloc(nummapthings * sizeof(*mapthings), PU_LEVEL, NULL);
|
||||
wvertexes = Z_Calloc(numvertexes * sizeof(*vertexes), PU_LEVEL, NULL);
|
||||
wvertexes = Z_Calloc(num_orig_vertexes * sizeof(*vertexes), PU_LEVEL, NULL);
|
||||
wsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL);
|
||||
wlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL);
|
||||
wsides = Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL);
|
||||
specialthings = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL);
|
||||
wusedvertexes = Z_Calloc(num_orig_vertexes * sizeof(boolean), PU_LEVEL, NULL);
|
||||
|
||||
memcpy(wmapthings, mapthings, nummapthings * sizeof(*mapthings));
|
||||
memcpy(wvertexes, vertexes, numvertexes * sizeof(*vertexes));
|
||||
memcpy(wvertexes, vertexes, num_orig_vertexes * sizeof(*vertexes));
|
||||
memcpy(wsectors, sectors, numsectors * sizeof(*sectors));
|
||||
memcpy(wlines, lines, numlines * sizeof(*lines));
|
||||
memcpy(wsides, sides, numsides * sizeof(*sides));
|
||||
|
|
@ -1951,9 +1954,19 @@ static void P_WriteTextmap(void)
|
|||
wsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t));
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
{
|
||||
size_t v;
|
||||
|
||||
if (lines[i].tags.count)
|
||||
wlines[i].tags.tags = memcpy(Z_Malloc(lines[i].tags.count * sizeof(mtag_t), PU_LEVEL, NULL), lines[i].tags.tags, lines[i].tags.count * sizeof(mtag_t));
|
||||
|
||||
v = lines[i].v1 - vertexes;
|
||||
wusedvertexes[v] = true;
|
||||
|
||||
v = lines[i].v2 - vertexes;
|
||||
wusedvertexes[v] = true;
|
||||
}
|
||||
|
||||
freetag = Tag_NextUnused(0);
|
||||
|
||||
for (i = 0; i < nummapthings; i++)
|
||||
|
|
@ -1961,6 +1974,13 @@ static void P_WriteTextmap(void)
|
|||
subsector_t *ss;
|
||||
INT32 s;
|
||||
|
||||
if (wmapthings[i].type == mobjinfo[MT_WAYPOINT].doomednum
|
||||
|| wmapthings[i].type == mobjinfo[MT_WAYPOINT_ANCHOR].doomednum
|
||||
|| wmapthings[i].type == mobjinfo[MT_WAYPOINT_RISER].doomednum)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Thing %s is a waypoint or waypoint parameter, which cannot be converted fully.\n"), sizeu1(i));
|
||||
}
|
||||
|
||||
if (wmapthings[i].type != 751 && wmapthings[i].type != 752 && wmapthings[i].type != 758)
|
||||
continue;
|
||||
|
||||
|
|
@ -2232,18 +2252,26 @@ static void P_WriteTextmap(void)
|
|||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < numvertexes; i++)
|
||||
j = 0;
|
||||
for (i = 0; i < num_orig_vertexes; i++)
|
||||
{
|
||||
fprintf(f, "vertex // %s\n", sizeu1(i));
|
||||
if (wusedvertexes[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(f, "vertex // %s\n", sizeu1(j));
|
||||
fprintf(f, "{\n");
|
||||
fprintf(f, "x = %f;\n", FIXED_TO_FLOAT(wvertexes[i].x));
|
||||
fprintf(f, "y = %f;\n", FIXED_TO_FLOAT(wvertexes[i].y));
|
||||
if (wvertexes[i].floorzset)
|
||||
fprintf(f, "zfloor = %f;\n", FIXED_TO_FLOAT(wvertexes[i].floorz));
|
||||
if (wvertexes[i].ceilingzset)
|
||||
fprintf(f, "zceiling = %f;\n", FIXED_TO_FLOAT(wvertexes[i].ceilingz));
|
||||
fprintf(f, "x = %f;\n", FIXED_TO_FLOAT(wvertexes[j].x));
|
||||
fprintf(f, "y = %f;\n", FIXED_TO_FLOAT(wvertexes[j].y));
|
||||
if (wvertexes[j].floorzset)
|
||||
fprintf(f, "zfloor = %f;\n", FIXED_TO_FLOAT(wvertexes[j].floorz));
|
||||
if (wvertexes[j].ceilingzset)
|
||||
fprintf(f, "zceiling = %f;\n", FIXED_TO_FLOAT(wvertexes[j].ceilingz));
|
||||
fprintf(f, "}\n");
|
||||
fprintf(f, "\n");
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
for (i = 0; i < numlines; i++)
|
||||
|
|
@ -2563,6 +2591,7 @@ static void P_WriteTextmap(void)
|
|||
Z_Free(wlines);
|
||||
Z_Free(wsides);
|
||||
Z_Free(specialthings);
|
||||
Z_Free(wusedvertexes);
|
||||
}
|
||||
|
||||
/** Loads the textmap data, after obtaining the elements count and allocating their respective space.
|
||||
|
|
@ -2939,6 +2968,10 @@ static boolean P_LoadMapData(const virtres_t *virt)
|
|||
if (numlines <= 0)
|
||||
I_Error("Level has no linedefs");
|
||||
|
||||
// Copy original vertex count before BSP modifications,
|
||||
// as it can alter how -writetextmap works.
|
||||
num_orig_vertexes = numvertexes;
|
||||
|
||||
vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
|
||||
sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL);
|
||||
sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
|
||||
|
|
@ -4400,7 +4433,7 @@ static void P_ConvertBinaryLinedefTypes(void)
|
|||
break;
|
||||
case 80: //Raise tagged things by type to this FOF
|
||||
lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
|
||||
// angle will be converted to tags elsewhere, because they aren't ready yet...
|
||||
lines[i].args[1] = tag;
|
||||
break;
|
||||
case 81: //Block enemies
|
||||
lines[i].flags |= ML_BLOCKMONSTERS;
|
||||
|
|
@ -6880,10 +6913,8 @@ static void P_ConvertBinaryMap(void)
|
|||
P_ConvertBinaryThingTypes();
|
||||
P_ConvertBinaryLinedefFlags();
|
||||
|
||||
#if 0 // Don't do this yet...
|
||||
if (M_CheckParm("-writetextmap"))
|
||||
P_WriteTextmap();
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Compute MD5 message digest for bytes read from memory source
|
||||
|
|
@ -7588,6 +7619,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
sector_t *ss;
|
||||
virtlump_t *encoreLump = NULL;
|
||||
|
||||
K_TimerReset();
|
||||
|
||||
levelloading = true;
|
||||
|
||||
// This is needed. Don't touch.
|
||||
|
|
@ -7885,10 +7918,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
{
|
||||
// Backwards compatibility for non-UDMF maps
|
||||
K_AdjustWaypointsParameters();
|
||||
|
||||
// Moved over here...
|
||||
if (M_CheckParm("-writetextmap"))
|
||||
P_WriteTextmap();
|
||||
}
|
||||
|
||||
if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
|
||||
|
|
@ -8009,8 +8038,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
P_MapEnd(); // just in case MapLoad modifies tm.thing
|
||||
}
|
||||
|
||||
K_TimerReset();
|
||||
|
||||
// No render mode or reloading gamestate, stop here.
|
||||
if (rendermode == render_none || reloadinggamestate)
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1112,13 +1112,18 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
|
|||
// Handles sliding down slopes, like if they were made of butter :)
|
||||
void P_ButteredSlope(mobj_t *mo)
|
||||
{
|
||||
fixed_t thrust;
|
||||
const fixed_t gameSpeed = K_GetKartGameSpeedScalar(gamespeed);
|
||||
fixed_t thrust = 0;
|
||||
|
||||
if (mo->flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY))
|
||||
{
|
||||
return; // don't slide down slopes if you can't touch them or you're not affected by gravity
|
||||
}
|
||||
|
||||
if (P_CanApplySlopePhysics(mo, mo->standingslope) == false)
|
||||
{
|
||||
return; // No physics, no butter.
|
||||
}
|
||||
|
||||
if (mo->player != NULL)
|
||||
{
|
||||
|
|
@ -1141,17 +1146,23 @@ void P_ButteredSlope(mobj_t *mo)
|
|||
|
||||
thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 5 / 4 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1);
|
||||
|
||||
if (mo->player) {
|
||||
if (mo->momx || mo->momy)
|
||||
{
|
||||
fixed_t mult = FRACUNIT;
|
||||
if (mo->momx || mo->momy) {
|
||||
angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection;
|
||||
angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection;
|
||||
|
||||
if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0)
|
||||
angle ^= ANGLE_180;
|
||||
|
||||
mult = FRACUNIT + (FRACUNIT + FINECOSINE(angle>>ANGLETOFINESHIFT))*4/3;
|
||||
if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0)
|
||||
{
|
||||
angle ^= ANGLE_180;
|
||||
}
|
||||
|
||||
// Make uphill easier to climb, and downhill even faster.
|
||||
mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
|
||||
|
||||
// Make relative to game speed
|
||||
mult = FixedMul(mult, gameSpeed);
|
||||
|
||||
mult = FRACUNIT + (FRACUNIT + mult)*4/3;
|
||||
thrust = FixedMul(thrust, mult);
|
||||
}
|
||||
|
||||
|
|
|
|||
17
src/p_spec.c
17
src/p_spec.c
|
|
@ -6185,7 +6185,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, I
|
|||
static void
|
||||
P_RaiseTaggedThingsToFakeFloor (
|
||||
UINT16 type,
|
||||
const taglist_t *tags,
|
||||
mtag_t tag,
|
||||
sector_t *control
|
||||
){
|
||||
sector_t *target;
|
||||
|
|
@ -6210,20 +6210,9 @@ P_RaiseTaggedThingsToFakeFloor (
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!udmf)
|
||||
{
|
||||
// We have to convert these here, as mobjs, let alone
|
||||
// sector thing lists, don't exist at the time of the rest
|
||||
// of the binary map conversion.
|
||||
const mtag_t convertTag = mthing->angle;
|
||||
|
||||
Tag_Add(&mthing->tags, convertTag);
|
||||
Taggroup_Add(tags_mapthings, convertTag, (size_t)(mthing - mapthings));
|
||||
}
|
||||
|
||||
if (
|
||||
(type == 0 || mthing->type == type) &&
|
||||
(tags->count == 0 || Tag_Share(&mthing->tags, tags))
|
||||
(tag == 0 || udmf ? Tag_Find(&mthing->tags, tag) : mthing->angle == tag)
|
||||
){
|
||||
if (( mo->flags2 & MF2_OBJECTFLIP ))
|
||||
{
|
||||
|
|
@ -7771,7 +7760,7 @@ void P_SpawnSpecialsThatRequireObjects(boolean fromnetsave)
|
|||
{
|
||||
P_RaiseTaggedThingsToFakeFloor(
|
||||
lines[i].args[0],
|
||||
&lines[i].tags,
|
||||
lines[i].args[1],
|
||||
lines[i].frontsector
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -537,10 +537,6 @@ INT32 P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
|
|||
if (!(gametyperules & GTR_SPHERES)) // No spheres in Race mode)
|
||||
return 0;
|
||||
|
||||
// Not alive
|
||||
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
|
||||
return 0;
|
||||
|
||||
if (num_spheres > 40) // Reached the cap, don't waste 'em!
|
||||
num_spheres = 40;
|
||||
else if (num_spheres < 0)
|
||||
|
|
@ -2256,7 +2252,7 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
angle_t leniency = (2*ANG1/3) * min(player->cmd.latency, 6);
|
||||
// Don't force another turning tic, just give them the desired angle!
|
||||
|
||||
if (targetDelta == angleChange || player->pflags & PF_DRIFTEND || (maxTurnRight == 0 && maxTurnLeft == 0))
|
||||
if (targetDelta == angleChange || player->pflags & PF_DRIFTEND || K_Sliptiding(player) || (maxTurnRight == 0 && maxTurnLeft == 0))
|
||||
{
|
||||
// We are where we need to be.
|
||||
// ...Or we aren't, but shouldn't be able to steer.
|
||||
|
|
@ -4404,7 +4400,7 @@ void P_PlayerThink(player_t *player)
|
|||
|| player->growshrinktimer > 0 // Grow doesn't flash either.
|
||||
|| (player->respawn.state != RESPAWNST_NONE && player->respawn.truedeath == true) // Respawn timer (for drop dash effect)
|
||||
|| (player->pflags & PF_NOCONTEST) // NO CONTEST explosion
|
||||
|| ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0 && player->karmadelay)))
|
||||
|| player->karmadelay))
|
||||
{
|
||||
if (player->flashing > 1 && player->flashing < K_GetKartFlashing(player)
|
||||
&& (leveltime & 1))
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ consvar_t stereoreverse = CVAR_INIT ("stereoreverse", "Off", CV_SAVE, CV_OnOff,
|
|||
static consvar_t precachesound = CVAR_INIT ("precachesound", "Off", CV_SAVE, CV_OnOff, NULL);
|
||||
|
||||
// actual general (maximum) sound & music volume, saved into the config
|
||||
consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "50", CV_SAVE, soundvolume_cons_t, NULL);
|
||||
consvar_t cv_digmusicvolume = CVAR_INIT ("musicvolume", "50", CV_SAVE, soundvolume_cons_t, NULL);
|
||||
consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "80", CV_SAVE, soundvolume_cons_t, NULL);
|
||||
consvar_t cv_digmusicvolume = CVAR_INIT ("musicvolume", "80", CV_SAVE, soundvolume_cons_t, NULL);
|
||||
|
||||
// number of channels available
|
||||
consvar_t cv_numChannels = CVAR_INIT ("snd_channels", "64", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum);
|
||||
|
|
@ -791,9 +791,9 @@ void S_UpdateSounds(void)
|
|||
mobj_t *listenmobj[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
// Update sound/music volumes, if changed manually at console
|
||||
if (actualsfxvolume != cv_soundvolume.value * USER_VOLUME_SCALE)
|
||||
if (actualsfxvolume != cv_soundvolume.value)
|
||||
S_SetSfxVolume (cv_soundvolume.value);
|
||||
if (actualdigmusicvolume != cv_digmusicvolume.value * USER_VOLUME_SCALE)
|
||||
if (actualdigmusicvolume != cv_digmusicvolume.value)
|
||||
S_SetDigMusicVolume (cv_digmusicvolume.value);
|
||||
|
||||
// We're done now, if we're not in a level.
|
||||
|
|
@ -990,7 +990,7 @@ void S_UpdateClosedCaptions(void)
|
|||
void S_SetSfxVolume(INT32 volume)
|
||||
{
|
||||
//CV_SetValue(&cv_soundvolume, volume);
|
||||
actualsfxvolume = volume * USER_VOLUME_SCALE;
|
||||
actualsfxvolume = volume;
|
||||
|
||||
#ifdef HW3SOUND
|
||||
hws_mode == HWS_DEFAULT_MODE ? I_SetSfxVolume(volume&0x1F) : HW3S_SetSfxVolume(volume&0x1F);
|
||||
|
|
@ -1360,7 +1360,6 @@ static tic_t pause_starttic;
|
|||
|
||||
musicdef_t *musicdefstart = NULL;
|
||||
struct cursongcredit cursongcredit; // Currently displayed song credit info
|
||||
int musicdef_volume;
|
||||
|
||||
//
|
||||
// S_FindMusicDef
|
||||
|
|
@ -2249,14 +2248,12 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
|
|||
music_flags = mflags;
|
||||
music_looping = looping;
|
||||
|
||||
musicdef_volume = DEFAULT_MUSICDEF_VOLUME;
|
||||
|
||||
{
|
||||
musicdef_t *def = S_FindMusicDef(music_name);
|
||||
|
||||
if (def)
|
||||
{
|
||||
musicdef_volume = def->volume;
|
||||
I_SetCurrentSongVolume(def->volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2350,7 +2347,7 @@ void S_SetMusicVolume(INT32 digvolume)
|
|||
digvolume = cv_digmusicvolume.value;
|
||||
|
||||
//CV_SetValue(&cv_digmusicvolume, digvolume);
|
||||
actualdigmusicvolume = digvolume * USER_VOLUME_SCALE;
|
||||
actualdigmusicvolume = digvolume;
|
||||
I_SetMusicVolume(digvolume);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ extern openmpt_module *openmpt_mhandle;
|
|||
#define PICKUP_SOUND 0x8000
|
||||
|
||||
//
|
||||
#define SOUND_VOLUME_RANGE 256
|
||||
#define MAX_SOUND_VOLUME 255
|
||||
#define SOUND_VOLUME_RANGE 100
|
||||
#define MAX_SOUND_VOLUME 100
|
||||
|
||||
#define DEFAULT_MUSICDEF_VOLUME ( 100 / VOLUME_DIVIDER )
|
||||
#define DEFAULT_MUSICDEF_VOLUME 100
|
||||
|
||||
extern consvar_t stereoreverse;
|
||||
extern consvar_t cv_soundvolume, cv_closedcaptioning, cv_digmusicvolume;
|
||||
|
|
@ -197,7 +197,6 @@ extern struct cursongcredit
|
|||
} cursongcredit;
|
||||
|
||||
extern musicdef_t *musicdefstart;
|
||||
extern int musicdef_volume;
|
||||
|
||||
void S_LoadMusicDefs(UINT16 wadnum);
|
||||
void S_InitMusicDefs(void);
|
||||
|
|
|
|||
|
|
@ -205,7 +205,8 @@ static void init_exchndl()
|
|||
|
||||
if (exchndl_module == NULL)
|
||||
{
|
||||
I_Error("exchndl.dll or mgwhelp.dll is missing");
|
||||
I_Error("exchndl.dll or mgwhelp.dll is missing, RPT files cannot be generated.\n"
|
||||
"If you NEED to run without them, use -noexchndl.");
|
||||
}
|
||||
|
||||
using PFN_ExcHndlInit = void(*)(void);
|
||||
|
|
@ -297,6 +298,7 @@ int main(int argc, char **argv)
|
|||
//I_OutputMsg("I_StartupSystem() ...\n");
|
||||
I_StartupSystem();
|
||||
#if defined (_WIN32)
|
||||
if (!M_CheckParm("-noexchndl"))
|
||||
{
|
||||
#if 0 // just load the DLL
|
||||
p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsDebuggerPresent");
|
||||
|
|
|
|||
|
|
@ -194,74 +194,9 @@ static char returnWadPath[256];
|
|||
#include "../byteptr.h"
|
||||
#endif
|
||||
|
||||
void I_StoreExJoystick(SDL_GameController *dev)
|
||||
{
|
||||
// ExJoystick is a massive hack to avoid needing to completely
|
||||
// rewrite pretty much all of the controller support from scratch...
|
||||
|
||||
// Used in favor of most instances of SDL_GameControllerClose.
|
||||
// If a joystick would've been discarded, then save it in an array,
|
||||
// because we want it have it for the joystick input screen.
|
||||
|
||||
int index = 0;
|
||||
|
||||
if (dev == NULL)
|
||||
{
|
||||
// No joystick?
|
||||
return;
|
||||
}
|
||||
|
||||
index = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(dev));
|
||||
|
||||
if (index >= MAXGAMEPADS || index < 0)
|
||||
{
|
||||
// Not enough space to save this joystick, completely discard.
|
||||
SDL_GameControllerClose(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ExJoystick[index] == dev)
|
||||
{
|
||||
// No need to do anything else.
|
||||
return;
|
||||
}
|
||||
|
||||
if (ExJoystick[index] != NULL)
|
||||
{
|
||||
// Discard joystick in the old slot.
|
||||
SDL_GameControllerClose(ExJoystick[index]);
|
||||
}
|
||||
|
||||
// Keep for safe-keeping.
|
||||
ExJoystick[index] = dev;
|
||||
}
|
||||
|
||||
/** \brief The JoyReset function
|
||||
|
||||
\param JoySet Joystick info to reset
|
||||
|
||||
\return void
|
||||
*/
|
||||
static void JoyReset(SDLJoyInfo_t *JoySet)
|
||||
{
|
||||
if (JoySet->dev)
|
||||
{
|
||||
I_StoreExJoystick(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[MAXSPLITSCREENPLAYERS] = {0,0,0,0};
|
||||
|
||||
/** \brief SDL info about joystick 1
|
||||
/** \brief SDL info about joysticks
|
||||
*/
|
||||
SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS];
|
||||
SDL_GameController *ExJoystick[MAXGAMEPADS];
|
||||
|
||||
SDL_bool consolevent = SDL_FALSE;
|
||||
SDL_bool framebuffer = SDL_FALSE;
|
||||
|
|
@ -983,316 +918,78 @@ void I_JoyScale4(void)
|
|||
JoyInfo[3].scale = Joystick[3].bGamepadStyle?1:cv_joyscale[1].value;
|
||||
}
|
||||
|
||||
// Cheat to get the device index for a game controller handle
|
||||
INT32 I_GetJoystickDeviceIndex(SDL_GameController *dev)
|
||||
void I_SetGamepadPlayerIndex(INT32 device_id, INT32 player)
|
||||
{
|
||||
SDL_Joystick *joystick = NULL;
|
||||
#if !(SDL_VERSION_ATLEAST(2,0,12))
|
||||
(void)device_id;
|
||||
(void)player;
|
||||
#else
|
||||
I_Assert(device_id > 0); // Gamepad devices are always ID 1 or higher
|
||||
I_Assert(player >= 0 && player < MAXSPLITSCREENPLAYERS);
|
||||
|
||||
joystick = SDL_GameControllerGetJoystick(dev);
|
||||
|
||||
if (joystick)
|
||||
SDL_GameController *controller = SDL_GameControllerFromInstanceID(device_id - 1);
|
||||
if (controller == NULL)
|
||||
{
|
||||
return SDL_JoystickInstanceID(joystick);
|
||||
return;
|
||||
}
|
||||
|
||||
return -1;
|
||||
SDL_GameControllerSetPlayerIndex(controller, player);
|
||||
#endif
|
||||
}
|
||||
|
||||
void I_UpdateJoystickDeviceIndex(UINT8 player)
|
||||
void I_SetGamepadIndicatorColor(INT32 device_id, UINT8 red, UINT8 green, UINT8 blue)
|
||||
{
|
||||
///////////////////////////////////////////////
|
||||
// update this joystick's device index (wow) //
|
||||
///////////////////////////////////////////////
|
||||
#if !(SDL_VERSION_ATLEAST(2,0,14))
|
||||
(void)device_id;
|
||||
(void)player;
|
||||
#else
|
||||
I_Assert(device_id > 0); // Gamepad devices are always ID 1 or higher
|
||||
|
||||
if (JoyInfo[player].dev)
|
||||
SDL_GameController *controller = SDL_GameControllerFromInstanceID(device_id - 1);
|
||||
if (controller == NULL)
|
||||
{
|
||||
cv_usejoystick[player].value = I_GetJoystickDeviceIndex(JoyInfo[player].dev) + 1;
|
||||
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, cv_usejoystick[player].value);
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 joystickID, compareJoystick;
|
||||
|
||||
for (joystickID = 0; joystickID < MAXSPLITSCREENPLAYERS; joystickID++)
|
||||
{
|
||||
// is this cv_usejoystick used?
|
||||
const INT32 value = atoi(cv_usejoystick[joystickID].string);
|
||||
|
||||
for (compareJoystick = 0; compareJoystick < MAXSPLITSCREENPLAYERS; compareJoystick++)
|
||||
{
|
||||
if (compareJoystick == player)
|
||||
continue;
|
||||
|
||||
if (value == JoyInfo[compareJoystick].oldjoy || value == cv_usejoystick[compareJoystick].value)
|
||||
break;
|
||||
}
|
||||
|
||||
if (compareJoystick == MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
// We DID make it through the whole loop, so we can use this one!
|
||||
cv_usejoystick[player].value = value;
|
||||
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, cv_usejoystick[player].value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (joystickID == MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
// We DID NOT make it through the whole loop, so we can't assign this joystick to anything.
|
||||
// When you try your best, but you don't succeed...
|
||||
cv_usejoystick[player].value = 0;
|
||||
CONS_Printf("I_UpdateJoystickDeviceIndex: Device for %d set to %d\n", player, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Misleading function: updates device indices for all players BUT the one specified.
|
||||
// Necessary for SDL_JOYDEVICEADDED events
|
||||
void I_UpdateJoystickDeviceIndices(UINT8 excludePlayer)
|
||||
{
|
||||
UINT8 player;
|
||||
|
||||
for (player = 0; player < MAXSPLITSCREENPLAYERS; player++)
|
||||
{
|
||||
if (player == excludePlayer)
|
||||
continue;
|
||||
|
||||
I_UpdateJoystickDeviceIndex(player);
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Shuts down joystick
|
||||
\return void
|
||||
*/
|
||||
void I_ShutdownJoystick(UINT8 index)
|
||||
{
|
||||
INT32 i;
|
||||
event_t event;
|
||||
|
||||
event.device = I_GetJoystickDeviceIndex(JoyInfo[index].dev);
|
||||
event.type = ev_keyup;
|
||||
event.data2 = 0;
|
||||
event.data3 = 0;
|
||||
|
||||
// emulate the up of all joystick buttons
|
||||
for (i = 0; i < JOYBUTTONS; i++)
|
||||
{
|
||||
event.data1 = KEY_JOY1+i;
|
||||
D_PostEvent(&event);
|
||||
return;
|
||||
}
|
||||
|
||||
// reset joystick position
|
||||
event.type = ev_joystick;
|
||||
for (i = 0; i < JOYAXES; i++)
|
||||
{
|
||||
event.data1 = i;
|
||||
D_PostEvent(&event);
|
||||
}
|
||||
|
||||
joystick_started[index] = 0;
|
||||
JoyReset(&JoyInfo[index]);
|
||||
|
||||
// don't shut down the subsystem here, because hotplugging
|
||||
}
|
||||
|
||||
/** \brief Open joystick handle
|
||||
|
||||
\param fname name of joystick
|
||||
|
||||
\return axises
|
||||
|
||||
|
||||
*/
|
||||
static int joy_open(int playerIndex, int joyIndex)
|
||||
{
|
||||
SDL_GameController *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 (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == 0)
|
||||
{
|
||||
CONS_Printf(M_GetText("Game Controller 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_GameControllerOpen(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[playerIndex].dev)
|
||||
{
|
||||
if (JoyInfo[playerIndex].dev == newdev // same device, nothing to do
|
||||
|| (newdev == NULL && SDL_GameControllerGetAttached(JoyInfo[playerIndex].dev))) // we failed, but already have a working device
|
||||
{
|
||||
return SDL_CONTROLLER_AXIS_MAX;
|
||||
}
|
||||
|
||||
// Else, we're changing devices, so send neutral joy events
|
||||
CONS_Debug(DBG_GAMELOGIC, "Joystick%d device is changing; resetting events...\n", playerIndex+1);
|
||||
I_ShutdownJoystick(playerIndex);
|
||||
}
|
||||
|
||||
JoyInfo[playerIndex].dev = newdev;
|
||||
|
||||
if (JoyInfo[playerIndex].dev == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick%d: Couldn't open device - %s\n"), playerIndex+1, SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick%d: %s\n"), playerIndex+1, SDL_GameControllerName(JoyInfo[playerIndex].dev));
|
||||
|
||||
JoyInfo[playerIndex].axises = SDL_CONTROLLER_AXIS_MAX;
|
||||
JoyInfo[playerIndex].buttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
JoyInfo[playerIndex].hats = 1;
|
||||
JoyInfo[playerIndex].balls = 0;
|
||||
|
||||
//JoyInfo[playerIndex].bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo[playerIndex].dev), "pad");
|
||||
|
||||
return JoyInfo[playerIndex].axises;
|
||||
}
|
||||
SDL_GameControllerSetLED(controller, red, green, blue);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// I_InitJoystick
|
||||
// I_StartupInput
|
||||
//
|
||||
void I_InitJoystick(UINT8 index)
|
||||
void I_StartupInput(void)
|
||||
{
|
||||
SDL_GameController *newcontroller = NULL;
|
||||
UINT8 i;
|
||||
|
||||
//I_ShutdownJoystick();
|
||||
//SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
|
||||
if (M_CheckParm("-nojoy"))
|
||||
return;
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER))
|
||||
{
|
||||
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");
|
||||
CONS_Printf("I_StartupInput()...\n");
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
|
||||
return;
|
||||
}
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't initialize game controllers: %s\n"), SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == 0)
|
||||
{
|
||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't initialize gamepads: %s\n"), SDL_GetError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_usejoystick[index].value)
|
||||
newcontroller = SDL_GameControllerOpen(cv_usejoystick[index].value-1);
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (i == index)
|
||||
continue;
|
||||
|
||||
if (JoyInfo[i].dev == newcontroller)
|
||||
break;
|
||||
}
|
||||
|
||||
if (newcontroller && i < MAXSPLITSCREENPLAYERS) // don't override an active device
|
||||
{
|
||||
cv_usejoystick[index].value = I_GetJoystickDeviceIndex(JoyInfo[index].dev) + 1;
|
||||
CONS_Printf("I_InitJoystick: Device for %d set to %d\n", index, cv_usejoystick[index].value);
|
||||
}
|
||||
else if (newcontroller && joy_open(index, cv_usejoystick[index].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[index].oldjoy = I_GetJoystickDeviceIndex(JoyInfo[index].dev) + 1;
|
||||
joystick_started[index] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (JoyInfo[index].oldjoy)
|
||||
I_ShutdownJoystick(index);
|
||||
cv_usejoystick[index].value = 0;
|
||||
CONS_Printf("I_InitJoystick: Device for %d set to %d\n", index, cv_usejoystick[index].value);
|
||||
joystick_started[index] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (JoyInfo[i].dev == newcontroller)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
// Joystick didn't end up being used
|
||||
I_StoreExJoystick(newcontroller);
|
||||
}
|
||||
}
|
||||
|
||||
void I_InitJoystick1(void)
|
||||
{
|
||||
I_InitJoystick(0);
|
||||
}
|
||||
|
||||
void I_InitJoystick2(void)
|
||||
{
|
||||
I_InitJoystick(1);
|
||||
}
|
||||
|
||||
void I_InitJoystick3(void)
|
||||
{
|
||||
I_InitJoystick(2);
|
||||
}
|
||||
|
||||
void I_InitJoystick4(void)
|
||||
{
|
||||
I_InitJoystick(3);
|
||||
// Upon initialization, the gamecontroller subsystem will automatically dispatch controller device added events
|
||||
// for controllers connected before initialization.
|
||||
}
|
||||
|
||||
static void I_ShutdownInput(void)
|
||||
{
|
||||
UINT8 i;
|
||||
|
||||
// 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.
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
I_ShutdownJoystick(i);
|
||||
// The game code is now responsible for resetting its internal state based on ev_gamepad_device_removed events.
|
||||
// In practice, Input should never be shutdown and restarted during runtime.
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) == SDL_INIT_GAMECONTROLLER)
|
||||
{
|
||||
|
|
@ -1322,14 +1019,28 @@ static char joyname[255]; // joystick name is straight from the driver
|
|||
const char *I_GetJoyName(INT32 joyindex)
|
||||
{
|
||||
const char *tempname = NULL;
|
||||
SDL_Joystick* joystick;
|
||||
joyname[0] = 0;
|
||||
joyindex--; //SDL's Joystick System starts at 0, not 1
|
||||
if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_JOYSTICK) != SDL_INIT_JOYSTICK)
|
||||
{
|
||||
tempname = SDL_JoystickNameForIndex(joyindex);
|
||||
if (tempname)
|
||||
strncpy(joyname, tempname, 255);
|
||||
return joyname;
|
||||
}
|
||||
|
||||
// joyindex corresponds to the open joystick *instance* ID, not the joystick number
|
||||
joystick = SDL_JoystickFromInstanceID(joyindex);
|
||||
if (joystick == NULL)
|
||||
{
|
||||
return joyname;
|
||||
}
|
||||
|
||||
tempname = SDL_JoystickNameForIndex(joyindex);
|
||||
if (tempname)
|
||||
{
|
||||
strncpy(joyname, tempname, 255);
|
||||
}
|
||||
|
||||
return joyname;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
|
|||
SDLforceUngrabMouse();
|
||||
}
|
||||
memset(gamekeydown, 0, sizeof(gamekeydown)); // TODO this is a scary memset
|
||||
memset(deviceResponding, false, sizeof (deviceResponding));
|
||||
G_ResetAllDeviceResponding();
|
||||
|
||||
if (MOUSE_MENU)
|
||||
{
|
||||
|
|
@ -701,7 +701,7 @@ static void Impl_HandleControllerAxisEvent(SDL_ControllerAxisEvent evt)
|
|||
event_t event;
|
||||
INT32 value;
|
||||
|
||||
event.type = ev_joystick;
|
||||
event.type = ev_gamepad_axis;
|
||||
|
||||
event.device = 1 + evt.which;
|
||||
if (event.device == INT32_MAX)
|
||||
|
|
@ -777,6 +777,40 @@ static void Impl_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint
|
|||
}
|
||||
}
|
||||
|
||||
static void Impl_HandleControllerDeviceAddedEvent(SDL_ControllerDeviceEvent event)
|
||||
{
|
||||
// The game is always interested in controller events, even if they aren't internally assigned to a player.
|
||||
// Thus, we *always* open SDL controllers as they become available, to begin receiving their events.
|
||||
|
||||
SDL_GameController* controller = SDL_GameControllerOpen(event.which);
|
||||
if (controller == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
|
||||
SDL_JoystickID joystick_instance_id = SDL_JoystickInstanceID(joystick);
|
||||
|
||||
event_t engine_event {};
|
||||
|
||||
engine_event.type = ev_gamepad_device_added;
|
||||
engine_event.device = 1 + joystick_instance_id;
|
||||
|
||||
D_PostEvent(&engine_event);
|
||||
}
|
||||
|
||||
static void Impl_HandleControllerDeviceRemovedEvent(SDL_ControllerDeviceEvent event)
|
||||
{
|
||||
// SDL only posts Device Removed events for controllers that have actually been opened.
|
||||
// Thus, we don't need to filter out controllers that may not have opened successfully prior to this event.
|
||||
event_t engine_event {};
|
||||
|
||||
engine_event.type = ev_gamepad_device_removed;
|
||||
engine_event.device = 1 + event.which;
|
||||
|
||||
D_PostEvent(&engine_event);
|
||||
}
|
||||
|
||||
static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
|
||||
{
|
||||
switch (keycode)
|
||||
|
|
@ -983,8 +1017,6 @@ void I_GetEvent(void)
|
|||
// otherwise we'll end up catching the warp back to center.
|
||||
//int mouseMotionOnce = 0;
|
||||
|
||||
UINT8 i;
|
||||
|
||||
if (!graphics_started)
|
||||
{
|
||||
return;
|
||||
|
|
@ -1031,147 +1063,14 @@ void I_GetEvent(void)
|
|||
Impl_HandleControllerButtonEvent(evt.cbutton, evt.type);
|
||||
break;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
{
|
||||
// OH BOY are you in for a good time! #abominationstation
|
||||
|
||||
SDL_GameController *newcontroller = SDL_GameControllerOpen(evt.cdevice.which);
|
||||
|
||||
CONS_Debug(DBG_GAMELOGIC, "Controller device index %d added\n", evt.cdevice.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!
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (newcontroller && (!JoyInfo[i].dev || !SDL_GameControllerGetAttached(JoyInfo[i].dev)))
|
||||
{
|
||||
UINT8 j;
|
||||
|
||||
for (j = 0; j < MAXSPLITSCREENPLAYERS; j++)
|
||||
{
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
if (JoyInfo[j].dev == newcontroller)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == MAXSPLITSCREENPLAYERS)
|
||||
{
|
||||
// ensures we aren't overriding a currently active device
|
||||
cv_usejoystick[i].value = evt.cdevice.which + 1;
|
||||
I_UpdateJoystickDeviceIndices(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Was cv_usejoystick disabled in settings?
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (!strcmp(cv_usejoystick[i].string, "0") || !cv_usejoystick[i].value)
|
||||
cv_usejoystick[i].value = 0;
|
||||
else if (atoi(cv_usejoystick[i].string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
|
||||
&& cv_usejoystick[i].value) // update the cvar ONLY if a device exists
|
||||
CV_SetValue(&cv_usejoystick[i], cv_usejoystick[i].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.
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
I_InitJoystick(i);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
CONS_Debug(DBG_GAMELOGIC, "Joystick%d device index: %d\n", i+1, JoyInfo[i].oldjoy);
|
||||
|
||||
#if 0
|
||||
// update the menu
|
||||
if (currentMenu == &OP_JoystickSetDef)
|
||||
M_SetupJoystickMenu(0);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (JoyInfo[i].dev == newcontroller)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAXSPLITSCREENPLAYERS)
|
||||
I_StoreExJoystick(newcontroller);
|
||||
}
|
||||
Impl_HandleControllerDeviceAddedEvent(evt.cdevice);
|
||||
break;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (JoyInfo[i].dev && !SDL_GameControllerGetAttached(JoyInfo[i].dev))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Joystick%d removed, device index: %d\n", i+1, JoyInfo[i].oldjoy);
|
||||
I_ShutdownJoystick(i);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// 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!
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
I_UpdateJoystickDeviceIndex(i);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Was cv_usejoystick disabled in settings?
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
if (!strcmp(cv_usejoystick[i].string, "0"))
|
||||
{
|
||||
cv_usejoystick[i].value = 0;
|
||||
}
|
||||
else if (atoi(cv_usejoystick[i].string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys
|
||||
&& cv_usejoystick[i].value) // update the cvar ONLY if a device exists
|
||||
{
|
||||
CV_SetValue(&cv_usejoystick[i], cv_usejoystick[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
CONS_Debug(DBG_GAMELOGIC, "Joystick%d device index: %d\n", i+1, JoyInfo[i].oldjoy);
|
||||
|
||||
#if 0
|
||||
// update the menu
|
||||
if (currentMenu == &OP_JoystickSetDef)
|
||||
M_SetupJoystickMenu(0);
|
||||
#endif
|
||||
Impl_HandleControllerDeviceRemovedEvent(evt.cdevice);
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
LUA_HookBool(true, HOOK(GameQuit));
|
||||
I_Quit();
|
||||
|
|
@ -1195,10 +1094,7 @@ void I_GetEvent(void)
|
|||
|
||||
// In order to make wheels act like buttons, we have to set their state to Up.
|
||||
// This is because wheel messages don't have an up/down state.
|
||||
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
|
||||
{
|
||||
gamekeydown[i][KEY_MOUSEWHEELDOWN] = gamekeydown[i][KEY_MOUSEWHEELUP] = 0;
|
||||
}
|
||||
G_GetDeviceGameKeyDownArray(0)[KEY_MOUSEWHEELDOWN] = G_GetDeviceGameKeyDownArray(0)[KEY_MOUSEWHEELUP] = 0;
|
||||
}
|
||||
|
||||
static void half_warp_mouse(uint16_t x, uint16_t y) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ static shared_ptr<Mixer<2>> mixer_sound_effects;
|
|||
static shared_ptr<Mixer<2>> mixer_music;
|
||||
static shared_ptr<MusicPlayer> music_player;
|
||||
static shared_ptr<Gain<2>> gain_sound_effects;
|
||||
static shared_ptr<Gain<2>> gain_music;
|
||||
static shared_ptr<Gain<2>> gain_music_player;
|
||||
static shared_ptr<Gain<2>> gain_music_channel;
|
||||
|
||||
static vector<shared_ptr<SoundEffectPlayer>> sound_effect_channels;
|
||||
|
||||
|
|
@ -187,12 +188,14 @@ void initialize_sound()
|
|||
mixer_music = make_shared<Mixer<2>>();
|
||||
music_player = make_shared<MusicPlayer>();
|
||||
gain_sound_effects = make_shared<Gain<2>>();
|
||||
gain_music = make_shared<Gain<2>>();
|
||||
gain_music_player = make_shared<Gain<2>>();
|
||||
gain_music_channel = make_shared<Gain<2>>();
|
||||
gain_sound_effects->bind(mixer_sound_effects);
|
||||
gain_music->bind(mixer_music);
|
||||
gain_music_player->bind(music_player);
|
||||
gain_music_channel->bind(mixer_music);
|
||||
master->add_source(gain_sound_effects);
|
||||
master->add_source(gain_music);
|
||||
mixer_music->add_source(music_player);
|
||||
master->add_source(gain_music_channel);
|
||||
mixer_music->add_source(gain_music_player);
|
||||
for (size_t i = 0; i < static_cast<size_t>(cv_numChannels.value); i++)
|
||||
{
|
||||
shared_ptr<SoundEffectPlayer> player = make_shared<SoundEffectPlayer>();
|
||||
|
|
@ -356,7 +359,7 @@ void I_SetSfxVolume(int volume)
|
|||
|
||||
if (gain_sound_effects)
|
||||
{
|
||||
gain_sound_effects->gain(vol * vol * vol);
|
||||
gain_sound_effects->gain(std::clamp(vol * vol * vol, 0.f, 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -597,6 +600,12 @@ boolean I_LoadSong(char* data, size_t len)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (gain_music_player)
|
||||
{
|
||||
// Reset song volume to 1.0 for newly loaded songs.
|
||||
gain_music_player->gain(1.0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -663,9 +672,22 @@ void I_SetMusicVolume(int volume)
|
|||
{
|
||||
float vol = static_cast<float>(volume) / 100.f;
|
||||
|
||||
if (gain_music)
|
||||
if (gain_music_channel)
|
||||
{
|
||||
gain_music->gain(vol * vol * vol);
|
||||
// Music channel volume is interpreted as logarithmic rather than linear.
|
||||
// We approximate by cubing the gain level so vol 50 roughly sounds half as loud.
|
||||
gain_music_channel->gain(std::clamp(vol * vol * vol, 0.f, 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
void I_SetCurrentSongVolume(int volume)
|
||||
{
|
||||
float vol = static_cast<float>(volume) / 100.f;
|
||||
|
||||
if (gain_music_player)
|
||||
{
|
||||
// However, different from music channel volume, musicdef volumes are explicitly linear.
|
||||
gain_music_player->gain(std::max(vol, 0.f));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ extern "C" {
|
|||
#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
|
||||
|
|
@ -65,9 +62,6 @@ typedef struct SDLJoyInfo_s
|
|||
/** \brief SDL info about controllers
|
||||
*/
|
||||
extern SDLJoyInfo_t JoyInfo[MAXSPLITSCREENPLAYERS];
|
||||
extern SDL_GameController *ExJoystick[MAXGAMEPADS];
|
||||
|
||||
void I_StoreExJoystick(SDL_GameController *dev);
|
||||
|
||||
/** \brief joystick axis deadzone
|
||||
*/
|
||||
|
|
@ -76,18 +70,6 @@ void I_StoreExJoystick(SDL_GameController *dev);
|
|||
|
||||
void I_GetConsoleEvents(void);
|
||||
|
||||
// So we can call this from i_video event loop
|
||||
void I_ShutdownJoystick(UINT8 index);
|
||||
|
||||
// Cheat to get the device index for a game controller handle
|
||||
INT32 I_GetJoystickDeviceIndex(SDL_GameController *dev);
|
||||
|
||||
// Quick thing to make SDL_JOYDEVICEADDED events less of an abomination
|
||||
void I_UpdateJoystickDeviceIndex(UINT8 player);
|
||||
void I_UpdateJoystickDeviceIndices(UINT8 excludePlayer);
|
||||
|
||||
void I_GetConsoleEvents(void);
|
||||
|
||||
void SDLforceUngrabMouse(void);
|
||||
|
||||
// Needed for some WIN32 functions
|
||||
|
|
|
|||
|
|
@ -1135,6 +1135,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"waved2", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved3", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved4", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved5", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Passing sounds
|
||||
{"pass01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
|
|
@ -1204,6 +1204,7 @@ typedef enum
|
|||
sfx_waved2,
|
||||
sfx_waved3,
|
||||
sfx_waved4,
|
||||
sfx_waved5,
|
||||
|
||||
// Passing sounds
|
||||
sfx_pass01,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue