diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0bb3d3db..b9f8dd58 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -95,8 +95,8 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. #endif SINT8 nodetoplayer[MAXNETNODES]; SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) -SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) -SINT8 nodetoplayer4[MAXNETNODES]; // say the numplayer for this node if any (splitscreen) +SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (splitscreen3) +SINT8 nodetoplayer4[MAXNETNODES]; // say the numplayer for this node if any (splitscreen4) UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen boolean nodeingame[MAXNETNODES]; // set false as nodes leave game static tic_t nettics[MAXNETNODES]; // what tic the client have received @@ -121,14 +121,16 @@ UINT8 hu_resynching = 0; // Client specific static ticcmd_t localcmds; static ticcmd_t localcmds2; +static ticcmd_t localcmds3; +static ticcmd_t localcmds4; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen -static UINT8 localtextcmd3[MAXTEXTCMD]; // splitscreen -static UINT8 localtextcmd4[MAXTEXTCMD]; // splitscreen +static UINT8 localtextcmd3[MAXTEXTCMD]; // splitscreen3 +static UINT8 localtextcmd4[MAXTEXTCMD]; // splitscreen4 static tic_t neededtic; SINT8 servernode = 0; // the number of the server node /// \brief do we accept new players? @@ -438,6 +440,8 @@ void D_ResetTiccmds(void) memset(&localcmds, 0, sizeof(ticcmd_t)); memset(&localcmds2, 0, sizeof(ticcmd_t)); + memset(&localcmds3, 0, sizeof(ticcmd_t)); + memset(&localcmds4, 0, sizeof(ticcmd_t)); // Reset the net command list for (i = 0; i < TEXTCMD_HASH_SIZE; i++) @@ -1218,7 +1222,11 @@ static boolean CL_SendJoin(void) CONS_Printf(M_GetText("Sending join request...\n")); netbuffer->packettype = PT_CLIENTJOIN; - if (splitscreen || botingame) + if ((splitscreen || splitscreen3 || splitscreen4) || botingame) + localplayers++; + if (splitscreen3 || splitscreen4) + localplayers++; + if (splitscreen4) localplayers++; netbuffer->u.clientcfg.localplayers = localplayers; netbuffer->u.clientcfg.version = VERSION; @@ -2701,7 +2709,9 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // Is playernum authorized to make this kick? if (playernum != serverplayer && !IsPlayerAdmin(playernum) && !(playerpernode[playernode[playernum]] == 2 - && nodetoplayer2[playernode[playernum]] == pnum)) + && nodetoplayer2[playernode[playernum]] == pnum + && nodetoplayer3[playernode[playernum]] == pnum + && nodetoplayer4[playernode[playernum]] == pnum)) { // We received a kick command from someone who isn't the // server or admin, and who isn't in splitscreen removing @@ -2927,6 +2937,8 @@ static void ResetNode(INT32 node) nodeingame[node] = false; nodetoplayer[node] = -1; nodetoplayer2[node] = -1; + nodetoplayer3[node] = -1; + nodetoplayer4[node] = -1; nettics[node] = gametic; supposedtics[node] = gametic; nodewaiting[node] = 0; @@ -2962,6 +2974,7 @@ void SV_ResetServer(void) playeringame[i] = false; playernode[i] = UINT8_MAX; sprintf(player_names[i], "Player %d", i + 1); + adminplayers[i] = -1; // Populate the entire adminplayers array with -1. } mynode = 0; @@ -3089,7 +3102,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) // Clear player before joining, lest some things get set incorrectly // HACK: don't do this for splitscreen, it relies on preset values - if ((!splitscreen || !splitscreen3 || !splitscreen4) && !botingame) + if (!(splitscreen || splitscreen3 || splitscreen4) && !botingame) CL_ClearPlayer(newplayernum); playeringame[newplayernum] = true; G_AddPlayer(newplayernum); @@ -3185,7 +3198,7 @@ static boolean SV_AddWaitingPlayers(void) buf[1] = newplayernum; if (playerpernode[node] < 1) nodetoplayer[node] = newplayernum; - else + else if (playerpernode[node] < 2) { nodetoplayer2[node] = newplayernum; buf[1] |= 0x80; @@ -3209,14 +3222,14 @@ void CL_AddSplitscreenPlayer(void) CL_SendJoin(); } -void CL_RemoveSplitscreenPlayer(void) +void CL_RemoveSplitscreenPlayer(UINT8 p) { XBOXSTATIC UINT8 buf[2]; if (cl_mode != CL_CONNECTED) return; - buf[0] = (UINT8)secondarydisplayplayer; + buf[0] = p; buf[1] = KICK_MSG_PLAYER_QUIT; SendNetXCmd(XD_KICK, &buf, 2); } @@ -3229,10 +3242,6 @@ boolean Playing(void) boolean SV_SpawnServer(void) { - INT32 i; - for (i = 0; i < MAXPLAYERS; i++) - adminplayers[i] = -1; // Populate the entire adminplayers array with -1. - if (demoplayback) G_StopDemo(); // reset engine parameter if (metalplayback) @@ -3271,6 +3280,8 @@ void SV_StopServer(void) localtextcmd[0] = 0; localtextcmd2[0] = 0; + localtextcmd3[0] = 0; + localtextcmd4[0] = 0; for (i = 0; i < BACKUPTICS; i++) D_Clearticcmd(i); @@ -4256,7 +4267,6 @@ static void CL_SendClientCmd(void) { netbuffer->packettype += 2; G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1); - packetsize = sizeof (client2cmd_pak); } else packetsize = sizeof (clientcmd_pak); @@ -4415,17 +4425,15 @@ static void Local_Maketic(INT32 realtics) // and G_MapEventsToControls if (!dedicated) rendergametic = gametic; // translate inputs (keyboard/mouse/joystick) into game controls - G_BuildTiccmd(&localcmds, realtics); + G_BuildTiccmd(&localcmds, realtics, 1); if ((splitscreen || splitscreen3 || splitscreen4) || botingame) { - G_BuildTiccmd2(&localcmds2, realtics); - + G_BuildTiccmd(&localcmds2, realtics, 2); if (splitscreen3 || splitscreen4) { - G_BuildTiccmd3(&localcmds3, realtics); - + G_BuildTiccmd(&localcmds3, realtics, 3); if (splitscreen4) - G_BuildTiccmd4(&localcmds4, realtics); + G_BuildTiccmd(&localcmds4, realtics, 4); } } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 5fde8ade..c4c3836d 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -107,6 +107,26 @@ typedef struct ticcmd_t cmd, cmd2; } ATTRPACK client2cmd_pak; +// Splitscreen3 packet +// WARNING: must have the same format of clientcmd_pak, for more easy use +typedef struct +{ + UINT8 client_tic; + UINT8 resendfrom; + INT16 consistancy; + ticcmd_t cmd, cmd2, cmd3; +} ATTRPACK client3cmd_pak; + +// Splitscreen4 packet +// WARNING: must have the same format of clientcmd_pak, for more easy use +typedef struct +{ + UINT8 client_tic; + UINT8 resendfrom; + INT16 consistancy; + ticcmd_t cmd, cmd2, cmd3, cmd4; +} ATTRPACK client4cmd_pak; + #ifdef _MSC_VER #pragma warning(disable : 4200) #endif @@ -397,6 +417,8 @@ typedef struct { clientcmd_pak clientpak; // 144 bytes client2cmd_pak client2pak; // 200 bytes + client3cmd_pak client3pak; // 256 bytes(?) + client4cmd_pak client4pak; // 312 bytes(?) servertics_pak serverpak; // 132495 bytes (more around 360, no?) serverconfig_pak servercfg; // 773 bytes resynchend_pak resynchend; // @@ -488,7 +510,7 @@ void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle); void SV_StopServer(void); void SV_ResetServer(void); void CL_AddSplitscreenPlayer(void); -void CL_RemoveSplitscreenPlayer(void); +void CL_RemoveSplitscreenPlayer(UINT8 p); void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); void CL_UpdateServerList(boolean internetsearch, INT32 room); diff --git a/src/d_event.h b/src/d_event.h index b0d0e3c5..09ff167b 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -27,6 +27,8 @@ typedef enum ev_joystick, ev_mouse2, ev_joystick2, + ev_joystick3, + ev_joystick4, } evtype_t; // Event structure. diff --git a/src/d_main.c b/src/d_main.c index 7b262998..367bd012 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -636,7 +636,7 @@ void D_SRB2Loop(void) if ((splitscreen3 || splitscreen4) && camera3.chase) P_MoveChaseCamera(&players[thirddisplayplayer], &camera3, false); if (splitscreen4 && camera4.chase) - P_MoveChaseCamera(&players[fourthdisplayplayer], &camera3, false); + P_MoveChaseCamera(&players[fourthdisplayplayer], &camera4, false); if (camera.chase) P_MoveChaseCamera(&players[displayplayer], &camera, false); } diff --git a/src/d_net.h b/src/d_net.h index 3bf5d693..cb70b6df 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -36,6 +36,8 @@ extern INT64 sendbytes; // Realtime updated extern SINT8 nodetoplayer[MAXNETNODES]; extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen) +extern SINT8 nodetoplayer3[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen3) +extern SINT8 nodetoplayer4[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen4) extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game diff --git a/src/g_game.c b/src/g_game.c index 0927d213..f2fcbc8e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -806,7 +806,7 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } -static INT32 JoyAxis(axis_input_e axissel) +static INT32 Joy1Axis(axis_input_e axissel) { INT32 retaxis; INT32 axisval; @@ -1039,7 +1039,7 @@ static INT32 Joy3Axis(axis_input_e axissel) return retaxis; } -static INT32 Joy3Axis(axis_input_e axissel) +static INT32 Joy4Axis(axis_input_e axissel) { INT32 retaxis; INT32 axisval; @@ -1117,6 +1117,35 @@ static INT32 Joy3Axis(axis_input_e axissel) return retaxis; } +static boolean InputDown(INT32 gc, UINT8 p) +{ + switch (p) + { + case 2: + return PLAYER2INPUTDOWN(gc); + case 3: + return PLAYER3INPUTDOWN(gc); + case 4: + return PLAYER4INPUTDOWN(gc); + default: + return PLAYER1INPUTDOWN(gc); + } +} + +static INT32 JoyAxis(axis_input_e axissel, UINT8 p) +{ + switch (p) + { + case 2: + return Joy2Axis(axissel); + case 3: + return Joy3Axis(axissel); + case 4: + return Joy4Axis(axissel); + default: + return Joy1Axis(axissel); + } +} // // G_BuildTiccmd @@ -1133,37 +1162,111 @@ static fixed_t forwardmove[2] = {25<>16, 50<>16}; static fixed_t sidemove[2] = {25<>16, 50<>16}; // faster! static fixed_t angleturn[3] = {400, 800, 200}; // + slow turn -void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) +void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { boolean forcestrafe = false; - INT32 tspeed, forward, side, axis, i; + INT32 laim, th, tspeed, forward, side, axis, i; const INT32 speed = 1; // these ones used for multiple conditions - boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove; - player_t *player = &players[consoleplayer]; - camera_t *thiscam = &camera; + boolean turnleft, turnright, invertmouse, mouseaiming, lookaxis, analog, analogjoystickmove, gamepadjoystickmove, kbl; + player_t *player; + camera_t *thiscam; + angle_t lang; - static INT32 turnheld; // for accelerative turning - static boolean keyboard_look; // true if lookup/down using keyboard + static INT32 turnheld, turnheld2, turnheld3, turnheld4; // for accelerative turning + static boolean keyboard_look, keyboard_look2, keyboard_look3, keyboard_look4; // true if lookup/down using keyboard - G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver + if (ssplayer == 2) + { + player = &players[secondarydisplayplayer]; + thiscam = (player->bot == 2 ? &camera : &camera2); + lang = localangle2; + laim = localaiming2; + th = turnheld2; + kbl = keyboard_look2; + G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); + } + else if (ssplayer == 3) + { + player = &players[thirddisplayplayer]; + thiscam = &camera3; + lang = localangle3; + laim = localaiming3; + th = turnheld3; + kbl = keyboard_look3; + G_CopyTiccmd(cmd, I_BaseTiccmd3(), 1); + } + else if (ssplayer == 4) + { + player = &players[fourthdisplayplayer]; + thiscam = &camera4; + lang = localangle3; + laim = localaiming3; + th = turnheld4; + kbl = keyboard_look4; + G_CopyTiccmd(cmd, I_BaseTiccmd4(), 1); + } + else + { + player = &players[consoleplayer]; + thiscam = &camera; + lang = localangle; + laim = localaiming; + th = turnheld; + kbl = keyboard_look; + G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver + } // why build a ticcmd if we're paused? // Or, for that matter, if we're being reborn. if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN)) { - cmd->angleturn = (INT16)(localangle >> 16); - cmd->aiming = G_ClipAimingPitch(&localaiming); + cmd->angleturn = (INT16)(lang >> 16); + cmd->aiming = G_ClipAimingPitch(&laim); return; } - turnright = PLAYER1INPUTDOWN(gc_turnright); - turnleft = PLAYER1INPUTDOWN(gc_turnleft); - mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook.value; - analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle; - gamepadjoystickmove = cv_usejoystick.value && Joystick.bGamepadStyle; + if (ssplayer == 2) + { + mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook2.value; + invertmouse = cv_invertmouse2.value; + lookaxis = cv_lookaxis2.value; + analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle; + gamepadjoystickmove = cv_usejoystick2.value && Joystick2.bGamepadStyle; + analog = cv_analog2.value; + } + else if (ssplayer == 3) + { + mouseaiming = false; + invertmouse = false; + lookaxis = cv_lookaxis3.value; + analogjoystickmove = cv_usejoystick3.value && !Joystick3.bGamepadStyle; + gamepadjoystickmove = cv_usejoystick3.value && Joystick3.bGamepadStyle; + analog = cv_analog3.value; + } + else if (ssplayer == 4) + { + mouseaiming = false; + invertmouse = false; + lookaxis = cv_lookaxis4.value; + analogjoystickmove = cv_usejoystick4.value && !Joystick4.bGamepadStyle; + gamepadjoystickmove = cv_usejoystick4.value && Joystick4.bGamepadStyle; + analog = cv_analog4.value; + } + else + { + mouseaiming = (PLAYER1INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook.value; + invertmouse = cv_invertmouse.value; + lookaxis = cv_lookaxis.value; + analogjoystickmove = cv_usejoystick.value && !Joystick.bGamepadStyle; + gamepadjoystickmove = cv_usejoystick.value && Joystick.bGamepadStyle; + analog = cv_analog.value; + } - axis = JoyAxis(AXISTURN); + turnright = InputDown(gc_turnright, ssplayer); + turnleft = InputDown(gc_turnleft, ssplayer); + + axis = JoyAxis(AXISTURN, ssplayer); if (gamepadjoystickmove && axis != 0) { turnright = turnright || (axis > 0); @@ -1174,30 +1277,32 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // use two stage accelerative turning // on the keyboard and joystick if (turnleft || turnright) - turnheld += realtics; + th += realtics; else - turnheld = 0; + th = 0; - if (turnheld < SLOWTURNTICS) + if (th < SLOWTURNTICS) tspeed = 2; // slow turn else tspeed = speed; // let movement keys cancel each other out - if (cv_analog.value) // Analog + if (analog) // Analog { if (turnright) cmd->angleturn = (INT16)(cmd->angleturn - angleturn[tspeed]); if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); } - if (cv_analog.value || twodlevel + + if (analog || twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) || (!demoplayback && (player->climbing || (player->pflags & PF_NIGHTSMODE) || (player->pflags & PF_SLIDING) || (player->pflags & PF_FORCESTRAFE)))) // Analog forcestrafe = true; + if (forcestrafe) // Analog { if (turnright) @@ -1226,7 +1331,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) } /* - axis = JoyAxis(AXISSTRAFE); + axis = JoyAxis(AXISSTRAFE, ssplayer); if (gamepadjoystickmove && axis != 0) { if (axis < 0) @@ -1242,26 +1347,26 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) */ // forward with key or button // SRB2kart - we use an accel/brake instead of forward/backward. - if (PLAYER1INPUTDOWN(gc_accelerate) || player->kartstuff[k_mushroomtimer]) + if (InputDown(gc_accelerate, ssplayer) || player->kartstuff[k_mushroomtimer]) { cmd->buttons |= BT_ACCELERATE; forward = forwardmove[1]; // 50 } - if (PLAYER1INPUTDOWN(gc_brake)) + if (InputDown(gc_brake, ssplayer)) { cmd->buttons |= BT_BRAKE; forward -= forwardmove[0]; // 25 - Halved value so clutching is possible } // But forward/backward IS used for aiming. - axis = JoyAxis(AXISMOVE); - if (PLAYER1INPUTDOWN(gc_aimforward) || (gamepadjoystickmove && axis < 0) || (analogjoystickmove && axis < 0)) + axis = JoyAxis(AXISMOVE, ssplayer); + if (InputDown(gc_aimforward, ssplayer) || (gamepadjoystickmove && axis < 0) || (analogjoystickmove && axis < 0)) cmd->buttons |= BT_FORWARD; - if (PLAYER1INPUTDOWN(gc_aimbackward) || (gamepadjoystickmove && axis > 0) || (analogjoystickmove && axis > 0)) + if (InputDown(gc_aimbackward, ssplayer) || (gamepadjoystickmove && axis > 0) || (analogjoystickmove && axis > 0)) cmd->buttons |= BT_BACKWARD; /* - if (PLAYER1INPUTDOWN(gc_forward) || (gamepadjoystickmove && axis < 0)) + if (InputDown(gc_forward, ssplayer) || (gamepadjoystickmove && axis < 0)) forward = forwardmove[speed]; - if (PLAYER1INPUTDOWN(gc_backward) || (gamepadjoystickmove && axis > 0)) + if (InputDown(gc_backward, ssplayer) || (gamepadjoystickmove && axis > 0)) forward -= forwardmove[speed]; */ @@ -1274,14 +1379,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // those people are weird /* // SRB2kart - these aren't used in kart - if (PLAYER1INPUTDOWN(gc_straferight)) + if (InputDown(gc_straferight, ssplayer)) side += sidemove[speed]; - if (PLAYER1INPUTDOWN(gc_strafeleft)) + if (InputDown(gc_strafeleft, ssplayer)) side -= sidemove[speed]; - if (PLAYER1INPUTDOWN(gc_driftleft)) + if (InputDown(gc_driftleft, ssplayer)) cmd->buttons |= BT_WEAPONNEXT; // Next Weapon - if (PLAYER1INPUTDOWN(gc_driftright)) + if (InputDown(gc_driftright, ssplayer)) cmd->buttons |= BT_WEAPONPREV; // Previous Weapon */ @@ -1291,38 +1396,38 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) //use the four avaliable bits to determine the weapon. cmd->buttons &= ~BT_WEAPONMASK; for (i = 0; i < NUM_WEAPONS; ++i) - if (PLAYER1INPUTDOWN(gc_wepslot1 + i)) + if (InputDown(gc_wepslot1 + i, ssplayer)) { cmd->buttons |= (UINT16)(i + 1); break; } // fire with any button/key - axis = JoyAxis(AXISFIRE); - if (PLAYER1INPUTDOWN(gc_fire) || (cv_usejoystick.value && axis > 0)) + axis = JoyAxis(AXISFIRE, ssplayer); + if (InputDown(gc_fire, ssplayer) || (cv_usejoystick.value && axis > 0)) cmd->buttons |= BT_ATTACK; // fire normal with any button/key /* - axis = JoyAxis(AXISFIRENORMAL); - if (PLAYER1INPUTDOWN(gc_accelerate) || (cv_usejoystick.value && axis > 0)) + axis = JoyAxis(ssplayer, AXISFIRENORMAL); + if (InputDown(gc_accelerate, ssplayer) || (cv_usejoystick.value && axis > 0)) cmd->buttons |= BT_ACCELERATE; */ - if (PLAYER1INPUTDOWN(gc_spectate)) + if (InputDown(gc_spectate, ssplayer)) cmd->buttons |= BT_SPECTATE; // Lua scriptable buttons - if (PLAYER1INPUTDOWN(gc_custom1)) + if (InputDown(gc_custom1, ssplayer)) cmd->buttons |= BT_CUSTOM1; - if (PLAYER1INPUTDOWN(gc_custom2)) + if (InputDown(gc_custom2, ssplayer)) cmd->buttons |= BT_CUSTOM2; - if (PLAYER1INPUTDOWN(gc_custom3)) + if (InputDown(gc_custom3, ssplayer)) cmd->buttons |= BT_CUSTOM3; // use with any button/key /* - if (PLAYER1INPUTDOWN(gc_brake)) + if (InputDown(gc_brake, ssplayer)) cmd->buttons |= BT_BRAKE; */ @@ -1330,17 +1435,17 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) /* if (cv_debug || cv_analog.value || demoplayback || objectplacing || player->pflags & PF_NIGHTSMODE) { - if (PLAYER1INPUTDOWN(gc_aimforward)) + if (InputDown(gc_aimforward, ssplayer)) cmd->buttons |= BT_FORWARD; - if (PLAYER1INPUTDOWN(gc_aimbackward)) + if (InputDown(gc_aimbackward, ssplayer)) cmd->buttons |= BT_BACKWARD; } */ /* - if (PLAYER1INPUTDOWN(gc_lookback)) + if (InputDown(gc_lookback, ssplayer)) { - if (camera.chase && !player->kartstuff[k_camspin]) + if (thiscam->chase && !player->kartstuff[k_camspin]) player->kartstuff[k_camspin] = 1; } else if (player->kartstuff[k_camspin] > 0) @@ -1348,58 +1453,58 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) */ // jump button - if (PLAYER1INPUTDOWN(gc_jump)) + if (InputDown(gc_jump, ssplayer)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... { - INT32 player_invert = cv_invertmouse.value ? -1 : 1; + INT32 player_invert = invertmouse ? -1 : 1; INT32 screen_invert = (player->mo && (player->mo->eflags & MFE_VERTICALFLIP) - && (!camera.chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted + && (!thiscam->chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted ? -1 : 1; // set to -1 or 1 to multiply // mouse look stuff (mouse look is not the same as mouse aim) if (mouseaiming) { - keyboard_look = false; + kbl = false; // looking up/down - localaiming += (mlooky<<19)*player_invert*screen_invert; + laim += (mlooky<<19)*player_invert*screen_invert; } - axis = JoyAxis(AXISLOOK); - if (analogjoystickmove && axis != 0 && cv_lookaxis.value != 0) - localaiming += (axis<<16) * screen_invert; + axis = JoyAxis(AXISLOOK, ssplayer); + if (analogjoystickmove && axis != 0 && lookaxis) + laim += (axis<<16) * screen_invert; // spring back if not using keyboard neither mouselookin' - if (!keyboard_look && cv_lookaxis.value == 0 && !mouseaiming) - localaiming = 0; + if (!kbl && !lookaxis && !mouseaiming) + laim = 0; - if (PLAYER1INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0)) + if (InputDown(gc_lookup, ssplayer) || (gamepadjoystickmove && axis < 0)) { - localaiming += KB_LOOKSPEED * screen_invert; - keyboard_look = true; + laim += KB_LOOKSPEED * screen_invert; + kbl = true; } - else if (PLAYER1INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && axis > 0)) + else if (InputDown(gc_lookdown, ssplayer) || (gamepadjoystickmove && axis > 0)) { - localaiming -= KB_LOOKSPEED * screen_invert; - keyboard_look = true; + laim -= KB_LOOKSPEED * screen_invert; + kbl = true; } - else if (PLAYER1INPUTDOWN(gc_centerview)) - localaiming = 0; + else if (InputDown(gc_centerview, ssplayer)) + laim = 0; // accept no mlook for network games if (!cv_allowmlook.value) - localaiming = 0; + laim = 0; - cmd->aiming = G_ClipAimingPitch(&localaiming); + cmd->aiming = G_ClipAimingPitch(&laim); } if (!mouseaiming && cv_mousemove.value) forward += mousey; - if (cv_analog.value || + if (analog || (!demoplayback && (player->climbing || (player->pflags & PF_SLIDING)))) // Analog for mouse side += mousex*2; @@ -1426,7 +1531,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) } //Silly hack to make 2d mode *somewhat* playable with no chasecam. - if ((twodlevel || (player->mo && player->mo->flags2 & MF2_TWOD)) && !camera.chase) + if ((twodlevel || (player->mo && player->mo->flags2 & MF2_TWOD)) && !thiscam->chase) { INT32 temp = forward; forward = side; @@ -1437,7 +1542,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) cmd->sidemove = (SINT8)(cmd->sidemove + side); //{ SRB2kart - Drift support - axis = JoyAxis(AXISTURN); + axis = JoyAxis(AXISTURN, ssplayer); if (cmd->angleturn > 0) // Drifting to the left cmd->buttons |= BT_DRIFTLEFT; @@ -1450,339 +1555,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) cmd->buttons &= ~BT_DRIFTRIGHT; //} - if (cv_analog.value) { - cmd->angleturn = (INT16)(thiscam->angle >> 16); - if (player->awayviewtics) - cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); - } - else - { - // limit turning to angleturn[1] to stop mouselook letting you look too fast - if (cmd->angleturn > angleturn[1]) - cmd->angleturn = angleturn[1]; - else if (cmd->angleturn < -angleturn[1]) - cmd->angleturn = -angleturn[1]; - - if (player->mo) - cmd->angleturn = K_GetKartTurnValue(player, cmd->angleturn); - - // SRB2kart - no additional angle if not moving - if ((player->mo && player->speed > 0) || (leveltime > 140 && (cmd->buttons & BT_ACCELERATE) && (cmd->buttons & BT_BRAKE))) - localangle += (cmd->angleturn<<16); - - cmd->angleturn = (INT16)(localangle >> 16); - } - - //Reset away view if a command is given. - if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) - && displayplayer != consoleplayer) - displayplayer = consoleplayer; -} - -// like the g_buildticcmd 1 but using mouse2, gamcontrolbis, ... -void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) -{ - boolean forcestrafe = false; - INT32 tspeed, forward, side, axis, i; - const INT32 speed = 1; - // these ones used for multiple conditions - boolean turnleft, turnright, mouseaiming, analogjoystickmove, gamepadjoystickmove; - player_t *player = &players[secondarydisplayplayer]; - camera_t *thiscam = (player->bot == 2 ? &camera : &camera2); - - static INT32 turnheld; // for accelerative turning - static boolean keyboard_look; // true if lookup/down using keyboard - static boolean resetdown; // don't cam reset every frame - - G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver - - //why build a ticcmd if we're paused? - // Or, for that matter, if we're being reborn. - if (paused || P_AutoPause() || player->playerstate == PST_REBORN) - { - cmd->angleturn = (INT16)(localangle2 >> 16); - cmd->aiming = G_ClipAimingPitch(&localaiming2); - return; - } - - turnright = PLAYER2INPUTDOWN(gc_turnright); - turnleft = PLAYER2INPUTDOWN(gc_turnleft); - mouseaiming = (PLAYER2INPUTDOWN(gc_mouseaiming)) ^ cv_alwaysfreelook2.value; - analogjoystickmove = cv_usejoystick2.value && !Joystick2.bGamepadStyle; - gamepadjoystickmove = cv_usejoystick2.value && Joystick2.bGamepadStyle; - - axis = Joy2Axis(AXISTURN); - if (gamepadjoystickmove && axis != 0) - { - turnright = turnright || (axis > 0); - turnleft = turnleft || (axis < 0); - } - forward = side = 0; - - // use two stage accelerative turning - // on the keyboard and joystick - if (turnleft || turnright) - turnheld += realtics; - else - turnheld = 0; - - if (turnheld < SLOWTURNTICS) - tspeed = 2; // slow turn - else - tspeed = speed; - - // let movement keys cancel each other out - if (cv_analog2.value) // Analog - { - if (turnright) - cmd->angleturn = (INT16)(cmd->angleturn - angleturn[tspeed]); - if (turnleft) - cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); - } - if (cv_analog2.value || twodlevel - || (player->mo && (player->mo->flags2 & MF2_TWOD)) - || player->climbing - || (player->pflags & PF_NIGHTSMODE) - || (player->pflags & PF_SLIDING) - || (player->pflags & PF_FORCESTRAFE)) // Analog - forcestrafe = true; - if (forcestrafe) // Analog - { - if (turnright) - side += sidemove[speed]; - if (turnleft) - side -= sidemove[speed]; - - if (analogjoystickmove && axis != 0) - { - // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); - } - } - else - { - if (turnright) - cmd->angleturn = (INT16)(cmd->angleturn - angleturn[tspeed]); - else if (turnleft) - cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); - - if (analogjoystickmove && axis != 0) - { - // JOYAXISRANGE should be 1023 (divide by 1024) - cmd->angleturn = (INT16)(cmd->angleturn - ((axis * angleturn[1]) >> 10)); // ANALOG! - } - } - - /* - axis = Joy2Axis(AXISSTRAFE); - if (gamepadjoystickmove && axis != 0) - { - if (axis < 0) - side += sidemove[speed]; - else if (axis > 0) - side -= sidemove[speed]; - } - else if (analogjoystickmove && axis != 0) - { - // JOYAXISRANGE is supposed to be 1023 (divide by 1024) - side += ((axis * sidemove[1]) >> 10); - } - */ - - // forward with key or button - if (PLAYER2INPUTDOWN(gc_accelerate) || player->kartstuff[k_mushroomtimer]) - { - cmd->buttons |= BT_ACCELERATE; - forward = forwardmove[1]; - } - if (PLAYER2INPUTDOWN(gc_brake)) - { - cmd->buttons |= BT_BRAKE; - forward -= forwardmove[0]; - } - // forward/backward is used for aiming. - axis = Joy2Axis(AXISMOVE); - if (PLAYER2INPUTDOWN(gc_aimforward) || (gamepadjoystickmove && axis < 0)) - cmd->buttons |= BT_FORWARD; - if (PLAYER2INPUTDOWN(gc_aimbackward) || (gamepadjoystickmove && axis > 0)) - cmd->buttons |= BT_BACKWARD; - - /* - if (analogjoystickmove && axis != 0) - forward -= ((axis * forwardmove[1]) >> 10); // ANALOG! - */ - - // some people strafe left & right with mouse buttons - // those people are (still) weird - if (PLAYER2INPUTDOWN(gc_straferight)) - side += sidemove[speed]; - if (PLAYER2INPUTDOWN(gc_strafeleft)) - side -= sidemove[speed]; - - /* // SRB2kart - these aren't used in kart - if (PLAYER2INPUTDOWN(gc_weaponnext)) - cmd->buttons |= BT_WEAPONNEXT; // Next Weapon - if (PLAYER2INPUTDOWN(gc_weaponprev)) - cmd->buttons |= BT_WEAPONPREV; // Previous Weapon - */ - - //use the four avaliable bits to determine the weapon. - cmd->buttons &= ~BT_WEAPONMASK; - for (i = 0; i < NUM_WEAPONS; ++i) - if (PLAYER2INPUTDOWN(gc_wepslot1 + i)) - { - cmd->buttons |= (UINT16)(i + 1); - break; - } - - // fire with any button/key - axis = Joy2Axis(AXISFIRE); - if (PLAYER2INPUTDOWN(gc_fire) || (cv_usejoystick2.value && axis > 0)) - cmd->buttons |= BT_ATTACK; - - // fire normal with any button/key - /* - axis = Joy2Axis(AXISFIRENORMAL); - if (PLAYER2INPUTDOWN(gc_accelerate) || (cv_usejoystick2.value && axis > 0)) - cmd->buttons |= BT_ACCELERATE; - */ - - if (PLAYER2INPUTDOWN(gc_spectate)) - cmd->buttons |= BT_SPECTATE; - - // Lua scriptable buttons - if (PLAYER2INPUTDOWN(gc_custom1)) - cmd->buttons |= BT_CUSTOM1; - if (PLAYER2INPUTDOWN(gc_custom2)) - cmd->buttons |= BT_CUSTOM2; - if (PLAYER2INPUTDOWN(gc_custom3)) - cmd->buttons |= BT_CUSTOM3; - - // use with any button/key - if (PLAYER2INPUTDOWN(gc_brake)) - cmd->buttons |= BT_BRAKE; - - // Camera Controls - if (cv_debug || cv_analog2.value || player->pflags & PF_NIGHTSMODE) - { - if (PLAYER2INPUTDOWN(gc_aimforward)) - cmd->buttons |= BT_FORWARD; - if (PLAYER2INPUTDOWN(gc_aimbackward)) - cmd->buttons |= BT_BACKWARD; - } - - if (PLAYER2INPUTDOWN(gc_lookback)) - { - if (camera2.chase && !resetdown) - P_ResetCamera(&players[secondarydisplayplayer], &camera2); // TODO: Replace with a camflip - resetdown = true; - } - else - resetdown = false; - - // jump button - if (PLAYER2INPUTDOWN(gc_jump)) - cmd->buttons |= BT_JUMP; - - // player aiming shit, ahhhh... - { - INT32 player_invert = cv_invertmouse2.value ? -1 : 1; - INT32 screen_invert = - (player->mo && (player->mo->eflags & MFE_VERTICALFLIP) - && (!camera2.chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted - ? -1 : 1; // set to -1 or 1 to multiply - - // mouse look stuff (mouse look is not the same as mouse aim) - if (mouseaiming) - { - keyboard_look = false; - - // looking up/down - localaiming2 += (mlook2y<<19)*player_invert*screen_invert; - } - - axis = Joy2Axis(AXISLOOK); - if (analogjoystickmove && axis != 0 && cv_lookaxis2.value != 0) - localaiming2 += (axis<<16) * screen_invert; - - // spring back if not using keyboard neither mouselookin' - if (!keyboard_look && cv_lookaxis2.value == 0 && !mouseaiming) - localaiming2 = 0; - - if (PLAYER2INPUTDOWN(gc_lookup) || (gamepadjoystickmove && axis < 0)) - { - localaiming2 += KB_LOOKSPEED * screen_invert; - keyboard_look = true; - } - else if (PLAYER2INPUTDOWN(gc_lookdown) || (gamepadjoystickmove && axis > 0)) - { - localaiming2 -= KB_LOOKSPEED * screen_invert; - keyboard_look = true; - } - else if (PLAYER2INPUTDOWN(gc_centerview)) - localaiming2 = 0; - - // accept no mlook for network games - if (!cv_allowmlook.value) - localaiming2 = 0; - - cmd->aiming = G_ClipAimingPitch(&localaiming2); - } - - if (!mouseaiming && cv_mousemove2.value) - forward += mouse2y; - - if (cv_analog2.value || player->climbing - || (player->pflags & PF_SLIDING)) // Analog for mouse - side += mouse2x*2; - else - cmd->angleturn = (INT16)(cmd->angleturn - (mouse2x*8)); - - mouse2x = mouse2y = mlook2y = 0; - - if (forward > MAXPLMOVE) - forward = MAXPLMOVE; - else if (forward < -MAXPLMOVE) - forward = -MAXPLMOVE; - if (side > MAXPLMOVE) - side = MAXPLMOVE; - else if (side < -MAXPLMOVE) - side = -MAXPLMOVE; - - // No additional acceleration when moving forward/backward and strafing simultaneously. - // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this. - if (!forcestrafe && forward && side) - { - forward = FixedMul(forward, 3*FRACUNIT/4); - side = FixedMul(side, 3*FRACUNIT/4); - } - - //Silly hack to make 2d mode *somewhat* playable with no chasecam. - if ((twodlevel || (player->mo && player->mo->flags2 & MF2_TWOD)) && !camera2.chase) - { - INT32 temp = forward; - forward = side; - side = temp; - } - - cmd->forwardmove = (SINT8)(cmd->forwardmove + forward); - cmd->sidemove = (SINT8)(cmd->sidemove + side); - - //{ SRB2kart - Drift support - axis = Joy2Axis(AXISTURN); - - if (cmd->angleturn > 0) // Drifting to the left - cmd->buttons |= BT_DRIFTLEFT; - else - cmd->buttons &= ~BT_DRIFTLEFT; - - if (cmd->angleturn < 0) // Drifting to the right - cmd->buttons |= BT_DRIFTRIGHT; - else - cmd->buttons &= ~BT_DRIFTRIGHT; - //} - - if (player->bot == 1) { + if (ssplayer == 2 && player->bot == 1) { if (!player->powers[pw_tailsfly] && (cmd->forwardmove || cmd->sidemove || cmd->buttons)) { player->bot = 2; // A player-controlled bot. Returns to AI when it respawns. @@ -1795,7 +1568,7 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) } } - if (cv_analog2.value) { + if (analog) { cmd->angleturn = (INT16)(thiscam->angle >> 16); if (player->awayviewtics) cmd->angleturn = (INT16)(player->awayviewmobj->angle >> 16); @@ -1813,10 +1586,44 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) // SRB2kart - no additional angle if not moving if ((player->mo && player->speed > 0) || (leveltime > 140 && (cmd->buttons & BT_ACCELERATE) && (cmd->buttons & BT_BRAKE))) - localangle2 += (cmd->angleturn<<16); + lang += (cmd->angleturn<<16); - cmd->angleturn = (INT16)(localangle2 >> 16); + cmd->angleturn = (INT16)(lang >> 16); } + + if (ssplayer == 2) + { + localangle2 = lang; + localaiming2 = laim; + keyboard_look2 = kbl; + turnheld2 = th; + } + else if (ssplayer == 3) + { + localangle3 = lang; + localaiming3 = laim; + keyboard_look3 = kbl; + turnheld3 = th; + } + else if (ssplayer == 4) + { + localangle4 = lang; + localaiming4 = laim; + keyboard_look4 = kbl; + turnheld4 = th; + } + else + { + localangle = lang; + localaiming = laim; + keyboard_look = kbl; + turnheld = th; + } + + //Reset away view if a command is given. + if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) + && displayplayer != consoleplayer && ssplayer == 1) + displayplayer = consoleplayer; } // User has designated that they want @@ -1978,8 +1785,12 @@ void G_DoLoadLevel(boolean resetplayer) P_FindEmerald(); displayplayer = consoleplayer; // view the guy you are playing - if (!splitscreen && !botingame) + if (!(splitscreen || splitscreen3 || splitscreen4) && !botingame) secondarydisplayplayer = consoleplayer; + if (!(splitscreen3 || splitscreen4)) + thirddisplayplayer = consoleplayer; + if (!splitscreen4) + fourthdisplayplayer = consoleplayer; gameaction = ga_nothing; #ifdef PARANOIA @@ -2232,6 +2043,11 @@ boolean G_Responder(event_t *ev) case ev_joystick2: return true; // eat events + case ev_joystick3: + return true; // eat events + + case ev_joystick4: + return true; // eat events default: break; @@ -2752,13 +2568,19 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) { if (nummapthings) { - if (playernum == consoleplayer || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) || (splitscreen4 && playernum == fourthdisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); spawnpoint = &mapthings[0]; } else { - if (playernum == consoleplayer || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) || (splitscreen4 && playernum == fourthdisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); //P_MovePlayerToSpawn handles this fine if the spawnpoint is NULL. } @@ -2777,7 +2599,10 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (!numredctfstarts && !numbluectfstarts) //why even bother, eh? { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("No CTF starts in this map!\n")); return NULL; } @@ -2786,7 +2611,10 @@ mapthing_t *G_FindCTFStart(INT32 playernum) { if (!numredctfstarts) { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("No Red Team starts in this map!\n")); return NULL; } @@ -2798,7 +2626,10 @@ mapthing_t *G_FindCTFStart(INT32 playernum) return redctfstarts[i]; } - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Red Team starts!\n")); return NULL; } @@ -2806,7 +2637,10 @@ mapthing_t *G_FindCTFStart(INT32 playernum) { if (!numbluectfstarts) { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("No Blue Team starts in this map!\n")); return NULL; } @@ -2817,7 +2651,10 @@ mapthing_t *G_FindCTFStart(INT32 playernum) if (G_CheckSpot(playernum, bluectfstarts[i])) return bluectfstarts[i]; } - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Blue Team starts!\n")); return NULL; } @@ -2837,12 +2674,18 @@ mapthing_t *G_FindMatchStart(INT32 playernum) if (G_CheckSpot(playernum, deathmatchstarts[i])) return deathmatchstarts[i]; } - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n")); return NULL; } - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n")); return NULL; } @@ -2860,7 +2703,10 @@ mapthing_t *G_FindCoopStart(INT32 playernum) return playerstarts[0]; } - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + if (playernum == consoleplayer + || ((splitscreen || splitscreen3 || splitscreen4) && playernum == secondarydisplayplayer) + || ((splitscreen3 || splitscreen4) && playernum == thirddisplayplayer) + || (splitscreen4 && playernum == fourthdisplayplayer)) CONS_Alert(CONS_WARNING, M_GetText("No Co-op starts in this map!\n")); return NULL; } @@ -3925,7 +3771,7 @@ void G_SaveGame(UINT32 savegameslot) // Can be called by the startup code or the menu task, // consoleplayer, displayplayer, playeringame[] should be set. // -void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS) +void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { UINT8 color = 0; paused = false; @@ -3944,9 +3790,27 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b botcolor = savedata.botcolor; botingame = (botskin != 0); } - else if (splitscreen != SSSG) + else if (!splitscreen4 && ssplayers == 4) { - splitscreen = SSSG; + splitscreen4 = true; + splitscreen = splitscreen3 = false; + SplitScreen_OnChange(); + } + else if (!splitscreen3 && ssplayers == 3) + { + splitscreen3 = true; + splitscreen = splitscreen4 = false; + SplitScreen_OnChange(); + } + else if (!splitscreen && ssplayers == 2) + { + splitscreen = true; + splitscreen3 = splitscreen4 = false; + SplitScreen_OnChange(); + } + else if ((splitscreen || splitscreen3 || splitscreen4) && ssplayers == 1) + { + splitscreen = splitscreen3 = splitscreen4 = false; SplitScreen_OnChange(); } diff --git a/src/g_game.h b/src/g_game.h index 9369665c..ec8a1817 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -69,8 +69,7 @@ extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_last, cv_ghost_ // build an internal map name MAPxx from map number const char *G_BuildMapName(INT32 map); -void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics); -void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics); +void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer); // copy ticcmd_t to and fro the normal way ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n); @@ -82,7 +81,7 @@ INT16 G_ClipAimingPitch(INT32 *aiming); INT16 G_SoftwareClipAimingPitch(INT32 *aiming); extern angle_t localangle, localangle2, localangle3, localangle4; -extern INT32 localaiming, localaiming2; // should be an angle_t but signed +extern INT32 localaiming, localaiming2, localaiming3, localaiming4; // should be an angle_t but signed // // GAME @@ -103,7 +102,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, but a warp test can start elsewhere void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, - boolean SSSG, boolean FLS); + UINT8 ssplayers, boolean FLS); void G_DoLoadLevel(boolean resetplayer); void G_DeferedPlayDemo(const char *demo); diff --git a/src/g_input.c b/src/g_input.c index 0b2573a9..fca940cb 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -174,6 +174,18 @@ void G_MapEventsToControls(event_t *ev) flag = G_CheckDoubleClick(gamekeydown[KEY_2JOY1+i], &joy2dclicks[i]); gamekeydown[KEY_DBL2JOY1+i] = flag; } + + for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_3JOY1+i], &joy3dclicks[i]); + gamekeydown[KEY_DBL3JOY1+i] = flag; + } + + for (i = 0; i < JOYBUTTONS + JOYHATS*4; i++) + { + flag = G_CheckDoubleClick(gamekeydown[KEY_4JOY1+i], &joy4dclicks[i]); + gamekeydown[KEY_DBL4JOY1+i] = flag; + } } // @@ -970,6 +982,602 @@ static keyname_t keynames[] = #endif #endif +#ifdef DC + {KEY_3JOY1+0, "TRD_JOYC"}, + {KEY_3JOY1+1, "TRD_JOYB"}, + {KEY_3JOY1+2, "TRD_JOYA"}, + {KEY_3JOY1+3, "TRD_JOYS"}, + {KEY_3JOY1+4, "TRD_JOYZ"}, + {KEY_3JOY1+5, "TRD_JOYY"}, + {KEY_3JOY1+6, "TRD_JOYX"}, + {KEY_3JOY1+7, "TRD_JOYD"}, +#elif defined (_XBOX) + {KEY_3JOY1+0, "TRD_JOYA"}, + {KEY_3JOY1+1, "TRD_JOYB"}, + {KEY_3JOY1+2, "TRD_JOYX"}, + {KEY_3JOY1+3, "TRD_JOYY"}, + {KEY_3JOY1+4, "TRD_JOYG"}, + {KEY_3JOY1+5, "TRD_JOYW"}, + {KEY_3JOY1+6, "TRD_JOYL"}, + {KEY_3JOY1+7, "TRD_JOYR"}, + {KEY_3JOY1+8, "TRD_JOYS"}, + {KEY_3JOY1+9, "TRD_JOYN"}, + {KEY_3JOY1+10,"TRD_JOYW"}, + {KEY_3JOY1+11,"TRD_JOYE"}, +#define NOMOREJOYBTN_2S +#elif defined (_PSP) + {KEY_3JOY1+0, "TRD_TRIANGLE"}, + {KEY_3JOY1+1, "TRD_CIRCLE" }, + {KEY_3JOY1+2, "TRD_CROSS" }, + {KEY_3JOY1+3, "TRD_SQUARE" }, + {KEY_3JOY1+4, "TRD_LTRIGGER"}, + {KEY_3JOY1+5, "TRD_RTRIGGER"}, + {KEY_3JOY1+6, "TRD_SELECT" }, + {KEY_3JOY1+7, "TRD_START" }, + {KEY_3JOY1+8, "TRD_HOME" }, + {KEY_3JOY1+9, "TRD_HOLD" }, +#define NOMOREJOYBTN_2S +#elif defined (WMINPUT) + {KEY_3JOY1+0, "TRD_JOYB"}, + {KEY_3JOY1+1, "TRD_JOYA"}, + {KEY_3JOY1+2, "TRD_JOYUP"}, + {KEY_3JOY1+3, "TRD_JOYDOWN"}, + {KEY_3JOY1+4, "TRD_JOYLEFT"}, + {KEY_3JOY1+5, "TRD_JOYRIGHT"}, + {KEY_3JOY1+6, "TRD_JOYAA"}, + {KEY_3JOY1+7, "TRD_JOYBB"}, + {KEY_3JOY1+8, "TRD_JOYCC"}, + {KEY_3JOY1+9, "TRD_JOYXX"}, + {KEY_3JOY1+10, "TRD_JOYYY"}, + {KEY_3JOY1+11, "TRD_JOYZZ"}, + {KEY_3JOY1+12, "TRD_JOYL"}, + {KEY_3JOY1+13, "TRD_JOYR"}, + {KEY_3JOY1+14, "TRD_JOYZL"}, + {KEY_3JOY1+15, "TRD_JOYZR"}, + {KEY_3JOY1+16, "TRD_JOYSELECT"}, + {KEY_3JOY1+17, "TRD_JOYSTART"}, + {KEY_3JOY1+18, "TRD_JOYHOME"}, + {KEY_3JOY1+19, "TRD_JOYMINUS"}, + {KEY_3JOY1+20, "TRD_JOYPLUS"}, + {KEY_3JOY1+21, "TRD_JOY_1"}, + {KEY_3JOY1+22, "TRD_JOY_2"}, + {KEY_3JOY1+23, "TRD_JOY24"}, + {KEY_3JOY1+24, "TRD_JOY25"}, + {KEY_3JOY1+25, "TRD_JOY26"}, + {KEY_3JOY1+26, "TRD_JOY27"}, + {KEY_3JOY1+27, "TRD_JOY28"}, + {KEY_3JOY1+28, "TRD_JOY29"}, + {KEY_3JOY1+29, "TRD_JOY30"}, + {KEY_3JOY1+30, "TRD_JOY31"}, + {KEY_3JOY1+31, "TRD_JOY32"}, +#define NOMOREJOYBTN_2S +#elif defined (_WII) + {KEY_3JOY1+0, "TRD_JOYA"}, + {KEY_3JOY1+1, "TRD_JOYB"}, + {KEY_3JOY1+2, "TRD_JOY1"}, + {KEY_3JOY1+3, "TRD_JOY2"}, + {KEY_3JOY1+4, "TRD_JOYMINUS"}, + {KEY_3JOY1+5, "TRD_JOYPLUS"}, + {KEY_3JOY1+6, "TRD_JOYHOME"}, + {KEY_3JOY1+7, "TRD_JOYZ"}, + {KEY_3JOY1+8, "TRD_JOYC"}, + {KEY_3JOY1+9, "TRD_JOYA_CC"}, + {KEY_3JOY1+10, "TRD_JOYB_CC"}, + {KEY_3JOY1+11, "TRD_JOYX"}, + {KEY_3JOY1+12, "TRD_JOYY"}, + {KEY_3JOY1+13, "TRD_JOYL"}, + {KEY_3JOY1+14, "TRD_JOYR"}, + {KEY_3JOY1+15, "TRD_JOYZL"}, + {KEY_3JOY1+16, "TRD_JOYZR"}, + {KEY_3JOY1+17, "TRD_JOYMINUS_CC"}, + {KEY_3JOY1+18, "TRD_JOYHPLUS_CC"}, + {KEY_3JOY1+19, "TRD_JOYMHOME_CC"}, +#define NOMOREJOYBTN_2S +#else + {KEY_3JOY1+0, "TRD_JOY1"}, + {KEY_3JOY1+1, "TRD_JOY2"}, + {KEY_3JOY1+2, "TRD_JOY3"}, + {KEY_3JOY1+3, "TRD_JOY4"}, + {KEY_3JOY1+4, "TRD_JOY5"}, + {KEY_3JOY1+5, "TRD_JOY6"}, + {KEY_3JOY1+6, "TRD_JOY7"}, + {KEY_3JOY1+7, "TRD_JOY8"}, +#endif +#if !defined (_arch_dreamcast) && !defined (NOMOREJOYBTN_2S) + // we use up to 32 buttons in DirectInput + {KEY_3JOY1+8, "TRD_JOY9"}, + {KEY_3JOY1+9, "TRD_JOY10"}, + {KEY_3JOY1+10, "TRD_JOY11"}, + {KEY_3JOY1+11, "TRD_JOY12"}, + {KEY_3JOY1+12, "TRD_JOY13"}, + {KEY_3JOY1+13, "TRD_JOY14"}, + {KEY_3JOY1+14, "TRD_JOY15"}, + {KEY_3JOY1+15, "TRD_JOY16"}, + {KEY_3JOY1+16, "TRD_JOY17"}, + {KEY_3JOY1+17, "TRD_JOY18"}, + {KEY_3JOY1+18, "TRD_JOY19"}, + {KEY_3JOY1+19, "TRD_JOY20"}, + {KEY_3JOY1+20, "TRD_JOY21"}, + {KEY_3JOY1+21, "TRD_JOY22"}, + {KEY_3JOY1+22, "TRD_JOY23"}, + {KEY_3JOY1+23, "TRD_JOY24"}, + {KEY_3JOY1+24, "TRD_JOY25"}, + {KEY_3JOY1+25, "TRD_JOY26"}, + {KEY_3JOY1+26, "TRD_JOY27"}, + {KEY_3JOY1+27, "TRD_JOY28"}, + {KEY_3JOY1+28, "TRD_JOY29"}, + {KEY_3JOY1+29, "TRD_JOY30"}, + {KEY_3JOY1+30, "TRD_JOY31"}, + {KEY_3JOY1+31, "TRD_JOY32"}, +#endif + // the DOS version uses Allegro's joystick support + {KEY_3HAT1+0, "TRD_HATUP"}, + {KEY_3HAT1+1, "TRD_HATDOWN"}, + {KEY_3HAT1+2, "TRD_HATLEFT"}, + {KEY_3HAT1+3, "TRD_HATRIGHT"}, +#if !defined (_XBOX) && !defined (_PSP) && !defined (_WII) + {KEY_3HAT1+4, "TRD_HATUP2"}, + {KEY_3HAT1+5, "TRD_HATDOWN2"}, + {KEY_3HAT1+6, "TRD_HATLEFT2"}, + {KEY_3HAT1+7, "TRD_HATRIGHT2"}, +#ifndef _arch_dreamcast + {KEY_3HAT1+8, "TRD_HATUP3"}, + {KEY_3HAT1+9, "TRD_HATDOWN3"}, + {KEY_3HAT1+10, "TRD_HATLEFT3"}, + {KEY_3HAT1+11, "TRD_HATRIGHT3"}, + {KEY_3HAT1+12, "TRD_HATUP4"}, + {KEY_3HAT1+13, "TRD_HATDOWN4"}, + {KEY_3HAT1+14, "TRD_HATLEFT4"}, + {KEY_3HAT1+15, "TRD_HATRIGHT4"}, +#endif +#endif + +#ifdef DC + {KEY_DBL3JOY1+0, "DBLTRD_JOYC"}, + {KEY_DBL3JOY1+1, "DBLTRD_JOYB"}, + {KEY_DBL3JOY1+2, "DBLTRD_JOYA"}, + {KEY_DBL3JOY1+3, "DBLTRD_JOYS"}, + {KEY_DBL3JOY1+4, "DBLTRD_JOYZ"}, + {KEY_DBL3JOY1+5, "DBLTRD_JOYY"}, + {KEY_DBL3JOY1+6, "DBLTRD_JOYX"}, + {KEY_DBL3JOY1+7, "DBLTRD_JOYD"}, +#elif defined (_XBOX) + {KEY_DBL3JOY1+0, "DBLTRD_JOYA"}, + {KEY_DBL3JOY1+1, "DBLTRD_JOYB"}, + {KEY_DBL3JOY1+2, "DBLTRD_JOYX"}, + {KEY_DBL3JOY1+3, "DBLTRD_JOYY"}, + {KEY_DBL3JOY1+4, "DBLTRD_JOYG"}, + {KEY_DBL3JOY1+5, "DBLTRD_JOYW"}, + {KEY_DBL3JOY1+6, "DBLTRD_JOYL"}, + {KEY_DBL3JOY1+7, "DBLTRD_JOYR"}, + {KEY_DBL3JOY1+8, "DBLTRD_JOYS"}, + {KEY_DBL3JOY1+9, "DBLTRD_JOYN"}, + {KEY_DBL3JOY1+10,"DBLTRD_JOYW"}, + {KEY_DBL3JOY1+11,"DBLTRD_JOYE"}, +#define NOMOREJOYBTN_2DBL +#elif defined (_PSP) + {KEY_DBL3JOY1+0, "DBLTRD_TRIANGLE"}, + {KEY_DBL3JOY1+1, "DBLTRD_CIRCLE" }, + {KEY_DBL3JOY1+2, "DBLTRD_CROSS" }, + {KEY_DBL3JOY1+3, "DBLTRD_SQUARE" }, + {KEY_DBL3JOY1+4, "DBLTRD_LTRIGGER"}, + {KEY_DBL3JOY1+5, "DBLTRD_RTRIGGER"}, + {KEY_DBL3JOY1+6, "DBLTRD_SELECT" }, + {KEY_DBL3JOY1+7, "DBLTRD_START" }, + {KEY_DBL3JOY1+8, "DBLTRD_HOME" }, + {KEY_DBL3JOY1+9, "DBLTRD_HOLD" }, +#define NOMOREJOYBTN_2DBL +#elif defined (WMINPUT) + {KEY_DBL3JOY1+0, "DBLTRD_JOYB"}, + {KEY_DBL3JOY1+1, "DBLTRD_JOYA"}, + {KEY_DBL3JOY1+2, "DBLTRD_JOYUP"}, + {KEY_DBL3JOY1+3, "DBLTRD_JOYDOWN"}, + {KEY_DBL3JOY1+4, "DBLTRD_JOYLEFT"}, + {KEY_DBL3JOY1+5, "DBLTRD_JOYRIGHT"}, + {KEY_DBL3JOY1+6, "DBLTRD_JOYAA"}, + {KEY_DBL3JOY1+7, "DBLTRD_JOYBB"}, + {KEY_DBL3JOY1+8, "DBLTRD_JOYCC"}, + {KEY_DBL3JOY1+9, "DBLTRD_JOYXX"}, + {KEY_DBL3JOY1+10, "DBLTRD_JOYYY"}, + {KEY_DBL3JOY1+11, "DBLTRD_JOYZZ"}, + {KEY_DBL3JOY1+12, "DBLTRD_JOYL"}, + {KEY_DBL3JOY1+13, "DBLTRD_JOYR"}, + {KEY_DBL3JOY1+14, "DBLTRD_JOYZL"}, + {KEY_DBL3JOY1+15, "DBLTRD_JOYZR"}, + {KEY_DBL3JOY1+16, "DBLTRD_JOYSELECT"}, + {KEY_DBL3JOY1+17, "DBLTRD_JOYSTART"}, + {KEY_DBL3JOY1+18, "DBLTRD_JOYHOME"}, + {KEY_DBL3JOY1+19, "DBLTRD_JOYMINUS"}, + {KEY_DBL3JOY1+20, "DBLTRD_JOYPLUS"}, + {KEY_DBL3JOY1+21, "DBLTRD_JOY_1"}, + {KEY_DBL3JOY1+22, "DBLTRD_JOY_2"}, + {KEY_DBL3JOY1+23, "DBLTRD_JOY24"}, + {KEY_DBL3JOY1+24, "DBLTRD_JOY25"}, + {KEY_DBL3JOY1+25, "DBLTRD_JOY26"}, + {KEY_DBL3JOY1+26, "DBLTRD_JOY27"}, + {KEY_DBL3JOY1+27, "DBLTRD_JOY28"}, + {KEY_DBL3JOY1+28, "DBLTRD_JOY29"}, + {KEY_DBL3JOY1+29, "DBLTRD_JOY30"}, + {KEY_DBL3JOY1+30, "DBLTRD_JOY31"}, + {KEY_DBL3JOY1+31, "DBLTRD_JOY32"}, +#define NOMOREJOYBTN_2SDBL +#elif defined (_WII) + {KEY_DBL3JOY1+0, "DBLTRD_JOYA"}, + {KEY_DBL3JOY1+1, "DBLTRD_JOYB"}, + {KEY_DBL3JOY1+2, "DBLTRD_JOY1"}, + {KEY_DBL3JOY1+3, "DBLTRD_JOY2"}, + {KEY_DBL3JOY1+4, "DBLTRD_JOYMINUS"}, + {KEY_DBL3JOY1+5, "DBLTRD_JOYPLUS"}, + {KEY_DBL3JOY1+6, "DBLTRD_JOYHOME"}, + {KEY_DBL3JOY1+7, "DBLTRD_JOYZ"}, + {KEY_DBL3JOY1+8, "DBLTRD_JOYC"}, + {KEY_DBL3JOY1+9, "DBLTRD_JOYA_CC"}, + {KEY_DBL3JOY1+10, "DBLTRD_JOYB_CC"}, + {KEY_DBL3JOY1+11, "DBLTRD_JOYX"}, + {KEY_DBL3JOY1+12, "DBLTRD_JOYY"}, + {KEY_DBL3JOY1+13, "DBLTRD_JOYL"}, + {KEY_DBL3JOY1+14, "DBLTRD_JOYR"}, + {KEY_DBL3JOY1+15, "DBLTRD_JOYZL"}, + {KEY_DBL3JOY1+16, "DBLTRD_JOYZR"}, + {KEY_DBL3JOY1+17, "DBLTRD_JOYMINUS_CC"}, + {KEY_DBL3JOY1+18, "DBLTRD_JOYHPLUS_CC"}, + {KEY_DBL3JOY1+19, "DBLTRD_JOYMHOME_CC"}, +#define NOMOREJOYBTN_2DBL +#else + {KEY_DBL3JOY1+0, "DBLTRD_JOY1"}, + {KEY_DBL3JOY1+1, "DBLTRD_JOY2"}, + {KEY_DBL3JOY1+2, "DBLTRD_JOY3"}, + {KEY_DBL3JOY1+3, "DBLTRD_JOY4"}, + {KEY_DBL3JOY1+4, "DBLTRD_JOY5"}, + {KEY_DBL3JOY1+5, "DBLTRD_JOY6"}, + {KEY_DBL3JOY1+6, "DBLTRD_JOY7"}, + {KEY_DBL3JOY1+7, "DBLTRD_JOY8"}, +#endif +#if !defined (_arch_dreamcast) && !defined (NOMOREJOYBTN_2DBL) + {KEY_DBL3JOY1+8, "DBLTRD_JOY9"}, + {KEY_DBL3JOY1+9, "DBLTRD_JOY10"}, + {KEY_DBL3JOY1+10, "DBLTRD_JOY11"}, + {KEY_DBL3JOY1+11, "DBLTRD_JOY12"}, + {KEY_DBL3JOY1+12, "DBLTRD_JOY13"}, + {KEY_DBL3JOY1+13, "DBLTRD_JOY14"}, + {KEY_DBL3JOY1+14, "DBLTRD_JOY15"}, + {KEY_DBL3JOY1+15, "DBLTRD_JOY16"}, + {KEY_DBL3JOY1+16, "DBLTRD_JOY17"}, + {KEY_DBL3JOY1+17, "DBLTRD_JOY18"}, + {KEY_DBL3JOY1+18, "DBLTRD_JOY19"}, + {KEY_DBL3JOY1+19, "DBLTRD_JOY20"}, + {KEY_DBL3JOY1+20, "DBLTRD_JOY21"}, + {KEY_DBL3JOY1+21, "DBLTRD_JOY22"}, + {KEY_DBL3JOY1+22, "DBLTRD_JOY23"}, + {KEY_DBL3JOY1+23, "DBLTRD_JOY24"}, + {KEY_DBL3JOY1+24, "DBLTRD_JOY25"}, + {KEY_DBL3JOY1+25, "DBLTRD_JOY26"}, + {KEY_DBL3JOY1+26, "DBLTRD_JOY27"}, + {KEY_DBL3JOY1+27, "DBLTRD_JOY28"}, + {KEY_DBL3JOY1+28, "DBLTRD_JOY29"}, + {KEY_DBL3JOY1+29, "DBLTRD_JOY30"}, + {KEY_DBL3JOY1+30, "DBLTRD_JOY31"}, + {KEY_DBL3JOY1+31, "DBLTRD_JOY32"}, +#endif + {KEY_DBL3HAT1+0, "DBLTRD_HATUP"}, + {KEY_DBL3HAT1+1, "DBLTRD_HATDOWN"}, + {KEY_DBL3HAT1+2, "DBLTRD_HATLEFT"}, + {KEY_DBL3HAT1+3, "DBLTRD_HATRIGHT"}, +#if !defined (_XBOX) && !defined (_PSP) && !defined (_WII) + {KEY_DBL3HAT1+4, "DBLTRD_HATUP2"}, + {KEY_DBL3HAT1+5, "DBLTRD_HATDOWN2"}, + {KEY_DBL3HAT1+6, "DBLTRD_HATLEFT2"}, + {KEY_DBL3HAT1+7, "DBLTRD_HATRIGHT2"}, +#ifndef _arch_dreamcast + {KEY_DBL3HAT1+8, "DBLTRD_HATUP3"}, + {KEY_DBL3HAT1+9, "DBLTRD_HATDOWN3"}, + {KEY_DBL3HAT1+10, "DBLTRD_HATLEFT3"}, + {KEY_DBL3HAT1+11, "DBLTRD_HATRIGHT3"}, + {KEY_DBL3HAT1+12, "DBLTRD_HATUP4"}, + {KEY_DBL3HAT1+13, "DBLTRD_HATDOWN4"}, + {KEY_DBL3HAT1+14, "DBLTRD_HATLEFT4"}, + {KEY_DBL3HAT1+15, "DBLTRD_HATRIGHT4"}, +#endif +#endif + +#ifdef DC + {KEY_4JOY1+0, "FOR_JOYC"}, + {KEY_4JOY1+1, "FOR_JOYB"}, + {KEY_4JOY1+2, "FOR_JOYA"}, + {KEY_4JOY1+3, "FOR_JOYS"}, + {KEY_4JOY1+4, "FOR_JOYZ"}, + {KEY_4JOY1+5, "FOR_JOYY"}, + {KEY_4JOY1+6, "FOR_JOYX"}, + {KEY_4JOY1+7, "FOR_JOYD"}, +#elif defined (_XBOX) + {KEY_4JOY1+0, "FOR_JOYA"}, + {KEY_4JOY1+1, "FOR_JOYB"}, + {KEY_4JOY1+2, "FOR_JOYX"}, + {KEY_4JOY1+3, "FOR_JOYY"}, + {KEY_4JOY1+4, "FOR_JOYG"}, + {KEY_4JOY1+5, "FOR_JOYW"}, + {KEY_4JOY1+6, "FOR_JOYL"}, + {KEY_4JOY1+7, "FOR_JOYR"}, + {KEY_4JOY1+8, "FOR_JOYS"}, + {KEY_4JOY1+9, "FOR_JOYN"}, + {KEY_4JOY1+10,"FOR_JOYW"}, + {KEY_4JOY1+11,"FOR_JOYE"}, +#define NOMOREJOYBTN_2S +#elif defined (_PSP) + {KEY_4JOY1+0, "FOR_TRIANGLE"}, + {KEY_4JOY1+1, "FOR_CIRCLE" }, + {KEY_4JOY1+2, "FOR_CROSS" }, + {KEY_4JOY1+3, "FOR_SQUARE" }, + {KEY_4JOY1+4, "FOR_LTRIGGER"}, + {KEY_4JOY1+5, "FOR_RTRIGGER"}, + {KEY_4JOY1+6, "FOR_SELECT" }, + {KEY_4JOY1+7, "FOR_START" }, + {KEY_4JOY1+8, "FOR_HOME" }, + {KEY_4JOY1+9, "FOR_HOLD" }, +#define NOMOREJOYBTN_2S +#elif defined (WMINPUT) + {KEY_4JOY1+0, "FOR_JOYB"}, + {KEY_4JOY1+1, "FOR_JOYA"}, + {KEY_4JOY1+2, "FOR_JOYUP"}, + {KEY_4JOY1+3, "FOR_JOYDOWN"}, + {KEY_4JOY1+4, "FOR_JOYLEFT"}, + {KEY_4JOY1+5, "FOR_JOYRIGHT"}, + {KEY_4JOY1+6, "FOR_JOYAA"}, + {KEY_4JOY1+7, "FOR_JOYBB"}, + {KEY_4JOY1+8, "FOR_JOYCC"}, + {KEY_4JOY1+9, "FOR_JOYXX"}, + {KEY_4JOY1+10, "FOR_JOYYY"}, + {KEY_4JOY1+11, "FOR_JOYZZ"}, + {KEY_4JOY1+12, "FOR_JOYL"}, + {KEY_4JOY1+13, "FOR_JOYR"}, + {KEY_4JOY1+14, "FOR_JOYZL"}, + {KEY_4JOY1+15, "FOR_JOYZR"}, + {KEY_4JOY1+16, "FOR_JOYSELECT"}, + {KEY_4JOY1+17, "FOR_JOYSTART"}, + {KEY_4JOY1+18, "FOR_JOYHOME"}, + {KEY_4JOY1+19, "FOR_JOYMINUS"}, + {KEY_4JOY1+20, "FOR_JOYPLUS"}, + {KEY_4JOY1+21, "FOR_JOY_1"}, + {KEY_4JOY1+22, "FOR_JOY_2"}, + {KEY_4JOY1+23, "FOR_JOY24"}, + {KEY_4JOY1+24, "FOR_JOY25"}, + {KEY_4JOY1+25, "FOR_JOY26"}, + {KEY_4JOY1+26, "FOR_JOY27"}, + {KEY_4JOY1+27, "FOR_JOY28"}, + {KEY_4JOY1+28, "FOR_JOY29"}, + {KEY_4JOY1+29, "FOR_JOY30"}, + {KEY_4JOY1+30, "FOR_JOY31"}, + {KEY_4JOY1+31, "FOR_JOY32"}, +#define NOMOREJOYBTN_2S +#elif defined (_WII) + {KEY_4JOY1+0, "FOR_JOYA"}, + {KEY_4JOY1+1, "FOR_JOYB"}, + {KEY_4JOY1+2, "FOR_JOY1"}, + {KEY_4JOY1+3, "FOR_JOY2"}, + {KEY_4JOY1+4, "FOR_JOYMINUS"}, + {KEY_4JOY1+5, "FOR_JOYPLUS"}, + {KEY_4JOY1+6, "FOR_JOYHOME"}, + {KEY_4JOY1+7, "FOR_JOYZ"}, + {KEY_4JOY1+8, "FOR_JOYC"}, + {KEY_4JOY1+9, "FOR_JOYA_CC"}, + {KEY_4JOY1+10, "FOR_JOYB_CC"}, + {KEY_4JOY1+11, "FOR_JOYX"}, + {KEY_4JOY1+12, "FOR_JOYY"}, + {KEY_4JOY1+13, "FOR_JOYL"}, + {KEY_4JOY1+14, "FOR_JOYR"}, + {KEY_4JOY1+15, "FOR_JOYZL"}, + {KEY_4JOY1+16, "FOR_JOYZR"}, + {KEY_4JOY1+17, "FOR_JOYMINUS_CC"}, + {KEY_4JOY1+18, "FOR_JOYHPLUS_CC"}, + {KEY_4JOY1+19, "FOR_JOYMHOME_CC"}, +#define NOMOREJOYBTN_2S +#else + {KEY_4JOY1+0, "FOR_JOY1"}, + {KEY_4JOY1+1, "FOR_JOY2"}, + {KEY_4JOY1+2, "FOR_JOY3"}, + {KEY_4JOY1+3, "FOR_JOY4"}, + {KEY_4JOY1+4, "FOR_JOY5"}, + {KEY_4JOY1+5, "FOR_JOY6"}, + {KEY_4JOY1+6, "FOR_JOY7"}, + {KEY_4JOY1+7, "FOR_JOY8"}, +#endif +#if !defined (_arch_dreamcast) && !defined (NOMOREJOYBTN_2S) + // we use up to 32 buttons in DirectInput + {KEY_4JOY1+8, "FOR_JOY9"}, + {KEY_4JOY1+9, "FOR_JOY10"}, + {KEY_4JOY1+10, "FOR_JOY11"}, + {KEY_4JOY1+11, "FOR_JOY12"}, + {KEY_4JOY1+12, "FOR_JOY13"}, + {KEY_4JOY1+13, "FOR_JOY14"}, + {KEY_4JOY1+14, "FOR_JOY15"}, + {KEY_4JOY1+15, "FOR_JOY16"}, + {KEY_4JOY1+16, "FOR_JOY17"}, + {KEY_4JOY1+17, "FOR_JOY18"}, + {KEY_4JOY1+18, "FOR_JOY19"}, + {KEY_4JOY1+19, "FOR_JOY20"}, + {KEY_4JOY1+20, "FOR_JOY21"}, + {KEY_4JOY1+21, "FOR_JOY22"}, + {KEY_4JOY1+22, "FOR_JOY23"}, + {KEY_4JOY1+23, "FOR_JOY24"}, + {KEY_4JOY1+24, "FOR_JOY25"}, + {KEY_4JOY1+25, "FOR_JOY26"}, + {KEY_4JOY1+26, "FOR_JOY27"}, + {KEY_4JOY1+27, "FOR_JOY28"}, + {KEY_4JOY1+28, "FOR_JOY29"}, + {KEY_4JOY1+29, "FOR_JOY30"}, + {KEY_4JOY1+30, "FOR_JOY31"}, + {KEY_4JOY1+31, "FOR_JOY32"}, +#endif + // the DOS version uses Allegro's joystick support + {KEY_4HAT1+0, "FOR_HATUP"}, + {KEY_4HAT1+1, "FOR_HATDOWN"}, + {KEY_4HAT1+2, "FOR_HATLEFT"}, + {KEY_4HAT1+3, "FOR_HATRIGHT"}, +#if !defined (_XBOX) && !defined (_PSP) && !defined (_WII) + {KEY_4HAT1+4, "FOR_HATUP2"}, + {KEY_4HAT1+5, "FOR_HATDOWN2"}, + {KEY_4HAT1+6, "FOR_HATLEFT2"}, + {KEY_4HAT1+7, "FOR_HATRIGHT2"}, +#ifndef _arch_dreamcast + {KEY_4HAT1+8, "FOR_HATUP3"}, + {KEY_4HAT1+9, "FOR_HATDOWN3"}, + {KEY_4HAT1+10, "FOR_HATLEFT3"}, + {KEY_4HAT1+11, "FOR_HATRIGHT3"}, + {KEY_4HAT1+12, "FOR_HATUP4"}, + {KEY_4HAT1+13, "FOR_HATDOWN4"}, + {KEY_4HAT1+14, "FOR_HATLEFT4"}, + {KEY_4HAT1+15, "FOR_HATRIGHT4"}, +#endif +#endif + +#ifdef DC + {KEY_DBL4JOY1+0, "DBLFOR_JOYC"}, + {KEY_DBL4JOY1+1, "DBLFOR_JOYB"}, + {KEY_DBL4JOY1+2, "DBLFOR_JOYA"}, + {KEY_DBL4JOY1+3, "DBLFOR_JOYS"}, + {KEY_DBL4JOY1+4, "DBLFOR_JOYZ"}, + {KEY_DBL4JOY1+5, "DBLFOR_JOYY"}, + {KEY_DBL4JOY1+6, "DBLFOR_JOYX"}, + {KEY_DBL4JOY1+7, "DBLFOR_JOYD"}, +#elif defined (_XBOX) + {KEY_DBL4JOY1+0, "DBLFOR_JOYA"}, + {KEY_DBL4JOY1+1, "DBLFOR_JOYB"}, + {KEY_DBL4JOY1+2, "DBLFOR_JOYX"}, + {KEY_DBL4JOY1+3, "DBLFOR_JOYY"}, + {KEY_DBL4JOY1+4, "DBLFOR_JOYG"}, + {KEY_DBL4JOY1+5, "DBLFOR_JOYW"}, + {KEY_DBL4JOY1+6, "DBLFOR_JOYL"}, + {KEY_DBL4JOY1+7, "DBLFOR_JOYR"}, + {KEY_DBL4JOY1+8, "DBLFOR_JOYS"}, + {KEY_DBL4JOY1+9, "DBLFOR_JOYN"}, + {KEY_DBL4JOY1+10,"DBLFOR_JOYW"}, + {KEY_DBL4JOY1+11,"DBLFOR_JOYE"}, +#define NOMOREJOYBTN_2DBL +#elif defined (_PSP) + {KEY_DBL4JOY1+0, "DBLFOR_TRIANGLE"}, + {KEY_DBL4JOY1+1, "DBLFOR_CIRCLE" }, + {KEY_DBL4JOY1+2, "DBLFOR_CROSS" }, + {KEY_DBL4JOY1+3, "DBLFOR_SQUARE" }, + {KEY_DBL4JOY1+4, "DBLFOR_LTRIGGER"}, + {KEY_DBL4JOY1+5, "DBLFOR_RTRIGGER"}, + {KEY_DBL4JOY1+6, "DBLFOR_SELECT" }, + {KEY_DBL4JOY1+7, "DBLFOR_START" }, + {KEY_DBL4JOY1+8, "DBLFOR_HOME" }, + {KEY_DBL4JOY1+9, "DBLFOR_HOLD" }, +#define NOMOREJOYBTN_2DBL +#elif defined (WMINPUT) + {KEY_DBL4JOY1+0, "DBLFOR_JOYB"}, + {KEY_DBL4JOY1+1, "DBLFOR_JOYA"}, + {KEY_DBL4JOY1+2, "DBLFOR_JOYUP"}, + {KEY_DBL4JOY1+3, "DBLFOR_JOYDOWN"}, + {KEY_DBL4JOY1+4, "DBLFOR_JOYLEFT"}, + {KEY_DBL4JOY1+5, "DBLFOR_JOYRIGHT"}, + {KEY_DBL4JOY1+6, "DBLFOR_JOYAA"}, + {KEY_DBL4JOY1+7, "DBLFOR_JOYBB"}, + {KEY_DBL4JOY1+8, "DBLFOR_JOYCC"}, + {KEY_DBL4JOY1+9, "DBLFOR_JOYXX"}, + {KEY_DBL4JOY1+10, "DBLFOR_JOYYY"}, + {KEY_DBL4JOY1+11, "DBLFOR_JOYZZ"}, + {KEY_DBL4JOY1+12, "DBLFOR_JOYL"}, + {KEY_DBL4JOY1+13, "DBLFOR_JOYR"}, + {KEY_DBL4JOY1+14, "DBLFOR_JOYZL"}, + {KEY_DBL4JOY1+15, "DBLFOR_JOYZR"}, + {KEY_DBL4JOY1+16, "DBLFOR_JOYSELECT"}, + {KEY_DBL4JOY1+17, "DBLFOR_JOYSTART"}, + {KEY_DBL4JOY1+18, "DBLFOR_JOYHOME"}, + {KEY_DBL4JOY1+19, "DBLFOR_JOYMINUS"}, + {KEY_DBL4JOY1+20, "DBLFOR_JOYPLUS"}, + {KEY_DBL4JOY1+21, "DBLFOR_JOY_1"}, + {KEY_DBL4JOY1+22, "DBLFOR_JOY_2"}, + {KEY_DBL4JOY1+23, "DBLFOR_JOY24"}, + {KEY_DBL4JOY1+24, "DBLFOR_JOY25"}, + {KEY_DBL4JOY1+25, "DBLFOR_JOY26"}, + {KEY_DBL4JOY1+26, "DBLFOR_JOY27"}, + {KEY_DBL4JOY1+27, "DBLFOR_JOY28"}, + {KEY_DBL4JOY1+28, "DBLFOR_JOY29"}, + {KEY_DBL4JOY1+29, "DBLFOR_JOY30"}, + {KEY_DBL4JOY1+30, "DBLFOR_JOY31"}, + {KEY_DBL4JOY1+31, "DBLFOR_JOY32"}, +#define NOMOREJOYBTN_2SDBL +#elif defined (_WII) + {KEY_DBL4JOY1+0, "DBLFOR_JOYA"}, + {KEY_DBL4JOY1+1, "DBLFOR_JOYB"}, + {KEY_DBL4JOY1+2, "DBLFOR_JOY1"}, + {KEY_DBL4JOY1+3, "DBLFOR_JOY2"}, + {KEY_DBL4JOY1+4, "DBLFOR_JOYMINUS"}, + {KEY_DBL4JOY1+5, "DBLFOR_JOYPLUS"}, + {KEY_DBL4JOY1+6, "DBLFOR_JOYHOME"}, + {KEY_DBL4JOY1+7, "DBLFOR_JOYZ"}, + {KEY_DBL4JOY1+8, "DBLFOR_JOYC"}, + {KEY_DBL4JOY1+9, "DBLFOR_JOYA_CC"}, + {KEY_DBL4JOY1+10, "DBLFOR_JOYB_CC"}, + {KEY_DBL4JOY1+11, "DBLFOR_JOYX"}, + {KEY_DBL4JOY1+12, "DBLFOR_JOYY"}, + {KEY_DBL4JOY1+13, "DBLFOR_JOYL"}, + {KEY_DBL4JOY1+14, "DBLFOR_JOYR"}, + {KEY_DBL4JOY1+15, "DBLFOR_JOYZL"}, + {KEY_DBL4JOY1+16, "DBLFOR_JOYZR"}, + {KEY_DBL4JOY1+17, "DBLFOR_JOYMINUS_CC"}, + {KEY_DBL4JOY1+18, "DBLFOR_JOYHPLUS_CC"}, + {KEY_DBL4JOY1+19, "DBLFOR_JOYMHOME_CC"}, +#define NOMOREJOYBTN_2DBL +#else + {KEY_DBL4JOY1+0, "DBLFOR_JOY1"}, + {KEY_DBL4JOY1+1, "DBLFOR_JOY2"}, + {KEY_DBL4JOY1+2, "DBLFOR_JOY3"}, + {KEY_DBL4JOY1+3, "DBLFOR_JOY4"}, + {KEY_DBL4JOY1+4, "DBLFOR_JOY5"}, + {KEY_DBL4JOY1+5, "DBLFOR_JOY6"}, + {KEY_DBL4JOY1+6, "DBLFOR_JOY7"}, + {KEY_DBL4JOY1+7, "DBLFOR_JOY8"}, +#endif +#if !defined (_arch_dreamcast) && !defined (NOMOREJOYBTN_2DBL) + {KEY_DBL4JOY1+8, "DBLFOR_JOY9"}, + {KEY_DBL4JOY1+9, "DBLFOR_JOY10"}, + {KEY_DBL4JOY1+10, "DBLFOR_JOY11"}, + {KEY_DBL4JOY1+11, "DBLFOR_JOY12"}, + {KEY_DBL4JOY1+12, "DBLFOR_JOY13"}, + {KEY_DBL4JOY1+13, "DBLFOR_JOY14"}, + {KEY_DBL4JOY1+14, "DBLFOR_JOY15"}, + {KEY_DBL4JOY1+15, "DBLFOR_JOY16"}, + {KEY_DBL4JOY1+16, "DBLFOR_JOY17"}, + {KEY_DBL4JOY1+17, "DBLFOR_JOY18"}, + {KEY_DBL4JOY1+18, "DBLFOR_JOY19"}, + {KEY_DBL4JOY1+19, "DBLFOR_JOY20"}, + {KEY_DBL4JOY1+20, "DBLFOR_JOY21"}, + {KEY_DBL4JOY1+21, "DBLFOR_JOY22"}, + {KEY_DBL4JOY1+22, "DBLFOR_JOY23"}, + {KEY_DBL4JOY1+23, "DBLFOR_JOY24"}, + {KEY_DBL4JOY1+24, "DBLFOR_JOY25"}, + {KEY_DBL4JOY1+25, "DBLFOR_JOY26"}, + {KEY_DBL4JOY1+26, "DBLFOR_JOY27"}, + {KEY_DBL4JOY1+27, "DBLFOR_JOY28"}, + {KEY_DBL4JOY1+28, "DBLFOR_JOY29"}, + {KEY_DBL4JOY1+29, "DBLFOR_JOY30"}, + {KEY_DBL4JOY1+30, "DBLFOR_JOY31"}, + {KEY_DBL4JOY1+31, "DBLFOR_JOY32"}, +#endif + {KEY_DBL4HAT1+0, "DBLFOR_HATUP"}, + {KEY_DBL4HAT1+1, "DBLFOR_HATDOWN"}, + {KEY_DBL4HAT1+2, "DBLFOR_HATLEFT"}, + {KEY_DBL4HAT1+3, "DBLFOR_HATRIGHT"}, +#if !defined (_XBOX) && !defined (_PSP) && !defined (_WII) + {KEY_DBL4HAT1+4, "DBLFOR_HATUP2"}, + {KEY_DBL4HAT1+5, "DBLFOR_HATDOWN2"}, + {KEY_DBL4HAT1+6, "DBLFOR_HATLEFT2"}, + {KEY_DBL4HAT1+7, "DBLFOR_HATRIGHT2"}, +#ifndef _arch_dreamcast + {KEY_DBL4HAT1+8, "DBLFOR_HATUP3"}, + {KEY_DBL4HAT1+9, "DBLFOR_HATDOWN3"}, + {KEY_DBL4HAT1+10, "DBLFOR_HATLEFT3"}, + {KEY_DBL4HAT1+11, "DBLFOR_HATRIGHT3"}, + {KEY_DBL4HAT1+12, "DBLFOR_HATUP4"}, + {KEY_DBL4HAT1+13, "DBLFOR_HATDOWN4"}, + {KEY_DBL4HAT1+14, "DBLFOR_HATLEFT4"}, + {KEY_DBL4HAT1+15, "DBLFOR_HATRIGHT4"}, +#endif +#endif + }; static const char *gamecontrolname[num_gamecontrols] = diff --git a/src/g_input.h b/src/g_input.h index 180816ae..6a9f6a72 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -71,7 +71,19 @@ typedef enum KEY_DBL2JOY1 = KEY_DBL2MOUSE1 + MOUSEBUTTONS, KEY_DBL2HAT1 = KEY_DBL2JOY1 + JOYBUTTONS, - KEY_MOUSEWHEELUP = KEY_DBL2HAT1 + JOYHATS*4, + KEY_3JOY1 = KEY_DBL2HAT1 + JOYHATS*4, + KEY_3HAT1 = KEY_3JOY1 + JOYBUTTONS, + + KEY_DBL3JOY1 = KEY_3HAT1 + JOYHATS*4, + KEY_DBL3HAT1 = KEY_DBL3JOY1 + JOYBUTTONS, + + KEY_4JOY1 = KEY_DBL3HAT1 + JOYHATS*4, + KEY_4HAT1 = KEY_4JOY1 + JOYBUTTONS, + + KEY_DBL4JOY1 = KEY_4HAT1 + JOYHATS*4, + KEY_DBL4HAT1 = KEY_DBL4JOY1 + JOYBUTTONS, + + KEY_MOUSEWHEELUP = KEY_DBL4HAT1 + JOYHATS*4, KEY_MOUSEWHEELDOWN = KEY_MOUSEWHEELUP + 1, KEY_2MOUSEWHEELUP = KEY_MOUSEWHEELDOWN + 1, KEY_2MOUSEWHEELDOWN = KEY_2MOUSEWHEELUP + 1, diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 72d465dc..e46080e0 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -39,7 +39,7 @@ #include "am_map.h" #include "d_main.h" -#include "p_local.h" // camera, camera2 +#include "p_local.h" // camera, camera2, camera3, camera4 #include "p_tick.h" #ifdef HWRENDER diff --git a/src/i_system.h b/src/i_system.h index a166629b..1887d2b9 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -76,10 +76,18 @@ void I_OsPolling(void); */ ticcmd_t *I_BaseTiccmd(void); -/** \brief Input for the sencond player +/** \brief Input for the second player */ ticcmd_t *I_BaseTiccmd2(void); +/** \brief Input for the third player +*/ +ticcmd_t *I_BaseTiccmd3(void); + +/** \brief Input for the fourth player +*/ +ticcmd_t *I_BaseTiccmd4(void); + /** \brief Called by M_Responder when quit is selected, return exit code 0 */ void I_Quit(void) FUNCNORETURN; diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 60cbbe50..ce46ad79 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -716,7 +716,11 @@ void LUAh_GameHUD(player_t *stplayr) lua_remove(gL, -3); // pop HUD LUA_PushUserdata(gL, stplayr, META_PLAYER); - if (splitscreen && stplayr == &players[secondarydisplayplayer]) + if (splitscreen4 && stplayr == &players[fourthdisplayplayer]) + LUA_PushUserdata(gL, &camera4, META_CAMERA); + else if ((splitscreen3 || splitscreen4) && stplayr == &players[thirddisplayplayer]) + LUA_PushUserdata(gL, &camera3, META_CAMERA); + else if ((splitscreen || splitscreen3 || splitscreen4) && stplayr == &players[secondarydisplayplayer]) LUA_PushUserdata(gL, &camera2, META_CAMERA); else LUA_PushUserdata(gL, &camera, META_CAMERA); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 6bb1388f..ec19261a 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -404,6 +404,10 @@ static int mobj_set(lua_State *L) localangle = mo->angle; else if (mo->player == &players[secondarydisplayplayer]) localangle2 = mo->angle; + else if (mo->player == &players[thirddisplayplayer]) + localangle3 = mo->angle; + else if (mo->player == &players[fourthdisplayplayer]) + localangle4 = mo->angle; break; case mobj_sprite: mo->sprite = luaL_checkinteger(L, 3); diff --git a/src/m_menu.c b/src/m_menu.c index fb9fb0d4..b0d82f31 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -176,7 +176,7 @@ static INT16 skullAnimCounter = 10; // skull animation counter static boolean setupcontrols_secondaryplayer; static boolean setupcontrols_thirdplayer; static boolean setupcontrols_fourthplayer; -static INT32 (*setupcontrols)[4]; // pointer to the gamecontrols of the player being edited +static INT32 (*setupcontrols)[2]; // pointer to the gamecontrols of the player being edited // shhh... what am I doing... nooooo! static INT32 vidm_testingmode = 0; @@ -261,6 +261,8 @@ static void M_ConnectMenu(INT32 choice); static void M_ConnectIPMenu(INT32 choice); #endif static void M_StartSplitServerMenu(INT32 choice); +static void M_Start3PServerMenu(INT32 choice); +static void M_Start4PServerMenu(INT32 choice); static void M_StartServer(INT32 choice); #ifndef NONET static void M_Refresh(INT32 choice); @@ -883,18 +885,18 @@ menuitem_t PlayerMenu[32] = static menuitem_t MP_MainMenu[] = { #ifndef NONET - {IT_CALL | IT_STRING, NULL, "HOST GAME", M_StartServerMenu, 10}, - {IT_CALL | IT_STRING, NULL, "JOIN GAME (Search)", M_ConnectMenu, 30}, - {IT_CALL | IT_STRING, NULL, "JOIN GAME (Specify IP)", M_ConnectIPMenu, 40}, + {IT_CALL | IT_STRING, NULL, "HOST GAME", M_StartServerMenu, 10}, + {IT_CALL | IT_STRING, NULL, "JOIN GAME (Search)", M_ConnectMenu, 30}, + {IT_CALL | IT_STRING, NULL, "JOIN GAME (Specify IP)", M_ConnectIPMenu, 40}, #endif - {IT_CALL | IT_STRING, NULL, "TWO PLAYER GAME", M_StartSplitServerMenu, 60}, - {IT_CALL | IT_STRING, NULL, "THREE PLAYER GAME", M_StartSplitServerMenu, 70}, - {IT_CALL | IT_STRING, NULL, "FOUR PLAYER GAME", M_StartSplitServerMenu, 80}, + {IT_CALL | IT_STRING, NULL, "TWO PLAYER GAME", M_StartSplitServerMenu, 60}, + {IT_CALL | IT_STRING, NULL, "THREE PLAYER GAME", M_Start3PServerMenu, 70}, + {IT_CALL | IT_STRING, NULL, "FOUR PLAYER GAME", M_Start4PServerMenu, 80}, - {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 1", M_SetupMultiPlayer, 100}, - {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 2", M_SetupMultiPlayer2, 110}, - {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 3", M_SetupMultiPlayer3, 120}, - {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 4", M_SetupMultiPlayer4, 130}, + {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 1", M_SetupMultiPlayer, 100}, + {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 2", M_SetupMultiPlayer2, 110}, + {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 3", M_SetupMultiPlayer3, 120}, + {IT_CALL | IT_STRING, NULL, "SETUP PLAYER 4", M_SetupMultiPlayer4, 130}, }; static menuitem_t MP_ServerMenu[] = @@ -1728,6 +1730,8 @@ menu_t MP_RoomDef = }; #endif menu_t MP_SplitServerDef = MAPICONMENUSTYLE("M_MULTI", MP_SplitServerMenu, &MP_MainDef); +menu_t MP_3PServerDef = MAPICONMENUSTYLE("M_MULTI", MP_SplitServerMenu, &MP_MainDef); +menu_t MP_4PServerDef = MAPICONMENUSTYLE("M_MULTI", MP_SplitServerMenu, &MP_MainDef); menu_t MP_PlayerSetupDef = { NULL, //"M_SPLAYR" @@ -2406,7 +2410,7 @@ boolean M_Responder(event_t *ev) { // dirty hack: for customising controls, I want only buttons/keys, not moves if (ev->type == ev_mouse || ev->type == ev_mouse2 || ev->type == ev_joystick - || ev->type == ev_joystick2) + || ev->type == ev_joystick2 || ev->type == ev_joystick3 || ev->type == ev_joystick4) return true; if (routine) { @@ -5085,7 +5089,7 @@ static void M_ChoosePlayer(INT32 choice) lastmapsaved = 0; gamecomplete = false; - G_DeferedInitNew(ultmode, G_BuildMapName(startmap), (UINT8)skinnum, false, fromlevelselect); + G_DeferedInitNew(ultmode, G_BuildMapName(startmap), (UINT8)skinnum, 1, fromlevelselect); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this } @@ -5675,7 +5679,7 @@ static void M_ChooseNightsAttack(INT32 choice) else G_RecordDemo(nameofdemo); - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, false, false); + G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), 0, 1, false); } // Player has selected the "START" from the time attack screen @@ -5703,7 +5707,7 @@ static void M_ChooseTimeAttack(INT32 choice) else G_RecordDemo(nameofdemo); - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), false, false); + G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), 1, false); } static void M_HandleStaffReplay(INT32 choice) @@ -6325,10 +6329,17 @@ static INT32 M_FindFirstMap(INT32 gtype) static void M_StartServer(INT32 choice) { - boolean StartSplitScreenGame = (currentMenu == &MP_SplitServerDef); + UINT8 ssplayers = 1; + + if (currentMenu == &MP_SplitServerDef) + ssplayers = 2; + else if (currentMenu == &MP_3PServerDef) + ssplayers = 3; + else if (currentMenu == &MP_4PServerDef) + ssplayers = 4; (void)choice; - if (!StartSplitScreenGame) + if (ssplayers < 2) netgame = true; multiplayer = true; @@ -6341,7 +6352,7 @@ static void M_StartServer(INT32 choice) if (metalrecording) G_StopMetalDemo(); - if (!StartSplitScreenGame) + if (ssplayers < 2) { D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false); COM_BufAddText("dummyconsvar 1\n"); @@ -6350,11 +6361,26 @@ static void M_StartServer(INT32 choice) { paused = false; SV_StartSinglePlayerServer(); - if (!splitscreen) + + if (!splitscreen4 && ssplayers == 4) { - splitscreen = true; + splitscreen4 = true; + splitscreen = splitscreen3 = false; SplitScreen_OnChange(); } + else if (!splitscreen3 && ssplayers == 3) + { + splitscreen3 = true; + splitscreen = splitscreen4 = false; + SplitScreen_OnChange(); + } + else if (!splitscreen && ssplayers == 2) + { + splitscreen = true; + splitscreen3 = splitscreen4 = false; + SplitScreen_OnChange(); + } + D_MapChange(cv_nextmap.value, cv_newgametype.value, false, 1, 1, false, false); } @@ -6422,6 +6448,22 @@ static void M_StartSplitServerMenu(INT32 choice) M_SetupNextMenu(&MP_SplitServerDef); } +static void M_Start3PServerMenu(INT32 choice) +{ + (void)choice; + levellistmode = LLM_CREATESERVER; + M_PrepareLevelSelect(); + M_SetupNextMenu(&MP_3PServerDef); +} + +static void M_Start4PServerMenu(INT32 choice) +{ + (void)choice; + levellistmode = LLM_CREATESERVER; + M_PrepareLevelSelect(); + M_SetupNextMenu(&MP_4PServerDef); +} + #ifndef NONET static void M_StartServerMenu(INT32 choice) { @@ -7040,8 +7082,10 @@ static void M_DrawJoystick(void) { M_DrawSaveLoadBorder(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i); - if ((setupcontrols_secondaryplayer && (i == cv_usejoystick2.value)) - || (!setupcontrols_secondaryplayer && (i == cv_usejoystick.value))) + if ((setupcontrols_fourthplayer && (i == cv_usejoystick4.value)) + || (setupcontrols_thirdplayer && (i == cv_usejoystick3.value)) + || (setupcontrols_secondaryplayer && (i == cv_usejoystick2.value)) + || (!(setupcontrols_secondaryplayer || setupcontrols_thirdplayer || setupcontrols_fourthplayer) && (i == cv_usejoystick.value))) V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i,V_GREENMAP,joystickInfo[i]); else V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i,0,joystickInfo[i]); @@ -7075,6 +7119,8 @@ static void M_SetupJoystickMenu(INT32 choice) static void M_Setup1PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = false; + setupcontrols_thirdplayer = false; + setupcontrols_fourthplayer = false; OP_JoystickSetDef.prevMenu = &OP_Joystick1Def; M_SetupJoystickMenu(choice); } @@ -7082,6 +7128,8 @@ static void M_Setup1PJoystickMenu(INT32 choice) static void M_Setup2PJoystickMenu(INT32 choice) { setupcontrols_secondaryplayer = true; + setupcontrols_thirdplayer = false; + setupcontrols_fourthplayer = false; OP_JoystickSetDef.prevMenu = &OP_Joystick2Def; M_SetupJoystickMenu(choice); } @@ -7089,6 +7137,8 @@ static void M_Setup2PJoystickMenu(INT32 choice) static void M_Setup3PJoystickMenu(INT32 choice) { setupcontrols_thirdplayer = true; + setupcontrols_secondaryplayer = false; + setupcontrols_fourthplayer = false; OP_JoystickSetDef.prevMenu = &OP_Joystick3Def; M_SetupJoystickMenu(choice); } @@ -7096,6 +7146,8 @@ static void M_Setup3PJoystickMenu(INT32 choice) static void M_Setup4PJoystickMenu(INT32 choice) { setupcontrols_fourthplayer = true; + setupcontrols_secondaryplayer = false; + setupcontrols_thirdplayer = false; OP_JoystickSetDef.prevMenu = &OP_Joystick4Def; M_SetupJoystickMenu(choice); } @@ -7291,6 +7343,10 @@ static void M_ChangecontrolResponse(event_t *ev) setupcontrols[control][found] = ch-KEY_2MOUSE1+KEY_DBL2MOUSE1; else if (ch >= KEY_2JOY1 && ch <= KEY_2JOY1+JOYBUTTONS) setupcontrols[control][found] = ch-KEY_2JOY1+KEY_DBL2JOY1; + else if (ch >= KEY_3JOY1 && ch <= KEY_3JOY1+JOYBUTTONS) + setupcontrols[control][found] = ch-KEY_3JOY1+KEY_DBL3JOY1; + else if (ch >= KEY_4JOY1 && ch <= KEY_4JOY1+JOYBUTTONS) + setupcontrols[control][found] = ch-KEY_4JOY1+KEY_DBL4JOY1; } else { diff --git a/src/p_floor.c b/src/p_floor.c index bc9bde63..b9b542ce 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2490,11 +2490,11 @@ void T_CameraScanner(elevator_t *elevator) { // leveltime is compared to make multiple scanners in one map function correctly. static tic_t lastleveltime = 32000; // any number other than 0 should do here - static boolean camerascanned, camerascanned2; + static boolean camerascanned, camerascanned2, camerascanned3, camerascanned4; if (leveltime != lastleveltime) // Back on the first camera scanner { - camerascanned = camerascanned2 = false; + camerascanned = camerascanned2 = camerascanned3 = camerascanned4 = false; lastleveltime = leveltime; } @@ -2526,7 +2526,7 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen && players[secondarydisplayplayer].mo) + if ((splitscreen || splitscreen3 || splitscreen4) && players[secondarydisplayplayer].mo) { if (players[secondarydisplayplayer].mo->subsector->sector == elevator->actionsector) { @@ -2553,6 +2553,62 @@ void T_CameraScanner(elevator_t *elevator) t_cam2_dist = t_cam2_height = t_cam2_rotate = -42; } } + + if ((splitscreen3 || splitscreen4) && players[thirddisplayplayer].mo) + { + if (players[thirddisplayplayer].mo->subsector->sector == elevator->actionsector) + { + if (t_cam3_rotate == -42) + t_cam3_dist = cv_cam3_dist.value; + if (t_cam3_rotate == -42) + t_cam3_height = cv_cam3_height.value; + if (t_cam3_rotate == -42) + t_cam3_rotate = cv_cam3_rotate.value; + CV_SetValue(&cv_cam3_height, FixedInt(elevator->sector->floorheight)); + CV_SetValue(&cv_cam3_dist, FixedInt(elevator->sector->ceilingheight)); + CV_SetValue(&cv_cam3_rotate, elevator->distance); + camerascanned3 = true; + } + else if (!camerascanned3) + { + if (t_cam3_height != -42 && cv_cam3_height.value != t_cam3_height) + CV_Set(&cv_cam3_height, va("%f", (double)FIXED_TO_FLOAT(t_cam3_height))); + if (t_cam3_dist != -42 && cv_cam3_dist.value != t_cam3_dist) + CV_Set(&cv_cam3_dist, va("%f", (double)FIXED_TO_FLOAT(t_cam3_dist))); + if (t_cam3_rotate != -42 && cv_cam3_rotate.value != t_cam3_rotate) + CV_Set(&cv_cam3_rotate, va("%f", (double)t_cam3_rotate)); + + t_cam3_dist = t_cam3_height = t_cam3_rotate = -42; + } + } + + if (splitscreen4 && players[fourthdisplayplayer].mo) + { + if (players[fourthdisplayplayer].mo->subsector->sector == elevator->actionsector) + { + if (t_cam4_rotate == -42) + t_cam4_dist = cv_cam4_dist.value; + if (t_cam4_rotate == -42) + t_cam4_height = cv_cam4_height.value; + if (t_cam4_rotate == -42) + t_cam4_rotate = cv_cam4_rotate.value; + CV_SetValue(&cv_cam4_height, FixedInt(elevator->sector->floorheight)); + CV_SetValue(&cv_cam4_dist, FixedInt(elevator->sector->ceilingheight)); + CV_SetValue(&cv_cam4_rotate, elevator->distance); + camerascanned4 = true; + } + else if (!camerascanned4) + { + if (t_cam4_height != -42 && cv_cam4_height.value != t_cam4_height) + CV_Set(&cv_cam4_height, va("%f", (double)FIXED_TO_FLOAT(t_cam4_height))); + if (t_cam4_dist != -42 && cv_cam4_dist.value != t_cam4_dist) + CV_Set(&cv_cam4_dist, va("%f", (double)FIXED_TO_FLOAT(t_cam4_dist))); + if (t_cam4_rotate != -42 && cv_cam4_rotate.value != t_cam4_rotate) + CV_Set(&cv_cam4_rotate, va("%f", (double)t_cam4_rotate)); + + t_cam4_dist = t_cam4_height = t_cam4_rotate = -42; + } + } } // diff --git a/src/p_inter.c b/src/p_inter.c index 0882f23f..1f86a869 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -951,6 +951,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) localangle = toucher->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = toucher->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = toucher->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = toucher->angle; P_ResetPlayer(player); diff --git a/src/p_map.c b/src/p_map.c index f2fcf53c..00108372 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -216,6 +216,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) localangle = spring->angle; else if (object->player == &players[secondarydisplayplayer]) localangle2 = spring->angle; + else if (object->player == &players[thirddisplayplayer]) + localangle3 = spring->angle; + else if (object->player == &players[fourthdisplayplayer]) + localangle4 = spring->angle; } } @@ -2511,7 +2515,9 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) if (twodlevel || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) + || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)) + || (thiscam == &camera3 && players[thirddisplayplayer].mo && (players[thirddisplayplayer].mo->flags2 & MF2_TWOD)) + || (thiscam == &camera4 && players[fourthdisplayplayer].mo && (players[fourthdisplayplayer].mo->flags2 & MF2_TWOD))) itsatwodlevel = true; if (!itsatwodlevel && players[displayplayer].mo) @@ -2520,7 +2526,9 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) fixed_t tryy = thiscam->y; if ((thiscam == &camera && (players[displayplayer].pflags & PF_NOCLIP)) - || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP))) + || (thiscam == &camera2 && (players[secondarydisplayplayer].pflags & PF_NOCLIP)) + || (thiscam == &camera3 && (players[thirddisplayplayer].pflags & PF_NOCLIP)) + || (thiscam == &camera4 && (players[fourthdisplayplayer].pflags & PF_NOCLIP))) { // Noclipping player camera noclips too!! floatok = true; thiscam->floorz = thiscam->z; @@ -3481,6 +3489,10 @@ isblocking: localangle = slidemo->angle; else if (slidemo->player == &players[secondarydisplayplayer]) localangle2 = slidemo->angle; + else if (slidemo->player == &players[thirddisplayplayer]) + localangle3 = slidemo->angle; + else if (slidemo->player == &players[fourthdisplayplayer]) + localangle4 = slidemo->angle; } if (!slidemo->player->climbing) diff --git a/src/p_mobj.c b/src/p_mobj.c index adbc466c..ee54f3dc 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1249,6 +1249,26 @@ static void P_PlayerFlip(mobj_t *mo) camera2.z += FixedMul(20*FRACUNIT, mo->scale); } } + else if (mo->player-players == thirddisplayplayer) + { + localaiming3 = mo->player->aiming; + if (camera3.chase) { + camera3.aiming = InvAngle(camera3.aiming); + camera3.z = mo->z - camera3.z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera3.z += FixedMul(20*FRACUNIT, mo->scale); + } + } + else if (mo->player-players == fourthdisplayplayer) + { + localaiming4 = mo->player->aiming; + if (camera4.chase) { + camera4.aiming = InvAngle(camera4.aiming); + camera4.z = mo->z - camera4.z + mo->z; + if (mo->eflags & MFE_VERTICALFLIP) + camera4.z += FixedMul(20*FRACUNIT, mo->scale); + } + } } } @@ -3578,7 +3598,9 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled postimg_t postimg = postimg_none; if (twodlevel || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) - || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD))) + || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)) + || (thiscam == &camera3 && players[thirddisplayplayer].mo && (players[thirddisplayplayer].mo->flags2 & MF2_TWOD)) + || (thiscam == &camera4 && players[fourthdisplayplayer].mo && (players[fourthdisplayplayer].mo->flags2 & MF2_TWOD))) itsatwodlevel = true; if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) @@ -9552,6 +9574,10 @@ void P_AfterPlayerSpawn(INT32 playernum) localangle = mobj->angle; else if (playernum == secondarydisplayplayer) localangle2 = mobj->angle; + else if (playernum == thirddisplayplayer) + localangle3 = mobj->angle; + else if (playernum == fourthdisplayplayer) + localangle4 = mobj->angle; p->viewheight = cv_viewheight.value<angle; else if (mo->player == &players[secondarydisplayplayer]) localangle2 = mo->angle; + else if (mo->player == &players[thirddisplayplayer]) + localangle3 = mo->angle; + else if (mo->player == &players[fourthdisplayplayer]) + localangle4 = mo->angle; } } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 847ba1a9..4ae5175a 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2064,6 +2064,10 @@ static void LoadMobjThinker(actionf_p1 thinker) localangle = mobj->angle; if (secondarydisplayplayer == i) localangle2 = mobj->angle; + if (thirddisplayplayer == i) + localangle3 = mobj->angle; + if (fourthdisplayplayer == i) + localangle4 = mobj->angle; } if (diff & MD_MOVEDIR) mobj->movedir = READANGLE(save_p); @@ -3370,7 +3374,7 @@ boolean P_LoadGame(INT16 mapoverride) return false; // Only do this after confirming savegame is ok - G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, false, true); + G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, 1, true); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this return true; diff --git a/src/p_spec.c b/src/p_spec.c index a6292355..27c17bde 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2381,7 +2381,21 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3 P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z); - if (splitscreen && mo->player == &players[secondarydisplayplayer] && camera2.chase) + if (splitscreen4 && mo->player == &players[fourthdisplayplayer] && camera4.chase) + { + camera4.x += x; + camera4.y += y; + camera4.z += z; + camera4.subsector = R_PointInSubsector(camera4.x, camera4.y); + } + else if ((splitscreen3 || splitscreen4) && mo->player == &players[thirddisplayplayer] && camera3.chase) + { + camera3.x += x; + camera3.y += y; + camera3.z += z; + camera3.subsector = R_PointInSubsector(camera3.x, camera3.y); + } + else if ((splitscreen || splitscreen3 || splitscreen4) && mo->player == &players[secondarydisplayplayer] && camera2.chase) { camera2.x += x; camera2.y += y; @@ -3770,6 +3784,10 @@ DoneSection2: localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } if (!(lines[i].flags & ML_EFFECT4)) @@ -7709,10 +7727,28 @@ void T_Pusher(pusher_t *p) else localangle2 += (thing->angle - localangle2) / 8; } + else if (thing->player == &players[thirddisplayplayer]) + { + if (thing->angle - localangle3 > ANGLE_180) + localangle3 -= (localangle3 - thing->angle) / 8; + else + localangle3 += (thing->angle - localangle3) / 8; + } + else if (thing->player == &players[fourthdisplayplayer]) + { + if (thing->angle - localangle4 > ANGLE_180) + localangle4 -= (localangle4 - thing->angle) / 8; + else + localangle4 += (thing->angle - localangle4) / 8; + } /*if (thing->player == &players[consoleplayer]) localangle = thing->angle; else if (thing->player == &players[secondarydisplayplayer]) - localangle2 = thing->angle;*/ + localangle2 = thing->angle; + else if (thing->player == &players[thirddisplayplayer]) + localangle3 = thing->angle; + else if (thing->player == &players[fourthdisplayplayer]) + localangle4 = thing->angle;*/ } } diff --git a/src/p_telept.c b/src/p_telept.c index d7248857..3f9883b6 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -67,13 +67,18 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, localangle = angle; if (thing == players[secondarydisplayplayer].mo) localangle2 = angle; + if (thing == players[thirddisplayplayer].mo) + localangle3 = angle; + if (thing == players[fourthdisplayplayer].mo) + localangle4 = angle; // move chasecam at new player location - if (splitscreen && camera2.chase - && thing->player == &players[secondarydisplayplayer]) - { + if (splitscreen4 && camera4.chase && thing->player == &players[fourthdisplayplayer]) + P_ResetCamera(thing->player, &camera4); + else if ((splitscreen3 || splitscreen4) && camera3.chase && thing->player == &players[thirddisplayplayer]) + P_ResetCamera(thing->player, &camera3); + else if ((splitscreen || splitscreen3 || splitscreen4) && camera2.chase && thing->player == &players[secondarydisplayplayer]) P_ResetCamera(thing->player, &camera2); - } else if (camera.chase && thing->player == &players[displayplayer]) P_ResetCamera(thing->player, &camera); @@ -147,9 +152,17 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle localangle = angle; if (thing->player == &players[secondarydisplayplayer]) localangle2 = angle; + if (thing->player == &players[thirddisplayplayer]) + localangle3 = angle; + if (thing->player == &players[fourthdisplayplayer]) + localangle4 = angle; // move chasecam at new player location - if (splitscreen && camera2.chase && thing->player == &players[secondarydisplayplayer]) + if (splitscreen4 && camera4.chase && thing->player == &players[fourthdisplayplayer]) + P_ResetCamera(thing->player, &camera4); + else if ((splitscreen3 || splitscreen4) && camera3.chase && thing->player == &players[thirddisplayplayer]) + P_ResetCamera(thing->player, &camera3); + else if ((splitscreen || splitscreen3 || splitscreen4) && camera2.chase && thing->player == &players[secondarydisplayplayer]) P_ResetCamera(thing->player, &camera2); else if (camera.chase && thing->player == &players[displayplayer]) P_ResetCamera(thing->player, &camera); diff --git a/src/p_user.c b/src/p_user.c index d4f01a03..0ad1c64f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2858,6 +2858,10 @@ static void P_DoClimbing(player_t *player) // SRB2kart - unused localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } if (player->climbing == 0) @@ -3687,6 +3691,10 @@ void P_DoJump(player_t *player, boolean soundandstate) localangle = player->mo->angle; // Adjust the local control angle. else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } player->climbing = 0; // Stop climbing, duh! @@ -4372,7 +4380,11 @@ INT32 P_GetPlayerControlDirection(player_t *player) fixed_t tempx = 0, tempy = 0; angle_t tempangle, origtempangle; - if (splitscreen && player == &players[secondarydisplayplayer]) + if (splitscreen4 && player == &players[fourthdisplayplayer]) + thiscam = &camera4; + else if ((splitscreen3 || splitscreen4) && player == &players[thirddisplayplayer]) + thiscam = &camera3; + else if ((splitscreen || splitscreen3 || splitscreen4) && player == &players[secondarydisplayplayer]) thiscam = &camera2; else thiscam = &camera; @@ -4519,6 +4531,10 @@ static void P_2dMovement(player_t *player) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; if (player->pflags & PF_GLIDING) movepushangle = player->mo->angle; @@ -6251,6 +6267,10 @@ static void P_NiGHTSMovement(player_t *player) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; if (still) { @@ -7110,6 +7130,10 @@ static void P_MovePlayer(player_t *player) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } /////////////////////////// @@ -7501,6 +7525,10 @@ static void P_DoZoomTube(player_t *player) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } } @@ -7882,6 +7910,10 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target localangle = source->angle; else if (source->player == &players[secondarydisplayplayer]) localangle2 = source->angle; + else if (source->player == &players[thirddisplayplayer]) + localangle3 = source->angle; + else if (source->player == &players[fourthdisplayplayer]) + localangle4 = source->angle; } // change slope @@ -8072,7 +8104,7 @@ static void P_DeathThink(player_t *player) // P_MoveCamera: make sure the camera is not outside the world and looks at the player avatar // -camera_t camera, camera2; // Two cameras.. one for split! +camera_t camera, camera2, camera3, camera4; // Four cameras, three for splitscreen static void CV_CamRotate_OnChange(void) { @@ -8141,6 +8173,12 @@ fixed_t t_cam_rotate = -42; fixed_t t_cam2_dist = -42; fixed_t t_cam2_height = -42; fixed_t t_cam2_rotate = -42; +fixed_t t_cam3_dist = -42; +fixed_t t_cam3_height = -42; +fixed_t t_cam3_rotate = -42; +fixed_t t_cam4_dist = -42; +fixed_t t_cam4_height = -42; +fixed_t t_cam4_rotate = -42; #define MAXCAMERADIST 140*FRACUNIT // Max distance the camera can be in front of the player (2D mode) @@ -8169,7 +8207,9 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->z = z; if (!(thiscam == &camera && (cv_cam_still.value || cv_analog.value)) - && !(thiscam == &camera2 && (cv_cam2_still.value || cv_analog2.value))) + && !(thiscam == &camera2 && (cv_cam2_still.value || cv_analog2.value)) + && !(thiscam == &camera3 && (cv_cam3_still.value || cv_analog3.value)) + && !(thiscam == &camera4 && (cv_cam4_still.value || cv_analog4.value))) { thiscam->angle = player->mo->angle; thiscam->aiming = 0; @@ -8206,6 +8246,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (!cv_chasecam2.value && thiscam == &camera2) return true; + + if (!cv_chasecam3.value && thiscam == &camera3) + return true; + + if (!cv_chasecam4.value && thiscam == &camera4) + return true; } if (!thiscam->chase && !resetcalled) @@ -8214,12 +8260,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall focusangle = localangle; else if (player == &players[secondarydisplayplayer]) focusangle = localangle2; + else if (player == &players[thirddisplayplayer]) + focusangle = localangle3; + else if (player == &players[fourthdisplayplayer]) + focusangle = localangle4; else focusangle = player->mo->angle; if (thiscam == &camera) camrotate = cv_cam_rotate.value; else if (thiscam == &camera2) camrotate = cv_cam2_rotate.value; + else if (thiscam == &camera3) + camrotate = cv_cam3_rotate.value; + else if (thiscam == &camera4) + camrotate = cv_cam4_rotate.value; else camrotate = 0; thiscam->angle = focusangle + FixedAngle(camrotate*FRACUNIT); @@ -8258,6 +8312,16 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall focusangle = localangle2; focusaiming = localaiming2; } + else if (player == &players[thirddisplayplayer]) + { + focusangle = localangle3; + focusaiming = localaiming3; + } + else if (player == &players[fourthdisplayplayer]) + { + focusangle = localangle4; + focusaiming = localaiming4; + } else { focusangle = player->mo->angle; @@ -8332,8 +8396,11 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else angle = focusangle + FixedAngle(camrotate*FRACUNIT); - if (!resetcalled && (cv_analog.value || demoplayback) && ((thiscam == &camera && t_cam_rotate != -42) || (thiscam == &camera2 - && t_cam2_rotate != -42))) + if (!resetcalled && (cv_analog.value || demoplayback) + && ((thiscam == &camera && t_cam_rotate != -42) + || (thiscam == &camera2 && t_cam2_rotate != -42) + || (thiscam == &camera3 && t_cam3_rotate != -42) + || (thiscam == &camera4 && t_cam4_rotate != -42))) { angle = FixedAngle(camrotate*FRACUNIT); thiscam->angle = angle; @@ -8424,12 +8491,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { dist = camdist; - // x1.5 dist for splitscreen - if (splitscreen) + if (splitscreen) // x1.5 dist for splitscreen { dist = FixedMul(dist, 3*FRACUNIT/2); height = FixedMul(height, 3*FRACUNIT/2); } + else if (splitscreen3) // x1.75 dist for 3p + { + dist = FixedMul(dist, 7*FRACUNIT/4); + height = FixedMul(height, 7*FRACUNIT/4); + } + else if (splitscreen4) // x2 dist for 4p + { + dist = FixedMul(dist, 2*FRACUNIT); + height = FixedMul(height, 2*FRACUNIT); + } // x1.2 dist for analog if (P_AnalogMove(player)) @@ -9401,7 +9477,9 @@ void P_PlayerThink(player_t *player) // Why not just not spawn the mobj? Well, I'd rather only flirt with // consistency so much... if ((player == &players[displayplayer] && !camera.chase) - || (splitscreen && player == &players[secondarydisplayplayer] && !camera2.chase)) + || ((splitscreen || splitscreen3 || splitscreen4) && player == &players[secondarydisplayplayer] && !camera2.chase) + || ((splitscreen3 || splitscreen4) && player == &players[thirddisplayplayer] && !camera3.chase) + || (splitscreen4 && player == &players[fourthdisplayplayer] && !camera4.chase)) gmobj->flags2 |= MF2_DONTDRAW; } #endif @@ -9617,7 +9695,11 @@ void P_PlayerAfterThink(player_t *player) P_PlayerInSpecialSector(player); #endif - if (splitscreen && player == &players[secondarydisplayplayer]) + if (splitscreen4 && player == &players[fourthdisplayplayer]) + thiscam = &camera4; + else if ((splitscreen3 || splitscreen4) && player == &players[thirddisplayplayer]) + thiscam = &camera3; + else if ((splitscreen || splitscreen3 || splitscreen4) && player == &players[secondarydisplayplayer]) thiscam = &camera2; else if (player == &players[displayplayer]) thiscam = &camera; @@ -9816,6 +9898,10 @@ void P_PlayerAfterThink(player_t *player) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } } @@ -9889,6 +9975,10 @@ void P_PlayerAfterThink(player_t *player) localangle = player->mo->angle; // Adjust the local control angle. else if (player == &players[secondarydisplayplayer]) localangle2 = player->mo->angle; + else if (player == &players[thirddisplayplayer]) + localangle3 = player->mo->angle; + else if (player == &players[fourthdisplayplayer]) + localangle4 = player->mo->angle; } } } diff --git a/src/r_bsp.c b/src/r_bsp.c index abb11204..27045d8c 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -257,7 +257,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, INT32 heightsec; boolean underwater; - if (splitscreen && viewplayer == &players[secondarydisplayplayer] && camera2.chase) + if (splitscreen4 && viewplayer == &players[fourthdisplayplayer] && camera4.chase) + heightsec = R_PointInSubsector(camera4.x, camera4.y)->sector->heightsec; + else if ((splitscreen3 || splitscreen4) && viewplayer == &players[thirddisplayplayer] && camera3.chase) + heightsec = R_PointInSubsector(camera3.x, camera3.y)->sector->heightsec; + else if ((splitscreen || splitscreen3 || splitscreen4) && viewplayer == &players[secondarydisplayplayer] && camera2.chase) heightsec = R_PointInSubsector(camera2.x, camera2.y)->sector->heightsec; else if (camera.chase && viewplayer == &players[displayplayer]) heightsec = R_PointInSubsector(camera.x, camera.y)->sector->heightsec; diff --git a/src/r_main.c b/src/r_main.c index 93222deb..66869145 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -67,7 +67,7 @@ fixed_t viewx, viewy, viewz; angle_t viewangle, aimingangle; fixed_t viewcos, viewsin; boolean viewsky, skyVisible; -boolean skyVisible1, skyVisible2; // saved values of skyVisible for P1 and P2, for splitscreen +boolean skyVisible1, skyVisible2, skyVisible3, skyVisible4; // saved values of skyVisible for P1/P2/P3/P4, for splitscreen sector_t *viewsector; player_t *viewplayer; @@ -178,10 +178,10 @@ void SplitScreen_OnChange(void) { if (!cv_debug && netgame) { - if (splitscreen) + if (splitscreen || splitscreen3 || splitscreen4) { CONS_Alert(CONS_NOTICE, M_GetText("Splitscreen not supported in netplay, sorry!\n")); - splitscreen = false; + splitscreen = splitscreen3 = splitscreen4 = false; } return; } @@ -191,23 +191,50 @@ void SplitScreen_OnChange(void) if (!demoplayback && !botingame) { - if (splitscreen) + if (splitscreen || splitscreen3 || splitscreen4) CL_AddSplitscreenPlayer(); else - CL_RemoveSplitscreenPlayer(); + CL_RemoveSplitscreenPlayer(secondarydisplayplayer); + + if (splitscreen3 || splitscreen4) + CL_AddSplitscreenPlayer(); + else + CL_RemoveSplitscreenPlayer(thirddisplayplayer); + + if (splitscreen4) + CL_AddSplitscreenPlayer(); + else + CL_RemoveSplitscreenPlayer(fourthdisplayplayer); if (server && !netgame) - multiplayer = splitscreen; + multiplayer = (splitscreen || splitscreen3 || splitscreen4); } else { INT32 i; secondarydisplayplayer = consoleplayer; + thirddisplayplayer = consoleplayer; + fourthdisplayplayer = consoleplayer; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && i != consoleplayer) { - secondarydisplayplayer = i; - break; + if (secondarydisplayplayer == consoleplayer) + { + secondarydisplayplayer = i; + continue; + } + else if (thirddisplayplayer == consoleplayer) + { + thirddisplayplayer = i; + continue; + } + else if (fourthdisplayplayer == consoleplayer) + { + fourthdisplayplayer = i; + break; + } + else + break; } } } @@ -232,8 +259,6 @@ static void ChaseCam2_OnChange(void) static void ChaseCam3_OnChange(void) { - if (botingame) - return; if (!cv_chasecam3.value || !cv_useranalog3.value) CV_SetValue(&cv_analog3, 0); else @@ -242,8 +267,6 @@ static void ChaseCam3_OnChange(void) static void ChaseCam4_OnChange(void) { - if (botingame) - return; if (!cv_chasecam4.value || !cv_useranalog4.value) CV_SetValue(&cv_analog4, 0); else @@ -634,9 +657,12 @@ void R_ExecuteSetViewSize(void) scaledviewwidth = vid.width; viewheight = vid.height; - if (splitscreen) + if (splitscreen || splitscreen3 || splitscreen4) viewheight >>= 1; + if (splitscreen3 || splitscreen4) + viewwidth >>= 1; + viewwidth = scaledviewwidth; centerx = viewwidth/2; @@ -803,8 +829,11 @@ void R_SkyboxFrame(player_t *player) INT32 dy = 0; camera_t *thiscam; - if (splitscreen && player == &players[secondarydisplayplayer] - && player != &players[consoleplayer]) + if (splitscreen4 && player == &players[fourthdisplayplayer]) + thiscam = &camera4; + else if ((splitscreen3 || splitscreen4) && player == &players[thirddisplayplayer]) + thiscam = &camera3; + else if ((splitscreen || splitscreen3 || splitscreen4) && player == &players[secondarydisplayplayer]) thiscam = &camera2; else thiscam = &camera; @@ -845,6 +874,16 @@ void R_SkyboxFrame(player_t *player) viewangle = localangle2; aimingangle = localaiming2; } + else if (player == &players[thirddisplayplayer]) + { + viewangle = localangle3; + aimingangle = localaiming3; + } + else if (player == &players[fourthdisplayplayer]) + { + viewangle = localangle4; + aimingangle = localaiming4; + } } } viewangle += viewmobj->angle; @@ -1039,8 +1078,17 @@ void R_SetupFrame(player_t *player, boolean skybox) camera_t *thiscam; boolean chasecam = false; - if (splitscreen && player == &players[secondarydisplayplayer] - && player != &players[consoleplayer]) + if (splitscreen4 && player == &players[fourthdisplayplayer]) + { + thiscam = &camera4; + chasecam = (cv_chasecam4.value != 0); + } + else if ((splitscreen3 || splitscreen4) && player == &players[thirddisplayplayer]) + { + thiscam = &camera3; + chasecam = (cv_chasecam3.value != 0); + } + else if ((splitscreen || splitscreen3 || splitscreen4) && player == &players[secondarydisplayplayer]) { thiscam = &camera2; chasecam = (cv_chasecam2.value != 0); @@ -1105,6 +1153,16 @@ void R_SetupFrame(player_t *player, boolean skybox) viewangle = localangle2; aimingangle = localaiming2; } + else if (player == &players[thirddisplayplayer]) + { + viewangle = localangle3; + aimingangle = localaiming3; + } + else if (player == &players[fourthdisplayplayer]) + { + viewangle = localangle4; + aimingangle = localaiming4; + } } } viewz += quake.z; diff --git a/src/s_sound.c b/src/s_sound.c index e19f9265..8940a9b8 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -396,9 +396,13 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) listener_t listener = {0,0,0,0}; listener_t listener2 = {0,0,0,0}; + listener_t listener3 = {0,0,0,0}; + listener_t listener4 = {0,0,0,0}; mobj_t *listenmobj = players[displayplayer].mo; mobj_t *listenmobj2 = NULL; + mobj_t *listenmobj3 = NULL; + mobj_t *listenmobj4 = NULL; if (sound_disabled || !sound_started || nosound) return; @@ -410,13 +414,27 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (players[displayplayer].awayviewtics) listenmobj = players[displayplayer].awayviewmobj; - if (splitscreen) + if (splitscreen || splitscreen3 || splitscreen4) { listenmobj2 = players[secondarydisplayplayer].mo; if (players[secondarydisplayplayer].awayviewtics) listenmobj2 = players[secondarydisplayplayer].awayviewmobj; } + if (splitscreen3 || splitscreen4) + { + listenmobj3 = players[thirddisplayplayer].mo; + if (players[thirddisplayplayer].awayviewtics) + listenmobj3 = players[thirddisplayplayer].awayviewmobj; + } + + if (splitscreen4) + { + listenmobj4 = players[fourthdisplayplayer].mo; + if (players[fourthdisplayplayer].awayviewtics) + listenmobj4 = players[fourthdisplayplayer].awayviewmobj; + } + #ifdef HW3SOUND if (hws_mode != HWS_DEFAULT_MODE) { @@ -460,6 +478,42 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) } } + if (listenmobj3) + { + if (camera3.chase && !players[thirddisplayplayer].awayviewtics) + { + listener3.x = camera3.x; + listener3.y = camera3.y; + listener3.z = camera3.z; + listener3.angle = camera3.angle; + } + else + { + listener3.x = listenmobj3->x; + listener3.y = listenmobj3->y; + listener3.z = listenmobj3->z; + listener3.angle = listenmobj3->angle; + } + } + + if (listenmobj4) + { + if (camera4.chase && !players[fourthdisplayplayer].awayviewtics) + { + listener4.x = camera4.x; + listener4.y = camera4.y; + listener4.z = camera4.z; + listener4.angle = camera4.angle; + } + else + { + listener4.x = listenmobj4->x; + listener4.y = listenmobj4->y; + listener4.z = listenmobj4->z; + listener4.angle = listenmobj4->angle; + } + } + // check for bogus sound # I_Assert(sfx_id >= 1); I_Assert(sfx_id < NUMSFX); @@ -477,7 +531,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) pitch = NORM_PITCH; priority = NORM_PRIORITY; - if (splitscreen && listenmobj2) // Copy the sound for the split player + if ((splitscreen || splitscreen3 || splitscreen4) && listenmobj2) // Copy the sound for the split player { // Check to see if it is audible, and if not, modify the params if (origin && origin != listenmobj2) @@ -518,6 +572,116 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (sfx->usefulness++ < 0) sfx->usefulness = -1; +#ifdef SURROUND + // Avoid channel reverse if surround + if (stereoreverse.value && sep != SURROUND_SEP) + sep = (~sep) & 255; +#else + if (stereoreverse.value) + sep = (~sep) & 255; +#endif + + // Assigns the handle to one of the channels in the + // mix/output buffer. + channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); + } + + if ((splitscreen3 || splitscreen4) && listenmobj3) // Copy the sound for the third player + { + // Check to see if it is audible, and if not, modify the params + if (origin && origin != listenmobj3) + { + INT32 rc; + rc = S_AdjustSoundParams(listenmobj3, origin, &volume, &sep, &pitch, sfx); + + if (!rc) + goto dontplay; // Maybe the other player can hear it... + + if (origin->x == listener3.x && origin->y == listener3.y) + sep = NORM_SEP; + } + else if (!origin) + // Do not play origin-less sounds for the second player. + // The first player will be able to hear it just fine, + // we really don't want it playing twice. + goto dontplay; + else + sep = NORM_SEP; + + // try to find a channel + cnum = S_getChannel(origin, sfx); + + if (cnum < 0) + return; // If there's no free channels, it's not gonna be free for player 1, either. + + // This is supposed to handle the loading/caching. + // For some odd reason, the caching is done nearly + // each time the sound is needed? + + // cache data if necessary + // NOTE: set sfx->data NULL sfx->lump -1 to force a reload + if (!sfx->data) + sfx->data = I_GetSfx(sfx); + + // increase the usefulness + if (sfx->usefulness++ < 0) + sfx->usefulness = -1; + +#ifdef SURROUND + // Avoid channel reverse if surround + if (stereoreverse.value && sep != SURROUND_SEP) + sep = (~sep) & 255; +#else + if (stereoreverse.value) + sep = (~sep) & 255; +#endif + + // Assigns the handle to one of the channels in the + // mix/output buffer. + channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); + } + + if (splitscreen4 && listenmobj4) // Copy the sound for the split player + { + // Check to see if it is audible, and if not, modify the params + if (origin && origin != listenmobj4) + { + INT32 rc; + rc = S_AdjustSoundParams(listenmobj4, origin, &volume, &sep, &pitch, sfx); + + if (!rc) + goto dontplay; // Maybe the other player can hear it... + + if (origin->x == listener4.x && origin->y == listener4.y) + sep = NORM_SEP; + } + else if (!origin) + // Do not play origin-less sounds for the second player. + // The first player will be able to hear it just fine, + // we really don't want it playing twice. + goto dontplay; + else + sep = NORM_SEP; + + // try to find a channel + cnum = S_getChannel(origin, sfx); + + if (cnum < 0) + return; // If there's no free channels, it's not gonna be free for player 1, either. + + // This is supposed to handle the loading/caching. + // For some odd reason, the caching is done nearly + // each time the sound is needed? + + // cache data if necessary + // NOTE: set sfx->data NULL sfx->lump -1 to force a reload + if (!sfx->data) + sfx->data = I_GetSfx(sfx); + + // increase the usefulness + if (sfx->usefulness++ < 0) + sfx->usefulness = -1; + #ifdef SURROUND // Avoid channel reverse if surround if (stereoreverse.value && sep != SURROUND_SEP) @@ -691,12 +855,18 @@ void S_UpdateSounds(void) listener_t listener; listener_t listener2; + listener_t listener3; + listener_t listener4; mobj_t *listenmobj = players[displayplayer].mo; mobj_t *listenmobj2 = NULL; + mobj_t *listenmobj3 = NULL; + mobj_t *listenmobj4 = NULL; memset(&listener, 0, sizeof(listener_t)); memset(&listener2, 0, sizeof(listener_t)); + memset(&listener3, 0, sizeof(listener_t)); + memset(&listener4, 0, sizeof(listener_t)); // Update sound/music volumes, if changed manually at console if (actualsfxvolume != cv_soundvolume.value) @@ -725,13 +895,27 @@ void S_UpdateSounds(void) if (players[displayplayer].awayviewtics) listenmobj = players[displayplayer].awayviewmobj; - if (splitscreen) + if (splitscreen || splitscreen3 || splitscreen4) { listenmobj2 = players[secondarydisplayplayer].mo; if (players[secondarydisplayplayer].awayviewtics) listenmobj2 = players[secondarydisplayplayer].awayviewmobj; } + if (splitscreen3 || splitscreen4) + { + listenmobj3 = players[thirddisplayplayer].mo; + if (players[thirddisplayplayer].awayviewtics) + listenmobj3 = players[thirddisplayplayer].awayviewmobj; + } + + if (splitscreen4) + { + listenmobj4 = players[fourthdisplayplayer].mo; + if (players[fourthdisplayplayer].awayviewtics) + listenmobj4 = players[fourthdisplayplayer].awayviewmobj; + } + if (camera.chase && !players[displayplayer].awayviewtics) { listener.x = camera.x; @@ -778,6 +962,42 @@ void S_UpdateSounds(void) } } + if (listenmobj3) + { + if (camera3.chase && !players[thirddisplayplayer].awayviewtics) + { + listener3.x = camera3.x; + listener3.y = camera3.y; + listener3.z = camera3.z; + listener3.angle = camera3.angle; + } + else + { + listener3.x = listenmobj3->x; + listener3.y = listenmobj3->y; + listener3.z = listenmobj3->z; + listener3.angle = listenmobj3->angle; + } + } + + if (listenmobj4) + { + if (camera4.chase && !players[fourthdisplayplayer].awayviewtics) + { + listener4.x = camera4.x; + listener4.y = camera4.y; + listener4.z = camera4.z; + listener4.angle = camera4.angle; + } + else + { + listener4.x = listenmobj4->x; + listener4.y = listenmobj4->y; + listener4.z = listenmobj4->z; + listener4.angle = listenmobj4->angle; + } + } + for (cnum = 0; cnum < numofchannels; cnum++) { c = &channels[cnum]; @@ -793,11 +1013,13 @@ void S_UpdateSounds(void) // check non-local sounds for distance clipping // or modify their params - if (c->origin && ((c->origin != players[consoleplayer].mo) || - (splitscreen && c->origin != players[secondarydisplayplayer].mo))) + if (c->origin && ((c->origin != players[consoleplayer].mo) + || ((splitscreen || splitscreen3 || splitscreen4) && c->origin != players[secondarydisplayplayer].mo) + || ((splitscreen3 || splitscreen4) && c->origin != players[thirddisplayplayer].mo) + || (splitscreen4 && c->origin != players[fourthdisplayplayer].mo))) { // Whomever is closer gets the sound, but only in splitscreen. - if (listenmobj && listenmobj2 && splitscreen) + if (listenmobj && listenmobj2 && (splitscreen || splitscreen3 || splitscreen4)) { const mobj_t *soundmobj = c->origin; @@ -823,7 +1045,59 @@ void S_UpdateSounds(void) else S_StopChannel(cnum); } - else if (listenmobj && !splitscreen) + else if (listenmobj && listenmobj3 && (splitscreen3 || splitscreen4)) // TODO: make 3/4P compare their distances with all players, not just the first player and themselves V: + { + const mobj_t *soundmobj = c->origin; + + fixed_t dist1, dist2; + dist1 = P_AproxDistance(listener.x-soundmobj->x, listener.y-soundmobj->y); + dist2 = P_AproxDistance(listener3.x-soundmobj->x, listener3.y-soundmobj->y); + + if (dist1 <= dist2) + { + // Player 1 gets the sound + audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch, + c->sfxinfo); + } + else + { + // Player 3 gets the sound + audible = S_AdjustSoundParams(listenmobj3, c->origin, &volume, &sep, &pitch, + c->sfxinfo); + } + + if (audible) + I_UpdateSoundParams(c->handle, volume, sep, pitch); + else + S_StopChannel(cnum); + } + else if (listenmobj && listenmobj4 && splitscreen4) + { + const mobj_t *soundmobj = c->origin; + + fixed_t dist1, dist2; + dist1 = P_AproxDistance(listener.x-soundmobj->x, listener.y-soundmobj->y); + dist2 = P_AproxDistance(listener4.x-soundmobj->x, listener4.y-soundmobj->y); + + if (dist1 <= dist2) + { + // Player 1 gets the sound + audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch, + c->sfxinfo); + } + else + { + // Player 4 gets the sound + audible = S_AdjustSoundParams(listenmobj4, c->origin, &volume, &sep, &pitch, + c->sfxinfo); + } + + if (audible) + I_UpdateSoundParams(c->handle, volume, sep, pitch); + else + S_StopChannel(cnum); + } + else if (listenmobj && !(splitscreen || splitscreen3 || splitscreen4)) { // In the case of a single player, he or she always should get updated sound. audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch, @@ -949,13 +1223,27 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v listensource.z = camera.z; listensource.angle = camera.angle; } - else if (splitscreen && listener == players[secondarydisplayplayer].mo && camera2.chase) + else if ((splitscreen || splitscreen3 || splitscreen4) && listener == players[secondarydisplayplayer].mo && camera2.chase) { listensource.x = camera2.x; listensource.y = camera2.y; listensource.z = camera2.z; listensource.angle = camera2.angle; } + else if ((splitscreen3 || splitscreen4) && listener == players[thirddisplayplayer].mo && camera3.chase) + { + listensource.x = camera3.x; + listensource.y = camera3.y; + listensource.z = camera3.z; + listensource.angle = camera3.angle; + } + else if (splitscreen4 && listener == players[fourthdisplayplayer].mo && camera4.chase) + { + listensource.x = camera4.x; + listensource.y = camera4.y; + listensource.z = camera4.z; + listensource.angle = camera4.angle; + } else { listensource.x = listener->x; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 7f3f2791..298fa5f0 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -898,7 +898,8 @@ static void I_ShutdownJoystick(void) joystick_started = 0; JoyReset(&JoyInfo); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); if (cv_usejoystick.value == 0) @@ -1050,7 +1051,7 @@ static int joy_open(const char *fname) int num_joy = 0; int i; - if (joystick_started == 0 && joystick2_started == 0) + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) { @@ -1179,7 +1180,8 @@ static void I_ShutdownJoystick2(void) } JoyReset(&JoyInfo2); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); if (cv_usejoystick2.value == 0) @@ -1189,54 +1191,6 @@ static void I_ShutdownJoystick2(void) } } -/** \brief Shuts down joystick 3 - - -\return void -*/ -static void I_ShutdownJoystick3(void) -{ - INT32 i; - event_t event; - event.type = ev_keyup; - event.data2 = 0; - event.data3 = 0; - - lastjoy3buttons = lastjoy3hats = 0; - - // emulate the up of all joystick buttons - for (i = 0; i < JOYBUTTONS; i++) - { - event.data1 = KEY_2JOY1 + i; - D_PostEvent(&event); - } - - // emulate the up of all joystick hats - for (i = 0; i < JOYHATS*4; i++) - { - event.data1 = KEY_2HAT1 + i; - D_PostEvent(&event); - } - - // reset joystick position - event.type = ev_joystick3; - for (i = 0; i < JOYAXISSET; i++) - { - event.data1 = i; - D_PostEvent(&event); - } - - JoyReset(&JoyInfo3); - if (!joystick_started && !joystick3_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - if (cv_usejoystick3.value == 0) - { - DEBFILE("I_Joystick3: SDL's Joystick system has been shutdown\n"); - } - } -} - void I_GetJoystick2Events(void) { static event_t event = {0,0,0,0}; @@ -1382,7 +1336,7 @@ static int joy_open2(const char *fname) int num_joy = 0; int i; - if (joystick_started == 0 && joystick2_started == 0) + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) { @@ -1461,6 +1415,572 @@ static int joy_open2(const char *fname) } } +//Joystick3 + +/** \brief Joystick 3 buttons states +*/ +static UINT64 lastjoy3buttons = 0; + +/** \brief Joystick 3 hats state +*/ +static UINT64 lastjoy3hats = 0; + +/** \brief Shuts down joystick 3 + + +\return void +*/ +static void I_ShutdownJoystick3(void) +{ + INT32 i; + event_t event; + event.type = ev_keyup; + event.data2 = 0; + event.data3 = 0; + + lastjoy3buttons = lastjoy3hats = 0; + + // emulate the up of all joystick buttons + for (i = 0; i < JOYBUTTONS; i++) + { + event.data1 = KEY_3JOY1 + i; + D_PostEvent(&event); + } + + // emulate the up of all joystick hats + for (i = 0; i < JOYHATS*4; i++) + { + event.data1 = KEY_3HAT1 + i; + D_PostEvent(&event); + } + + // reset joystick position + event.type = ev_joystick3; + for (i = 0; i < JOYAXISSET; i++) + { + event.data1 = i; + D_PostEvent(&event); + } + + JoyReset(&JoyInfo3); + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + if (cv_usejoystick3.value == 0) + { + DEBFILE("I_Joystick3: SDL's Joystick system has been shutdown\n"); + } + } +} + +void I_GetJoystick3Events(void) +{ + static event_t event = {0,0,0,0}; + INT32 i = 0; + UINT64 joyhats = 0; +#if 0 + INT64 joybuttons = 0; +#endif + INT32 axisx, axisy; + + if (!joystick3_started) + return; + + if (!JoyInfo3.dev) //I_ShutdownJoystick3(); + return; + + +#if 0 + //faB: look for as much buttons as g_input code supports, + // we don't use the others + for (i = JoyInfo3.buttons - 1; i >= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo3.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoy3buttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoy3buttons; + lastjoy3buttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_3JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo3.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo3.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoy3hats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoy3hats; + lastjoy3hats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_3HAT1 + i; + D_PostEvent(&event); + } + } + } + + // send joystick axis positions + event.type = ev_joystick3; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.data1 = i; + if (i*2 + 1 <= JoyInfo3.axises) + axisx = SDL_JoystickGetAxis(JoyInfo3.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo3.axises) + axisy = SDL_JoystickGetAxis(JoyInfo3.dev, i*2 + 1); + else axisy = 0; + + // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; + + if (Joystick3.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.data2 = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.data2 = 1; + else + event.data2 = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.data3 = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.data3 = 1; + else + event.data3 = 0; + } + else + { + + axisx = JoyInfo3.scale?((axisx/JoyInfo3.scale)*JoyInfo3.scale):axisx; + axisy = JoyInfo3.scale?((axisy/JoyInfo3.scale)*JoyInfo3.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.data2 = axisx; // x axis + event.data3 = axisy; // y axis + } + D_PostEvent(&event); + } + +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open3(const char *fname) +{ + int joyindex = atoi(fname); + int num_joy = 0; + int i; + + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) + { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return -1; + } + else + num_joy = SDL_NumJoysticks(); + + if (num_joy < joyindex) + { + CONS_Printf(M_GetText("Cannot use joystick #%d/(%s), it doesn't exist\n"),joyindex,fname); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); + I_ShutdownJoystick3(); + return -1; + } + } + else + { + JoyReset(&JoyInfo3); + //I_ShutdownJoystick(); + //joy_open(fname); + } + + num_joy = SDL_NumJoysticks(); + + if (joyindex <= 0 || num_joy == 0 || JoyInfo3.oldjoy == joyindex) + { +// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); + if (num_joy != 0) + { + CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); + } + else + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + if (joyindex <= 0 || num_joy == 0) return 0; + } + + JoyInfo3.dev = SDL_JoystickOpen(joyindex-1); + + if (!JoyInfo3.dev) + { + CONS_Printf(M_GetText("Couldn't open joystick3: %s\n"), SDL_GetError()); + I_ShutdownJoystick3(); + return -1; + } + else + { + CONS_Printf(M_GetText("Joystick3: %s\n"), SDL_JoystickName(JoyInfo3.dev)); + JoyInfo3.axises = SDL_JoystickNumAxes(JoyInfo3.dev); + if (JoyInfo3.axises > JOYAXISSET*2) + JoyInfo3.axises = JOYAXISSET*2; +/* if (joyaxes < 2) + { + I_OutputMsg("Not enought axes?\n"); + I_ShutdownJoystick3(); + return 0; + }*/ + + JoyInfo3.buttons = SDL_JoystickNumButtons(JoyInfo3.dev); + if (JoyInfo3.buttons > JOYBUTTONS) + JoyInfo3.buttons = JOYBUTTONS; + + JoyInfo3.hats = SDL_JoystickNumHats(JoyInfo3.dev); + if (JoyInfo3.hats > JOYHATS) + JoyInfo3.hats = JOYHATS; + + JoyInfo3.balls = SDL_JoystickNumBalls(JoyInfo3.dev); + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo3.dev), "pad"); + + return JoyInfo3.axises; + } +} + +//Joystick4 + +/** \brief Joystick 4 buttons states +*/ +static UINT64 lastjoy4buttons = 0; + +/** \brief Joystick 4 hats state +*/ +static UINT64 lastjoy4hats = 0; + +/** \brief Shuts down joystick 4 + + +\return void +*/ +static void I_ShutdownJoystick4(void) +{ + INT32 i; + event_t event; + event.type = ev_keyup; + event.data2 = 0; + event.data3 = 0; + + lastjoy4buttons = lastjoy4hats = 0; + + // emulate the up of all joystick buttons + for (i = 0; i < JOYBUTTONS; i++) + { + event.data1 = KEY_4JOY1 + i; + D_PostEvent(&event); + } + + // emulate the up of all joystick hats + for (i = 0; i < JOYHATS*4; i++) + { + event.data1 = KEY_4HAT1 + i; + D_PostEvent(&event); + } + + // reset joystick position + event.type = ev_joystick4; + for (i = 0; i < JOYAXISSET; i++) + { + event.data1 = i; + D_PostEvent(&event); + } + + JoyReset(&JoyInfo4); + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + if (cv_usejoystick4.value == 0) + { + DEBFILE("I_Joystick3: SDL's Joystick system has been shutdown\n"); + } + } +} + +void I_GetJoystick4Events(void) +{ + static event_t event = {0,0,0,0}; + INT32 i = 0; + UINT64 joyhats = 0; +#if 0 + INT64 joybuttons = 0; +#endif + INT32 axisx, axisy; + + if (!joystick4_started) + return; + + if (!JoyInfo4.dev) //I_ShutdownJoystick4(); + return; + + +#if 0 + //faB: look for as much buttons as g_input code supports, + // we don't use the others + for (i = JoyInfo4.buttons - 1; i >= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo4.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoy4buttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoy4buttons; + lastjoy4buttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_4JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo4.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo4.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoy4hats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoy4hats; + lastjoy4hats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_4HAT1 + i; + D_PostEvent(&event); + } + } + } + + // send joystick axis positions + event.type = ev_joystick4; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.data1 = i; + if (i*2 + 1 <= JoyInfo4.axises) + axisx = SDL_JoystickGetAxis(JoyInfo4.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo4.axises) + axisy = SDL_JoystickGetAxis(JoyInfo4.dev, i*2 + 1); + else axisy = 0; + + // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; + + if (Joystick4.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.data2 = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.data2 = 1; + else + event.data2 = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.data3 = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.data3 = 1; + else + event.data3 = 0; + } + else + { + + axisx = JoyInfo4.scale?((axisx/JoyInfo4.scale)*JoyInfo4.scale):axisx; + axisy = JoyInfo4.scale?((axisy/JoyInfo4.scale)*JoyInfo4.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.data2 = axisx; // x axis + event.data3 = axisy; // y axis + } + D_PostEvent(&event); + } + +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open4(const char *fname) +{ + int joyindex = atoi(fname); + int num_joy = 0; + int i; + + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) + { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return -1; + } + else + num_joy = SDL_NumJoysticks(); + + if (num_joy < joyindex) + { + CONS_Printf(M_GetText("Cannot use joystick #%d/(%s), it doesn't exist\n"),joyindex,fname); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); + I_ShutdownJoystick4(); + return -1; + } + } + else + { + JoyReset(&JoyInfo4); + //I_ShutdownJoystick(); + //joy_open(fname); + } + + num_joy = SDL_NumJoysticks(); + + if (joyindex <= 0 || num_joy == 0 || JoyInfo4.oldjoy == joyindex) + { +// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); + if (num_joy != 0) + { + CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); + } + else + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + if (joyindex <= 0 || num_joy == 0) return 0; + } + + JoyInfo4.dev = SDL_JoystickOpen(joyindex-1); + + if (!JoyInfo4.dev) + { + CONS_Printf(M_GetText("Couldn't open joystick4: %s\n"), SDL_GetError()); + I_ShutdownJoystick3(); + return -1; + } + else + { + CONS_Printf(M_GetText("Joystick4: %s\n"), SDL_JoystickName(JoyInfo4.dev)); + JoyInfo3.axises = SDL_JoystickNumAxes(JoyInfo4.dev); + if (JoyInfo4.axises > JOYAXISSET*2) + JoyInfo4.axises = JOYAXISSET*2; +/* if (joyaxes < 2) + { + I_OutputMsg("Not enought axes?\n"); + I_ShutdownJoystick4(); + return 0; + }*/ + + JoyInfo4.buttons = SDL_JoystickNumButtons(JoyInfo4.dev); + if (JoyInfo4.buttons > JOYBUTTONS) + JoyInfo4.buttons = JOYBUTTONS; + + JoyInfo4.hats = SDL_JoystickNumHats(JoyInfo4.dev); + if (JoyInfo4.hats > JOYHATS) + JoyInfo4.hats = JOYHATS; + + JoyInfo4.balls = SDL_JoystickNumBalls(JoyInfo4.dev); + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo4.dev), "pad"); + + return JoyInfo4.axises; + } +} + // // I_InitJoystick // @@ -1498,34 +2018,34 @@ void I_InitJoystick2(void) void I_InitJoystick3(void) { - //I_ShutdownJoystick3(); + I_ShutdownJoystick3(); SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); if (!strcmp(cv_usejoystick3.string, "0") || M_CheckParm("-nojoy")) return; - /*if (joy_open3(cv_usejoystick3.string) != -1) + if (joy_open3(cv_usejoystick3.string) != -1) JoyInfo3.oldjoy = atoi(cv_usejoystick3.string); else { cv_usejoystick3.value = 0; return; } - joystick3_started = 1;*/ + joystick3_started = 1; } void I_InitJoystick4(void) { - //I_ShutdownJoystick4(); + I_ShutdownJoystick4(); SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); if (!strcmp(cv_usejoystick3.string, "0") || M_CheckParm("-nojoy")) return; - /*if (joy_open4(cv_usejoystick4.string) != -1) + if (joy_open4(cv_usejoystick4.string) != -1) JoyInfo4.oldjoy = atoi(cv_usejoystick4.string); else { cv_usejoystick4.value = 0; return; } - joystick4_started = 1;*/ + joystick4_started = 1; } static void I_ShutdownInput(void) diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index 8a6e63da..9058cc4d 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -291,6 +291,25 @@ static INT32 joystick2_started = 0; */ SDLJoyInfo_t JoyInfo2; + +/** \brief Third joystick up and running +*/ +static INT32 joystick3_started = 0; + +/** \brief SDL inof about joystick 3 +*/ +SDLJoyInfo_t JoyInfo3; + + +/** \brief Fourth joystick up and running +*/ +static INT32 joystick4_started = 0; + +/** \brief SDL inof about joystick 4 +*/ +SDLJoyInfo_t JoyInfo4; + + #ifdef HAVE_TERMIOS static INT32 fdmouse2 = -1; static INT32 mouse2_started = 0; @@ -930,6 +949,28 @@ void I_JoyScale2(void) JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value; } +void I_JoyScale3(void) +{ +#ifdef GP2X + if (JoyInfo3.dev && SDL_JoystickIndex(JoyInfo3.dev) == 0) + Joystick.bGamepadStyle = true; + else +#endif + Joystick3.bGamepadStyle = cv_joyscale3.value==0; + JoyInfo3.scale = Joystick3.bGamepadStyle?1:cv_joyscale3.value; +} + +void I_JoyScale4(void) +{ +#ifdef GP2X + if (JoyInfo4.dev && SDL_JoystickIndex(JoyInfo4.dev) == 0) + Joystick.bGamepadStyle = true; + else +#endif + Joystick4.bGamepadStyle = cv_joyscale4.value==0; + JoyInfo4.scale = Joystick4.bGamepadStyle?1:cv_joyscale4.value; +} + /** \brief Joystick 1 buttons states */ static UINT64 lastjoybuttons = 0; @@ -979,7 +1020,8 @@ static void I_ShutdownJoystick(void) joystick_started = 0; JoyReset(&JoyInfo); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); if (cv_usejoystick.value == 0) @@ -1140,7 +1182,7 @@ static int joy_open(const char *fname) int num_joy = 0; int i; - if (joystick_started == 0 && joystick2_started == 0) + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) { @@ -1273,7 +1315,8 @@ static void I_ShutdownJoystick2(void) } JoyReset(&JoyInfo2); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); if (cv_usejoystick2.value == 0) @@ -1434,7 +1477,7 @@ static int joy_open2(const char *fname) int num_joy = 0; int i; - if (joystick_started == 0 && joystick2_started == 0) + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) { if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) { @@ -1457,7 +1500,7 @@ static int joy_open2(const char *fname) { JoyReset(&JoyInfo2); //I_ShutdownJoystick(); - //joy_open(fname); + //joy_open2(fname); } num_joy = SDL_NumJoysticks(); @@ -1517,6 +1560,592 @@ static int joy_open2(const char *fname) } } +//Joystick3 + +/** \brief Joystick 3 buttons states +*/ +static UINT64 lastjoy3buttons = 0; + +/** \brief Joystick 3 hats state +*/ +static UINT64 lastjoy3hats = 0; + +/** \brief Shuts down joystick 3 + + + \return void +*/ +static void I_ShutdownJoystick3(void) +{ + INT32 i; + event_t event; + event.type = ev_keyup; + event.data2 = 0; + event.data3 = 0; + + lastjoy3buttons = lastjoy3hats = 0; + + // emulate the up of all joystick buttons + for (i = 0; i < JOYBUTTONS; i++) + { + event.data1 = KEY_3JOY1 + i; + D_PostEvent(&event); + } + + // emulate the up of all joystick hats + for (i = 0; i < JOYHATS*4; i++) + { + event.data1 = KEY_3HAT1 + i; + D_PostEvent(&event); + } + + // reset joystick position + event.type = ev_joystick3; + for (i = 0; i < JOYAXISSET; i++) + { + event.data1 = i; + D_PostEvent(&event); + } + + JoyReset(&JoyInfo3); + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + if (cv_usejoystick3.value == 0) + { + DEBFILE("I_Joystick3: SDL's Joystick system has been shutdown\n"); + } + } +} + +void I_GetJoystick3Events(void) +{ + static event_t event = {0,0,0,0}; + INT32 i = 0; + UINT64 joyhats = 0; +#if 0 + INT64 joybuttons = 0; + INT32 axisx, axisy; +#endif + + if (!joystick3_started) + return; + + if (!JoyInfo3.dev) //I_ShutdownJoystick3(); + return; + + +#if 0 + //faB: look for as much buttons as g_input code supports, + // we don't use the others + for (i = JoyInfo3.buttons - 1; i >= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo3.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoy3buttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoy3buttons; + lastjoy3buttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_3JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo3.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo3.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoy3hats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoy3hats; + lastjoy3hats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_3HAT1 + i; + D_PostEvent(&event); + } + } + } + +#if 0 + // send joystick axis positions + event.type = ev_joystick3; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.data1 = i; + if (i*2 + 1 <= JoyInfo3.axises) + axisx = SDL_JoystickGetAxis(JoyInfo3.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo3.axises) + axisy = SDL_JoystickGetAxis(JoyInfo3.dev, i*2 + 1); + else axisy = 0; + +#ifdef _arch_dreamcast // -128 to 127 + axisx = axisx*8; + axisy = axisy*8; +#else // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; +#endif + + if (Joystick3.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.data2 = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.data2 = 1; + else + event.data2 = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.data3 = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.data3 = 1; + else + event.data3 = 0; + } + else + { + + axisx = JoyInfo3.scale?((axisx/JoyInfo3.scale)*JoyInfo3.scale):axisx; + axisy = JoyInfo3.scale?((axisy/JoyInfo3.scale)*JoyInfo3.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.data2 = axisx; // x axis + event.data3 = axisy; // y axis + } + D_PostEvent(&event); + } +#endif + +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open3(const char *fname) +{ + int joyindex = atoi(fname); + int num_joy = 0; + int i; + + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) + { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return -1; + } + else + num_joy = SDL_NumJoysticks(); + + if (num_joy < joyindex) + { + CONS_Printf(M_GetText("Cannot use joystick #%d/(%s), it doesn't exist\n"),joyindex,fname); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickName(i)); + I_ShutdownJoystick3(); + return -1; + } + } + else + { + JoyReset(&JoyInfo3); + //I_ShutdownJoystick(); + //joy_open3(fname); + } + + num_joy = SDL_NumJoysticks(); + + if (joyindex <= 0 || num_joy == 0 || JoyInfo3.oldjoy == joyindex) + { +// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); + if (num_joy != 0) + { + CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickName(i)); + } + else + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + if (joyindex <= 0 || num_joy == 0) return 0; + } + + JoyInfo3.dev = SDL_JoystickOpen(joyindex-1); + CONS_Printf(M_GetText("Joystick3: %s\n"), SDL_JoystickName(joyindex-1)); + + if (!JoyInfo3.dev) + { + CONS_Printf(M_GetText("Couldn't open joystick3: %s\n"), SDL_GetError()); + I_ShutdownJoystick3(); + return -1; + } + else + { + JoyInfo3.axises = SDL_JoystickNumAxes(JoyInfo3.dev); + if (JoyInfo3.axises > JOYAXISSET*2) + JoyInfo3.axises = JOYAXISSET*2; +/* if (joyaxes < 2) + { + I_OutputMsg("Not enought axes?\n"); + I_ShutdownJoystick3(); + return 0; + }*/ + + JoyInfo3.buttons = SDL_JoystickNumButtons(JoyInfo3.dev); + if (JoyInfo3.buttons > JOYBUTTONS) + JoyInfo3.buttons = JOYBUTTONS; + +#ifdef DC + JoyInfo3.hats = 0; +#else + JoyInfo3.hats = SDL_JoystickNumHats(JoyInfo3.dev); + if (JoyInfo3.hats > JOYHATS) + JoyInfo3.hats = JOYHATS; + + JoyInfo3.balls = SDL_JoystickNumBalls(JoyInfo3.dev); +#endif + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(SDL_JoystickIndex(JoyInfo3.dev)), "pad"); + + return JoyInfo3.axises; + } +} + +//Joystick4 + +/** \brief Joystick 4 buttons states +*/ +static UINT64 lastjoy4buttons = 0; + +/** \brief Joystick 4 hats state +*/ +static UINT64 lastjoy4hats = 0; + +/** \brief Shuts down joystick 4 + + + \return void +*/ +static void I_ShutdownJoystick4(void) +{ + INT32 i; + event_t event; + event.type = ev_keyup; + event.data2 = 0; + event.data3 = 0; + + lastjoy4buttons = lastjoy4hats = 0; + + // emulate the up of all joystick buttons + for (i = 0; i < JOYBUTTONS; i++) + { + event.data1 = KEY_4JOY1 + i; + D_PostEvent(&event); + } + + // emulate the up of all joystick hats + for (i = 0; i < JOYHATS*4; i++) + { + event.data1 = KEY_4HAT1 + i; + D_PostEvent(&event); + } + + // reset joystick position + event.type = ev_joystick4; + for (i = 0; i < JOYAXISSET; i++) + { + event.data1 = i; + D_PostEvent(&event); + } + + JoyReset(&JoyInfo4); + if (!joystick_started && !joystick2_started && !joystick3_started && !joystick4_started + && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) + { + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + if (cv_usejoystick4.value == 0) + { + DEBFILE("I_Joystick3: SDL's Joystick system has been shutdown\n"); + } + } +} + +void I_GetJoystick4Events(void) +{ + static event_t event = {0,0,0,0}; + INT32 i = 0; + UINT64 joyhats = 0; +#if 0 + INT64 joybuttons = 0; + INT32 axisx, axisy; +#endif + + if (!joystick4_started) + return; + + if (!JoyInfo4.dev) //I_ShutdownJoystick4(); + return; + + +#if 0 + //faB: look for as much buttons as g_input code supports, + // we don't use the others + for (i = JoyInfo4.buttons - 1; i >= 0; i--) + { + joybuttons <<= 1; + if (SDL_JoystickGetButton(JoyInfo4.dev,i)) + joybuttons |= 1; + } + + if (joybuttons != lastjoy4buttons) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newbuttons = joybuttons ^ lastjoy4buttons; + lastjoy4buttons = joybuttons; + + for (i = 0; i < JOYBUTTONS; i++, j <<= 1) + { + if (newbuttons & j) // button changed state? + { + if (joybuttons & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_4JOY1 + i; + D_PostEvent(&event); + } + } + } +#endif + + for (i = JoyInfo4.hats - 1; i >= 0; i--) + { + Uint8 hat = SDL_JoystickGetHat(JoyInfo4.dev, i); + + if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i); + if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i); + if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i); + if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i); + } + + if (joyhats != lastjoy4hats) + { + INT64 j = 1; // keep only bits that changed since last time + INT64 newhats = joyhats ^ lastjoy4hats; + lastjoy4hats = joyhats; + + for (i = 0; i < JOYHATS*4; i++, j <<= 1) + { + if (newhats & j) // hat changed state? + { + if (joyhats & j) + event.type = ev_keydown; + else + event.type = ev_keyup; + event.data1 = KEY_4HAT1 + i; + D_PostEvent(&event); + } + } + } + +#if 0 + // send joystick axis positions + event.type = ev_joystick4; + + for (i = JOYAXISSET - 1; i >= 0; i--) + { + event.data1 = i; + if (i*2 + 1 <= JoyInfo4.axises) + axisx = SDL_JoystickGetAxis(JoyInfo4.dev, i*2 + 0); + else axisx = 0; + if (i*2 + 2 <= JoyInfo4.axises) + axisy = SDL_JoystickGetAxis(JoyInfo4.dev, i*2 + 1); + else axisy = 0; + +#ifdef _arch_dreamcast // -128 to 127 + axisx = axisx*8; + axisy = axisy*8; +#else // -32768 to 32767 + axisx = axisx/32; + axisy = axisy/32; +#endif + + if (Joystick4.bGamepadStyle) + { + // gamepad control type, on or off, live or die + if (axisx < -(JOYAXISRANGE/2)) + event.data2 = -1; + else if (axisx > (JOYAXISRANGE/2)) + event.data2 = 1; + else + event.data2 = 0; + if (axisy < -(JOYAXISRANGE/2)) + event.data3 = -1; + else if (axisy > (JOYAXISRANGE/2)) + event.data3 = 1; + else + event.data3 = 0; + } + else + { + + axisx = JoyInfo4.scale?((axisx/JoyInfo4.scale)*JoyInfo4.scale):axisx; + axisy = JoyInfo4.scale?((axisy/JoyInfo4.scale)*JoyInfo4.scale):axisy; + +#ifdef SDL_JDEADZONE + if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0; + if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0; +#endif + + // analog control style , just send the raw data + event.data2 = axisx; // x axis + event.data3 = axisy; // y axis + } + D_PostEvent(&event); + } +#endif + +} + +/** \brief Open joystick handle + + \param fname name of joystick + + \return axises + + +*/ +static int joy_open4(const char *fname) +{ + int joyindex = atoi(fname); + int num_joy = 0; + int i; + + if (joystick_started == 0 && joystick2_started == 0 && joystick3_started == 0 && joystick4_started == 0) + { + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return -1; + } + else + num_joy = SDL_NumJoysticks(); + + if (num_joy < joyindex) + { + CONS_Printf(M_GetText("Cannot use joystick #%d/(%s), it doesn't exist\n"),joyindex,fname); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickName(i)); + I_ShutdownJoystick3(); + return -1; + } + } + else + { + JoyReset(&JoyInfo4); + //I_ShutdownJoystick(); + //joy_open4(fname); + } + + num_joy = SDL_NumJoysticks(); + + if (joyindex <= 0 || num_joy == 0 || JoyInfo4.oldjoy == joyindex) + { +// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); + if (num_joy != 0) + { + CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); + for (i = 0; i < num_joy; i++) + CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickName(i)); + } + else + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + if (joyindex <= 0 || num_joy == 0) return 0; + } + + JoyInfo4.dev = SDL_JoystickOpen(joyindex-1); + CONS_Printf(M_GetText("Joystick4: %s\n"), SDL_JoystickName(joyindex-1)); + + if (!JoyInfo4.dev) + { + CONS_Printf(M_GetText("Couldn't open joystick4: %s\n"), SDL_GetError()); + I_ShutdownJoystick4(); + return -1; + } + else + { + JoyInfo4.axises = SDL_JoystickNumAxes(JoyInfo4.dev); + if (JoyInfo4.axises > JOYAXISSET*2) + JoyInfo4.axises = JOYAXISSET*2; +/* if (joyaxes < 2) + { + I_OutputMsg("Not enought axes?\n"); + I_ShutdownJoystick4(); + return 0; + }*/ + + JoyInfo4.buttons = SDL_JoystickNumButtons(JoyInfo4.dev); + if (JoyInfo4.buttons > JOYBUTTONS) + JoyInfo4.buttons = JOYBUTTONS; + +#ifdef DC + JoyInfo4.hats = 0; +#else + JoyInfo4.hats = SDL_JoystickNumHats(JoyInfo4.dev); + if (JoyInfo4.hats > JOYHATS) + JoyInfo4.hats = JOYHATS; + + JoyInfo4.balls = SDL_JoystickNumBalls(JoyInfo4.dev); +#endif + + //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(SDL_JoystickIndex(JoyInfo4.dev)), "pad"); + + return JoyInfo4.axises; + } +} + // // I_InitJoystick // @@ -1550,12 +2179,44 @@ void I_InitJoystick2(void) joystick2_started = 1; } +void I_InitJoystick3(void) +{ + I_ShutdownJoystick3(); + if (!strcmp(cv_usejoystick3.string, "0") || M_CheckParm("-nojoy")) + return; + if (joy_open3(cv_usejoystick3.string) != -1) + JoyInfo3.oldjoy = atoi(cv_usejoystick3.string); + else + { + cv_usejoystick3.value = 0; + return; + } + joystick3_started = 1; +} + +void I_InitJoystick4(void) +{ + I_ShutdownJoystick4(); + if (!strcmp(cv_usejoystick4.string, "0") || M_CheckParm("-nojoy")) + return; + if (joy_open4(cv_usejoystick4.string) != -1) + JoyInfo4.oldjoy = atoi(cv_usejoystick4.string); + else + { + cv_usejoystick4.value = 0; + return; + } + joystick4_started = 1; +} + static void I_ShutdownInput(void) { if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { JoyReset(&JoyInfo); JoyReset(&JoyInfo2); + JoyReset(&JoyInfo3); + JoyReset(&JoyInfo4); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } diff --git a/src/st_stuff.c b/src/st_stuff.c index 15343adc..3ea045ca 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1893,7 +1893,9 @@ static void ST_overlayDrawer(void) // This is where we draw all the fun cheese if you have the chasecam off! if ((stplyr == &players[displayplayer] && !camera.chase) - || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)) + || (((splitscreen || splitscreen3 || splitscreen4) && stplyr == &players[secondarydisplayplayer]) && !camera2.chase) + || (((splitscreen3 || splitscreen4) && stplyr == &players[thirddisplayplayer]) && !camera3.chase) + || ((splitscreen4 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase)) { ST_drawFirstPersonHUD(); }