From 1d6215030eb02a611a0f20aff44055264cf41240 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 00:51:03 -0400 Subject: [PATCH 01/36] Online splitscreen It WORKS, including kicking players in splitscreen --- src/d_clisrv.c | 112 ++++++++++++++---------------------------------- src/d_netcmd.c | 114 +++++++++++++++++++++++++++++++++++++++++++++---- src/r_main.c | 10 ----- 3 files changed, 136 insertions(+), 100 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 63393690..3c934e3b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2419,14 +2419,15 @@ static void CL_RemovePlayer(INT32 playernum) if (server && !demoplayback) { INT32 node = playernode[playernum]; + //playerpernode[node] = 0; // It'd be better to remove them all at once, but ghosting happened, so continue to let CL_RemovePlayer do it one-by-one playerpernode[node]--; if (playerpernode[node] <= 0) { // If a resynch was in progress, well, it no longer needs to be. SV_InitResynchVars(playernode[playernum]); - nodeingame[playernode[playernum]] = false; - Net_CloseConnection(playernode[playernum]); + nodeingame[node] = false; + Net_CloseConnection(node); ResetNode(node); } } @@ -2761,11 +2762,7 @@ 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 - || nodetoplayer3[playernode[playernum]] == pnum - || nodetoplayer4[playernode[playernum]] == pnum))) + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { // We received a kick command from someone who isn't the // server or admin, and who isn't in splitscreen removing @@ -2777,12 +2774,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // "consistency failure" and kicking the offending user // instead. - // Note: Splitscreen in netgames is broken because of - // this. Only the server has any idea of which players - // are using splitscreen on the same computer, so - // clients cannot always determine if a kick is - // legitimate. - CONS_Alert(CONS_WARNING, M_GetText("Illegal kick command received from %s for player %d\n"), player_names[playernum], pnum); // In debug, print a longer message with more details. @@ -2892,7 +2883,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) break; } - if (pnum == consoleplayer) + if (playernode[pnum] == playernode[consoleplayer]) { #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); @@ -2916,7 +2907,18 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); } else - CL_RemovePlayer(pnum); + { + UINT8 splitnode = playernode[pnum]; + // Can't tell which player pnum is on the node from a glance, so we have to convert to node, then check each player on the node + if (nodetoplayer[splitnode] != -1) + CL_RemovePlayer(nodetoplayer[splitnode]); + if (nodetoplayer2[splitnode] != -1) + CL_RemovePlayer(nodetoplayer2[splitnode]); + if (nodetoplayer3[splitnode] != -1) + CL_RemovePlayer(nodetoplayer3[splitnode]); + if (nodetoplayer4[splitnode] != -1) + CL_RemovePlayer(nodetoplayer4[splitnode]); + } } consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; @@ -3156,7 +3158,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 && !botingame) + //if (!splitscreen && !botingame) CL_ClearPlayer(newplayernum); playeringame[newplayernum] = true; G_AddPlayer(newplayernum); @@ -3256,69 +3258,17 @@ static boolean SV_AddWaitingPlayers(void) { newplayer = true; - if (netgame) - // !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!! - // - // The line just after that comment is an awful, horrible, terrible, TERRIBLE hack. - // - // Basically, the fix I did in order to fix the download freezes happens - // to cause situations in which a player number does not match - // the node number associated to that player. - // That is totally normal, there is absolutely *nothing* wrong with that. - // Really. Player 7 being tied to node 29, for instance, is totally fine. - // - // HOWEVER. A few (broken) parts of the netcode do the TERRIBLE mistake - // of mixing up the concepts of node and player, resulting in - // incorrect handling of cases where a player is tied to a node that has - // a different number (which is a totally normal case, or at least should be). - // This incorrect handling can go as far as literally - // anyone from joining your server at all, forever. - // - // Given those two facts, there are two options available - // in order to let this download freeze fix be: - // 1) Fix the broken parts that assume a node is a player or similar bullshit. - // 2) Change the part this comment is located at, so that any player who joins - // is given the same number as their associated node. - // - // No need to say, 1) is by far the obvious best, whereas 2) is a terrible hack. - // Unfortunately, after trying 1), I most likely didn't manage to find all - // of those broken parts, and thus 2) has become the only safe option that remains. - // - // So I did this hack. - // - // If it isn't clear enough, in order to get rid of this ugly hack, - // you will have to fix all parts of the netcode that - // make a confusion between nodes and players. - // - // And if it STILL isn't clear enough, a node and a player - // is NOT the same thing. Never. NEVER. *NEVER*. - // - // And if someday you make the terrible mistake of - // daring to have the unforgivable idea to try thinking - // that a node might possibly be the same as a player, - // or that a player should have the same number as its node, - // be sure that I will somehow know about it and - // hunt you down tirelessly and make you regret it, - // even if you live on the other side of the world. - // - // TODO: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // \todo >>>>>>>>>> Remove this horrible hack as soon as possible <<<<<<<<<< - // TODO: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!! - newplayernum = node; // OMFG SAY WELCOME TO TEH NEW HACK FOR FIX FIL DOWNLOAD!!1! - else // Don't use the hack if we don't have to - // search for a free playernum - // we can't use playeringame since it is not updated here - for (; newplayernum < MAXPLAYERS; newplayernum++) - { - for (n = 0; n < MAXNETNODES; n++) - if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum - || nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum) - break; - if (n == MAXNETNODES) + // search for a free playernum + // we can't use playeringame since it is not updated here + for (; newplayernum < MAXPLAYERS; newplayernum++) + { + for (n = 0; n < MAXNETNODES; n++) + if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum + || nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum) break; - } + if (n == MAXNETNODES) + break; + } // should never happen since we check the playernum // before accepting the join @@ -3493,7 +3443,7 @@ static void HandleConnect(SINT8 node) SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment")); else if (D_NumPlayers() >= cv_maxplayers.value) SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value)); - else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client? + else if (netgame && netbuffer->u.clientcfg.localplayers > 4) // Hacked client? SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join? SV_SendRefuse(node, M_GetText("No players from\nthis node.")); @@ -3979,10 +3929,10 @@ FILESTAMP --resynch_score[node]; break; case PT_TEXTCMD: - case PT_TEXTCMD2: // splitscreen special + case PT_TEXTCMD2: case PT_TEXTCMD3: case PT_TEXTCMD4: - if (netbuffer->packettype == PT_TEXTCMD2) + if (netbuffer->packettype == PT_TEXTCMD2) // splitscreen special netconsole = nodetoplayer2[node]; else if (netbuffer->packettype == PT_TEXTCMD3) netconsole = nodetoplayer3[node]; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 144e4bf9..ea913b06 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1350,16 +1350,23 @@ static void SendNameAndColor(void) // splitscreen static void SendNameAndColor2(void) { - INT32 secondplaya; + INT32 secondplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 1 && !botingame) return; // can happen if skin2/color2/name2 changed if (secondarydisplayplayer != consoleplayer) secondplaya = secondarydisplayplayer; - else // HACK + else if (!netgame) // HACK secondplaya = 1; + if (secondplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1436,21 +1443,53 @@ static void SendNameAndColor2(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac2pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(secondarydisplayplayer))) + CV_StealthSet(&cv_playername2, player_names[secondarydisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(secondarydisplayplayer, cv_playername2.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(secondarydisplayplayer)) + CV_StealthSet(&cv_skin2, skins[players[secondarydisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin2 may have + // the name of a skin that was available in the previous game) + cv_skin2.value = R_SkinAvailable(cv_skin2.string); + if (cv_skin2.value < 0) + { + CV_StealthSet(&cv_skin2, DEFAULTSKIN); + cv_skin2.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername2.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor2.value); + WRITEUINT8(p, (UINT8)cv_skin2.value); + SendNetXCmd2(XD_NAMEANDCOLOR, buf, p - buf); } static void SendNameAndColor3(void) { - INT32 thirdplaya; + INT32 thirdplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 2) return; // can happen if skin3/color3/name3 changed if (thirddisplayplayer != consoleplayer) thirdplaya = thirddisplayplayer; - else // HACK + else if (!netgame) // HACK thirdplaya = 2; + if (thirdplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1519,21 +1558,53 @@ static void SendNameAndColor3(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac3pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(thirddisplayplayer))) + CV_StealthSet(&cv_playername3, player_names[thirddisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(thirddisplayplayer, cv_playername3.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(thirddisplayplayer)) + CV_StealthSet(&cv_skin3, skins[players[thirddisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin3 may have + // the name of a skin that was available in the previous game) + cv_skin3.value = R_SkinAvailable(cv_skin3.string); + if (cv_skin3.value < 0) + { + CV_StealthSet(&cv_skin3, DEFAULTSKIN); + cv_skin3.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername3.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor3.value); + WRITEUINT8(p, (UINT8)cv_skin3.value); + SendNetXCmd3(XD_NAMEANDCOLOR, buf, p - buf); } static void SendNameAndColor4(void) { - INT32 fourthplaya; + INT32 fourthplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 3) return; // can happen if skin4/color4/name4 changed if (fourthdisplayplayer != consoleplayer) fourthplaya = fourthdisplayplayer; - else // HACK + else if (!netgame) // HACK fourthplaya = 3; + if (fourthplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1610,7 +1681,32 @@ static void SendNameAndColor4(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac4pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(fourthdisplayplayer))) + CV_StealthSet(&cv_playername4, player_names[fourthdisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(fourthdisplayplayer, cv_playername4.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(fourthdisplayplayer)) + CV_StealthSet(&cv_skin4, skins[players[fourthdisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin4 may have + // the name of a skin that was available in the previous game) + cv_skin4.value = R_SkinAvailable(cv_skin4.string); + if (cv_skin4.value < 0) + { + CV_StealthSet(&cv_skin4, DEFAULTSKIN); + cv_skin4.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername4.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor4.value); + WRITEUINT8(p, (UINT8)cv_skin4.value); + SendNetXCmd4(XD_NAMEANDCOLOR, buf, p - buf); } static void Got_NameAndColor(UINT8 **cp, INT32 playernum) diff --git a/src/r_main.c b/src/r_main.c index 5990224c..11213a27 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -178,16 +178,6 @@ void SplitScreen_OnChange(void) { UINT8 i; - if (!cv_debug && netgame) - { - if (splitscreen) - { - CONS_Alert(CONS_NOTICE, M_GetText("Splitscreen not supported in netplay, sorry!\n")); - splitscreen = 0; - } - return; - } - // recompute screen size R_ExecuteSetViewSize(); From 3c567b39f118bce4798315b90c6dbc578f497aaa Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 01:23:59 -0400 Subject: [PATCH 02/36] Minor splitscreen+netgame fixes Mainly related to drawing Battle arrows or Hyudoro --- src/k_kart.c | 4 +++- src/k_kart.h | 1 + src/lua_baselib.c | 14 ++++++++++++++ src/p_mobj.c | 10 ++++------ src/p_user.c | 4 ++-- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ed91616b..105e8055 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4852,8 +4852,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->mo->eflags |= MFE_DRAWONLYFORP3; else if (player == &players[fourthdisplayplayer] && splitscreen > 2) player->mo->eflags |= MFE_DRAWONLYFORP4; - else + else if (player == &players[consoleplayer]) player->mo->eflags |= MFE_DRAWONLYFORP1; + else + player->mo->flags2 |= MF2_DONTDRAW; } else player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); diff --git a/src/k_kart.h b/src/k_kart.h index 7c37ef67..7906bad8 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -21,6 +21,7 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); boolean K_IsPlayerWanted(player_t *player); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); void K_RespawnChecker(player_t *player); void K_KartMoveAnimation(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7c44c796..da524de7 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2091,6 +2091,19 @@ static int lib_kKartBouncing(lua_State *L) return 0; } +static int lib_kMatchGenericExtraFlags(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *master = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + NOHUD + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + if (!master) + return LUA_ErrInvalid(L, "mobj_t"); + K_MatchGenericExtraFlags(mo, master); + return 0; +} + static int lib_kDoInstashield(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2487,6 +2500,7 @@ static luaL_Reg lib[] = { {"K_IsPlayerLosing",lib_kIsPlayerLosing}, {"K_IsPlayerWanted",lib_kIsPlayerWanted}, {"K_KartBouncing",lib_kKartBouncing}, + {"K_MatchGenericExtraFlags",lib_kMatchGenericExtraFlags}, {"K_DoInstashield",lib_kDoInstashield}, {"K_SpinPlayer",lib_kSpinPlayer}, {"K_SquishPlayer",lib_kSquishPlayer}, diff --git a/src/p_mobj.c b/src/p_mobj.c index 0f065733..5c341737 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6802,17 +6802,15 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->health && mobj->target->player && !mobj->target->player->spectator && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - && players[displayplayer].mo && !players[displayplayer].spectator) + /*&& players[displayplayer].mo && !players[displayplayer].spectator*/) { fixed_t scale = mobj->target->scale; mobj->color = mobj->target->color; + K_MatchGenericExtraFlags(mobj, mobj->target); - if (G_RaceGametype() - || mobj->target->player == &players[displayplayer] - || mobj->target->player->kartstuff[k_bumper] <= 0 - || (mobj->target->player->mo->flags2 & MF2_DONTDRAW) + if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) #if 1 // Set to 0 to test without needing to host - || !netgame + || ((mobj->target->player == &players[displayplayer]) || P_IsLocalPlayer(mobj->target->player)) #endif ) mobj->flags2 |= MF2_DONTDRAW; diff --git a/src/p_user.c b/src/p_user.c index d3407bd6..1b63e35c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8973,7 +8973,7 @@ void P_PlayerThink(player_t *player) } #ifdef SEENAMES - if (netgame && player == &players[displayplayer] && !(leveltime % (TICRATE/5))) + if (netgame && player == &players[displayplayer] && !(leveltime % (TICRATE/5)) && !splitscreen) { seenplayer = NULL; @@ -9194,7 +9194,7 @@ void P_PlayerThink(player_t *player) } } - if ((netgame || splitscreen) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) + if ((netgame || multiplayer) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) { player->pflags ^= PF_WANTSTOJOIN; //player->powers[pw_flashing] = TICRATE + 1; From fc93e5812da21f87d84696b4d1c68f2d942a8118 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 01:51:49 -0400 Subject: [PATCH 03/36] Add a message for when multiple players on one node get removed Example: Chrome has been kicked (Go away) Shadow has left the game (Joined with Chrome) Kryne has left the game (Joined with Chrome) Vyce has left the game (Joined with Chrome) --- src/d_clisrv.c | 30 ++++++++++++++++++++---------- src/k_kart.c | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3c934e3b..99a08c6c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2892,7 +2892,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_Reset(); D_StartTitle(); if (msg == KICK_MSG_CON_FAIL) - M_StartMessage(M_GetText("Server closed connection\n(synch failure)\nPress ESC\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING); #ifdef NEWPING else if (msg == KICK_MSG_PING_HIGH) M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); @@ -2909,15 +2909,25 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) else { UINT8 splitnode = playernode[pnum]; - // Can't tell which player pnum is on the node from a glance, so we have to convert to node, then check each player on the node - if (nodetoplayer[splitnode] != -1) - CL_RemovePlayer(nodetoplayer[splitnode]); - if (nodetoplayer2[splitnode] != -1) - CL_RemovePlayer(nodetoplayer2[splitnode]); - if (nodetoplayer3[splitnode] != -1) - CL_RemovePlayer(nodetoplayer3[splitnode]); - if (nodetoplayer4[splitnode] != -1) - CL_RemovePlayer(nodetoplayer4[splitnode]); + + // Sal: Because kicks (and a lot of other commands) are player-based, we can't tell which player pnum is on the node from a glance. + // When we want to remove everyone from a node, we have to get the kicked player's node, then remove everyone on that node manually so we don't miss any. + // This avoids the old bugs with older SRB2 version's online splitscreen kicks, and means we can keep it in now! :D + +#define removethisplayer(otherp) \ + if (otherp >= 0) \ + { \ + if (otherp != pnum) \ + CONS_Printf("\x82%s\x80 left the game (Joined with \x82%s\x80)\n", player_names[otherp], player_names[pnum]); \ + CL_RemovePlayer(otherp); \ + } + + removethisplayer(nodetoplayer[splitnode]) + removethisplayer(nodetoplayer2[splitnode]) + removethisplayer(nodetoplayer3[splitnode]) + removethisplayer(nodetoplayer4[splitnode]) + +#undef removethisplayer } } diff --git a/src/k_kart.c b/src/k_kart.c index 105e8055..61630879 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1250,7 +1250,7 @@ static void K_UpdateOffroad(player_t *player) } // These have to go earlier than its sisters because of K_RespawnChecker... -static void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master) +void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master) { // flipping mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP)|(master->eflags & MFE_VERTICALFLIP); From 5628ffe3606bef161ad1aae282613009f76a930f Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 11:21:41 -0400 Subject: [PATCH 04/36] HUD debugger (no cvar yet) --- src/k_kart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index 61630879..b7732c97 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7434,6 +7434,12 @@ void K_drawKartHUD(void) if (cv_kartdebugcheckpoint.value) K_drawCheckpointDebugger(); + + { + UINT8 p; + for (p = 0; p < MAXPLAYERS; p++) + V_DrawString(8, 64+(8*p), V_YELLOWMAP, va("%d - %d", p, playernode[p])); + } } //} From 847924a47aa95a9a6a8ca089ff82cb082a2785c4 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 11:22:10 -0400 Subject: [PATCH 05/36] Let's try what that comment suggests. --- src/d_clisrv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 99a08c6c..3c46c0e7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2424,7 +2424,7 @@ static void CL_RemovePlayer(INT32 playernum) if (playerpernode[node] <= 0) { // If a resynch was in progress, well, it no longer needs to be. - SV_InitResynchVars(playernode[playernum]); + SV_InitResynchVars(node); nodeingame[node] = false; Net_CloseConnection(node); @@ -3487,6 +3487,7 @@ static void HandleConnect(SINT8 node) /// \note Shouldn't SV_SendRefuse be called before ResetNode? ResetNode(node); SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); + ResetNode(node); // Yeah, lets try it! /// \todo fix this !!! return; // restart the while } From f858b2aa116f9910ced4aecf8b9e6ee9fefaefab Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 11:22:31 -0400 Subject: [PATCH 06/36] RIP, didn't commit this --- src/d_clisrv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3c46c0e7..43f93b7d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3485,7 +3485,6 @@ static void HandleConnect(SINT8 node) { G_SetGamestate(backupstate); /// \note Shouldn't SV_SendRefuse be called before ResetNode? - ResetNode(node); SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); ResetNode(node); // Yeah, lets try it! /// \todo fix this !!! From d705d2a606c93684952ab0d20810146516c81fb1 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 11:22:56 -0400 Subject: [PATCH 07/36] Temporary testing measure set splitscreen = 3 on host or connect --- src/d_clisrv.c | 2 +- src/m_menu.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 43f93b7d..92374e0d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2377,7 +2377,7 @@ static void Command_connect(void) CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); } - splitscreen = 0; + splitscreen = 3; // TEMPORARY TESTING MEASURE SplitScreen_OnChange(); botingame = false; botskin = 0; diff --git a/src/m_menu.c b/src/m_menu.c index 5d0448ce..243ec30d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7419,6 +7419,7 @@ static void M_StartServer(INT32 choice) if (ssplayers < 1) { + splitscreen = 3; SplitScreen_OnChange(); // TEMPORARY TESTING MEASURE D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); COM_BufAddText("dummyconsvar 1\n"); } From 7d8891f0572fef9803547c46fb54ec001ecf0aad Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 12:12:12 -0400 Subject: [PATCH 08/36] Instead of directly using CL_RemovePlayer, do a silly loop around Hopefully I don't have to keep this, just have to see if it works --- src/d_clisrv.c | 37 ++++++++++++++++++++++--------------- src/d_clisrv.h | 1 + 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 92374e0d..5a69df24 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2870,6 +2870,9 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (netgame) // not splitscreen/bots CONS_Printf(M_GetText("left the game\n")); break; + case KICK_MSG_SPLITSCREEN: + CONS_Printf(M_GetText("left the game (Splitscreen session)\n")); + break; case KICK_MSG_BANNED: CONS_Printf(M_GetText("has been banned (Don't come back)\n")); break; @@ -2885,6 +2888,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (playernode[pnum] == playernode[consoleplayer]) { + if (msg == KICK_MSG_SPLITSCREEN) return; #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); #endif @@ -2908,26 +2912,30 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } else { - UINT8 splitnode = playernode[pnum]; + CL_RemovePlayer(pnum); // Sal: Because kicks (and a lot of other commands) are player-based, we can't tell which player pnum is on the node from a glance. // When we want to remove everyone from a node, we have to get the kicked player's node, then remove everyone on that node manually so we don't miss any. - // This avoids the old bugs with older SRB2 version's online splitscreen kicks, and means we can keep it in now! :D + // This avoids the bugs with older SRB2 version's online splitscreen kicks, specifically ghosting. + // On top of this, it can't just be a CL_RemovePlayer call; it has to be a server-side kick. + // Clients don't bother setting any nodes for anything but THE server player (even ignoring the server's extra players!), so it'll often remove everyone because they all have node -1/255, insta-desync! + if (server) + { + XBOXSTATIC UINT8 buf[2]; #define removethisplayer(otherp) \ - if (otherp >= 0) \ + if (otherp != -1 && otherp != pnum) \ { \ - if (otherp != pnum) \ - CONS_Printf("\x82%s\x80 left the game (Joined with \x82%s\x80)\n", player_names[otherp], player_names[pnum]); \ - CL_RemovePlayer(otherp); \ + buf[0] = (UINT8)otherp; \ + buf[1] = KICK_MSG_SPLITSCREEN; \ + SendNetXCmd(XD_KICK, &buf, 2); \ } - - removethisplayer(nodetoplayer[splitnode]) - removethisplayer(nodetoplayer2[splitnode]) - removethisplayer(nodetoplayer3[splitnode]) - removethisplayer(nodetoplayer4[splitnode]) - + removethisplayer(nodetoplayer[playernode[pnum]]) + removethisplayer(nodetoplayer2[playernode[pnum]]) + removethisplayer(nodetoplayer3[playernode[pnum]]) + removethisplayer(nodetoplayer4[playernode[pnum]]) #undef removethisplayer + } } } @@ -3167,9 +3175,8 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) newplayernum %= MAXPLAYERS; // Clear player before joining, lest some things get set incorrectly - // HACK: don't do this for splitscreen, it relies on preset values - //if (!splitscreen && !botingame) - CL_ClearPlayer(newplayernum); + CL_ClearPlayer(newplayernum); + playeringame[newplayernum] = true; G_AddPlayer(newplayernum); if (newplayernum+1 > doomcom->numslots) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index c8e8b008..97141ac2 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -480,6 +480,7 @@ extern consvar_t cv_playbackspeed; #endif #define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_BAN 8 +#define KICK_MSG_SPLITSCREEN 9 extern boolean server; #define client (!server) From 56ec3d0465e69ebe7bb4398505e04ee9e69758dc Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 12:19:26 -0400 Subject: [PATCH 09/36] Probably should do this too... --- src/d_clisrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5a69df24..b41848f9 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2920,7 +2920,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // On top of this, it can't just be a CL_RemovePlayer call; it has to be a server-side kick. // Clients don't bother setting any nodes for anything but THE server player (even ignoring the server's extra players!), so it'll often remove everyone because they all have node -1/255, insta-desync! - if (server) + if (server && msg != KICK_MSG_SPLITSCREEN) { XBOXSTATIC UINT8 buf[2]; #define removethisplayer(otherp) \ From 4da5c165f4316b9ea2f6421cd5dcb4ba44b6267b Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 16:20:01 -0400 Subject: [PATCH 10/36] Fix all of the joining ghost issues or desyncing The answer was so obvious! Just add a XD that just calls CL_RemovePlayer! Duh! --- src/d_clisrv.c | 60 ++++++++++++++++++++++++++++++++------------------ src/d_clisrv.h | 1 - src/d_netcmd.h | 5 +++-- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b41848f9..66bde9bd 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2870,9 +2870,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (netgame) // not splitscreen/bots CONS_Printf(M_GetText("left the game\n")); break; - case KICK_MSG_SPLITSCREEN: - CONS_Printf(M_GetText("left the game (Splitscreen session)\n")); - break; case KICK_MSG_BANNED: CONS_Printf(M_GetText("has been banned (Don't come back)\n")); break; @@ -2888,7 +2885,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (playernode[pnum] == playernode[consoleplayer]) { - if (msg == KICK_MSG_SPLITSCREEN) return; #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); #endif @@ -2910,32 +2906,31 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) else M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); } - else + else if (server) { - CL_RemovePlayer(pnum); + XBOXSTATIC UINT8 buf[0]; // Sal: Because kicks (and a lot of other commands) are player-based, we can't tell which player pnum is on the node from a glance. // When we want to remove everyone from a node, we have to get the kicked player's node, then remove everyone on that node manually so we don't miss any. // This avoids the bugs with older SRB2 version's online splitscreen kicks, specifically ghosting. - // On top of this, it can't just be a CL_RemovePlayer call; it has to be a server-side kick. + // On top of this, it can't just be a CL_RemovePlayer call; it has to be a server-sided. // Clients don't bother setting any nodes for anything but THE server player (even ignoring the server's extra players!), so it'll often remove everyone because they all have node -1/255, insta-desync! + // And yes. This is a netxcmd wrap for just CL_RemovePlayer! :V - if (server && msg != KICK_MSG_SPLITSCREEN) - { - XBOXSTATIC UINT8 buf[2]; #define removethisplayer(otherp) \ - if (otherp != -1 && otherp != pnum) \ + if (otherp >= 0) \ { \ + if (otherp != pnum) \ + CONS_Printf("\x82%s\x80 left the game (Joined with \x82%s\x80)\n", player_names[otherp], player_names[pnum]); \ buf[0] = (UINT8)otherp; \ - buf[1] = KICK_MSG_SPLITSCREEN; \ - SendNetXCmd(XD_KICK, &buf, 2); \ + SendNetXCmd(XD_REMOVEPLAYER, &buf, 1); \ + otherp = -1; \ } - removethisplayer(nodetoplayer[playernode[pnum]]) - removethisplayer(nodetoplayer2[playernode[pnum]]) - removethisplayer(nodetoplayer3[playernode[pnum]]) - removethisplayer(nodetoplayer4[playernode[pnum]]) + removethisplayer(nodetoplayer[playernode[pnum]]) + removethisplayer(nodetoplayer2[playernode[pnum]]) + removethisplayer(nodetoplayer3[playernode[pnum]]) + removethisplayer(nodetoplayer4[playernode[pnum]]) #undef removethisplayer - } } } @@ -2957,6 +2952,7 @@ static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static void Got_AddPlayer(UINT8 **p, INT32 playernum); +static void Got_RemovePlayer(UINT8 **p, INT32 playernum); // called one time at init void D_ClientServerInit(void) @@ -2984,6 +2980,7 @@ void D_ClientServerInit(void) RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); + RegisterNetXCmd(XD_REMOVEPLAYER, Got_RemovePlayer); #ifndef NONET CV_RegisterVar(&cv_allownewplayer); CV_RegisterVar(&cv_joinnextround); @@ -3258,6 +3255,27 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) #endif } +// Xcmd XD_REMOVEPLAYER +static void Got_RemovePlayer(UINT8 **p, INT32 playernum) +{ + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + { + // protect against hacked/buggy client + CONS_Alert(CONS_WARNING, M_GetText("Illegal remove player command received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + CL_RemovePlayer(READUINT8(*p)); +} + static boolean SV_AddWaitingPlayers(void) { INT32 node, n, newplayer = false; @@ -4036,9 +4054,9 @@ FILESTAMP else buf[1] = KICK_MSG_PLAYER_QUIT; SendNetXCmd(XD_KICK, &buf, 2); - nodetoplayer[node] = -1; + //nodetoplayer[node] = -1; - if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 + /*if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 && playeringame[(UINT8)nodetoplayer2[node]]) { buf[0] = nodetoplayer2[node]; @@ -4060,7 +4078,7 @@ FILESTAMP buf[0] = nodetoplayer4[node]; SendNetXCmd(XD_KICK, &buf, 2); nodetoplayer4[node] = -1; - } + }*/ } Net_CloseConnection(node); nodeingame[node] = false; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 97141ac2..c8e8b008 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -480,7 +480,6 @@ extern consvar_t cv_playbackspeed; #endif #define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_BAN 8 -#define KICK_MSG_SPLITSCREEN 9 extern boolean server; #define client (!server) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index aee243cf..cbe3512a 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -197,9 +197,10 @@ typedef enum XD_SETUPVOTE, // 22 XD_MODIFYVOTE, // 23 XD_PICKVOTE, // 24 + XD_REMOVEPLAYER,// 25 #ifdef HAVE_BLUA - XD_LUACMD, // 25 - XD_LUAVAR, // 26 + XD_LUACMD, // 26 + XD_LUAVAR, // 27 #endif MAXNETXCMD } netxcmd_t; From ad06b3c62f54c531578fd7a1fbbf848bf50f2c64 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 16:35:05 -0400 Subject: [PATCH 11/36] Proper G_GametypeHasSpectators for netgame splits --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index e501fa56..d2f4cee7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3132,7 +3132,7 @@ boolean G_GametypeHasSpectators(void) #if 0 return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); #else - return (!splitscreen);//true; + return (multiplayer && !netgame); //true #endif } From bc807dccc4b07ceb629679cb23cf4b3501c7cbd6 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 17:09:59 -0400 Subject: [PATCH 12/36] Sorta messy menu to set splitscreen Now this branch is completely functional! --- src/m_menu.c | 123 ++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 243ec30d..be757473 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -246,6 +246,7 @@ static void M_ConfirmTeamChange(INT32 choice); static void M_SetupChoosePlayer(INT32 choice); static void M_QuitSRB2(INT32 choice); menu_t SP_MainDef, MP_MainDef, OP_MainDef; +menu_t MP_SetPlayersDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; // Single Player @@ -271,7 +272,7 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); #endif -static void M_StartSplitServerMenu(INT32 choice); +static void M_StartOfflineServerMenu(INT32 choice); static void M_StartServer(INT32 choice); #ifndef NONET static void M_Refresh(INT32 choice); @@ -463,8 +464,8 @@ consvar_t cv_ghost_staff = {"ghost_staff", "Show", CV_SAVE, ghost2_cons_ // or make these consvars legitimate like color or skin. #ifndef NOFOURPLAYER static void Dummysplitplayers_OnChange(void); -static CV_PossibleValue_t dummysplitplayers_cons_t[] = {{2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; -static consvar_t cv_dummysplitplayers = {"dummysplitplayers", "Two", CV_HIDEN|CV_CALL, dummysplitplayers_cons_t, Dummysplitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t dummysplitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; +static consvar_t cv_dummysplitplayers = {"dummysplitplayers", "One", CV_HIDEN|CV_CALL, dummysplitplayers_cons_t, Dummysplitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; @@ -500,12 +501,7 @@ static menuitem_t MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, -#ifdef NONET -M_StartSplitServerMenu - {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu, 92}, -#else - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, -#endif + {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_SetPlayersDef, 92}, {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, @@ -949,16 +945,35 @@ menuitem_t PlayerMenu[32] = #ifndef NONET +// Set number of players first! +static menuitem_t MP_SetPlayersMenu[] = +{ +#ifndef NOFOURPLAYER + {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_dummysplitplayers, 10}, +#endif + +#ifdef NOFOURPLAYER + {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 90}, + {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 100}, +#else + {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 80}, + {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 90}, + {IT_GRAYEDOUT, NULL, "P3 Setup...", M_SetupMultiPlayer3, 100}, + {IT_GRAYEDOUT, NULL, "P4 Setup... ", M_SetupMultiPlayer4, 110}, +#endif + {IT_SUBMENU|IT_STRING, NULL, "Next...", &MP_MainDef, 130}, +}; + static menuitem_t MP_MainMenu[] = { {IT_HEADER, NULL, "Host a game", NULL, 0}, - {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 10}, - {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 18}, + {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 10}, + {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 18}, {IT_HEADER, NULL, "Join a game", NULL, 32}, - {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenu, 42}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 50}, - {IT_HEADER, NULL, "Player setup", NULL, 80}, - {IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, + {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 42}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 50}, + //{IT_HEADER, NULL, "Player setup", NULL, 80}, + //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, }; #endif @@ -977,38 +992,26 @@ static menuitem_t MP_ServerMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; -// Separated splitscreen and normal servers. -static menuitem_t MP_SplitServerMenu[] = +// Separated offline and normal servers. +static menuitem_t MP_OfflineServerMenu[] = { -#ifndef NOFOURPLAYER - {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_dummysplitplayers, 10}, -#endif - {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, -#ifdef NOFOURPLAYER - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 110}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 120}, -#else - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 90}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 100}, - {IT_GRAYEDOUT, NULL, "P3 Setup...", M_SetupMultiPlayer3, 110}, - {IT_GRAYEDOUT, NULL, "P4 Setup... ", M_SetupMultiPlayer4, 120}, -#endif + {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; #ifndef NOFOURPLAYER static void Dummysplitplayers_OnChange(void) { - UINT8 i = 2; // player 2 is the last unchanging setup + UINT8 i = 1; // player 1 is the last unchanging setup while (i < 4) { if (i < cv_dummysplitplayers.value) - MP_SplitServerMenu[3+i].status = IT_STRING|IT_CALL; + MP_SetPlayersMenu[i+1].status = IT_STRING|IT_CALL; else - MP_SplitServerMenu[3+i].status = IT_GRAYEDOUT; + MP_SetPlayersMenu[i+1].status = IT_GRAYEDOUT; i++; } } @@ -1890,7 +1893,7 @@ menu_t MP_MainDef = { "M_MULTI", sizeof (MP_MainMenu)/sizeof (menuitem_t), - &MainDef, + &MP_SetPlayersDef, MP_MainMenu, M_DrawMPMainMenu, 42, 50, @@ -1899,7 +1902,8 @@ menu_t MP_MainDef = }; menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); #endif -menu_t MP_SplitServerDef = MAPICONMENUSTYLE("M_MULTI", MP_SplitServerMenu, &MP_MainDef); +menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); +menu_t MP_SetPlayersDef = MAPICONMENUSTYLE("M_MULTI", MP_SetPlayersMenu, &MainDef); #ifndef NONET menu_t MP_ConnectDef = { @@ -7390,17 +7394,17 @@ static INT32 M_FindFirstMap(INT32 gtype) static void M_StartServer(INT32 choice) { - UINT8 ssplayers = 0; + UINT8 ssplayers = +#ifdef NOFOURPLAYER + 1; +#else + cv_dummysplitplayers.value-1; +#endif (void)choice; - if (currentMenu == &MP_SplitServerDef) - ssplayers = -#ifdef NOFOURPLAYER - 1; -#else - cv_dummysplitplayers.value-1; -#endif + if (currentMenu == &MP_OfflineServerDef) + netgame = false; else netgame = true; @@ -7417,25 +7421,23 @@ static void M_StartServer(INT32 choice) if (!cv_nextmap.value) CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)+1); - if (ssplayers < 1) + if (splitscreen != ssplayers) { - splitscreen = 3; SplitScreen_OnChange(); // TEMPORARY TESTING MEASURE - D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); - COM_BufAddText("dummyconsvar 1\n"); + splitscreen = ssplayers; + SplitScreen_OnChange(); } - else // split screen + + if (currentMenu == &MP_OfflineServerDef) // offline server { paused = false; SV_StartSinglePlayerServer(); - - if (splitscreen != ssplayers) - { - splitscreen = ssplayers; - SplitScreen_OnChange(); - } - D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); } + else + { + D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); + COM_BufAddText("dummyconsvar 1\n"); + } M_ClearMenus(true); } @@ -7571,7 +7573,8 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) static void M_DrawServerMenu(void) { - M_DrawLevelSelectOnly((currentMenu == &MP_SplitServerDef), false); + if (currentMenu != &MP_SetPlayersDef) + M_DrawLevelSelectOnly(false, false); M_DrawGenericMenu(); #ifndef NONET @@ -7581,7 +7584,7 @@ static void M_DrawServerMenu(void) #define mp_server_room 1 if (ms_RoomId < 0) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, - highlightflags, (itemOn == mp_server_room) ? "" : ""); else V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, highlightflags, room_list[menuRoomIndex].name); @@ -7589,7 +7592,7 @@ static void M_DrawServerMenu(void) } else #endif - if (currentMenu == &MP_SplitServerDef) + if (currentMenu == &MP_SetPlayersDef) // character bar, ripped off the color bar :V { #define iconwidth 32 @@ -7664,12 +7667,12 @@ static void M_MapChange(INT32 choice) M_SetupNextMenu(&MISC_ChangeLevelDef); } -static void M_StartSplitServerMenu(INT32 choice) +static void M_StartOfflineServerMenu(INT32 choice) { (void)choice; levellistmode = LLM_CREATESERVER; M_PrepareLevelSelect(); - M_SetupNextMenu(&MP_SplitServerDef); + M_SetupNextMenu(&MP_OfflineServerDef); } #ifndef NONET From 5132c31e0fcb6c5f9f9c611f7bad249a24e970ee Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 17:17:33 -0400 Subject: [PATCH 13/36] I have no idea if this is an actual problem or not, but this was in the back of my mind from day 1 --- src/m_menu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index be757473..45803c6c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7421,6 +7421,9 @@ static void M_StartServer(INT32 choice) if (!cv_nextmap.value) CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)+1); + if (cv_maxplayers.value < ssplayers+1) + CV_SetValue(&cv_maxplayers, ssplayers+1); + if (splitscreen != ssplayers) { splitscreen = ssplayers; From 9cf379f091c4813f52a8cf665a6c7b39737a2989 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 17:47:56 -0400 Subject: [PATCH 14/36] kartdebugnodes --- src/d_netcmd.c | 1 + src/d_netcmd.h | 2 +- src/k_kart.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index ea913b06..582649eb 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -375,6 +375,7 @@ consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR| consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugcheckpoint = {"kartdebugcheckpoint", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartdebugnodes = {"kartdebugnodes", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}}; consvar_t cv_votetime = {"votetime", "20", CV_NETVAR, votetime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index cbe3512a..dfa5c83c 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -134,7 +134,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_votetime; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; -extern consvar_t cv_kartdebugcheckpoint; +extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes; extern consvar_t cv_itemfinder; diff --git a/src/k_kart.c b/src/k_kart.c index b7732c97..c22dec0c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -442,6 +442,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebughuddrop); CV_RegisterVar(&cv_kartdebugcheckpoint); + CV_RegisterVar(&cv_kartdebugnodes); } //} @@ -7435,6 +7436,7 @@ void K_drawKartHUD(void) if (cv_kartdebugcheckpoint.value) K_drawCheckpointDebugger(); + if (cv_kartdebugnodes.value) { UINT8 p; for (p = 0; p < MAXPLAYERS; p++) From a4f3d4867da9f3f8c5c81142742c5af19f0dae70 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 18:07:05 -0400 Subject: [PATCH 15/36] Change dummysplitplayers into splitplayers, unhide it, and set it when joining and not just hosting Silly oversight --- src/d_clisrv.c | 7 +++++-- src/d_netcmd.c | 2 ++ src/g_game.h | 1 + src/m_menu.c | 18 +++++++++--------- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 66bde9bd..1385bfcc 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2377,8 +2377,11 @@ static void Command_connect(void) CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); } - splitscreen = 3; // TEMPORARY TESTING MEASURE - SplitScreen_OnChange(); + if (splitscreen != cv_splitplayers.value-1) + { + splitscreen = cv_splitplayers.value-1; + SplitScreen_OnChange(); + } botingame = false; botskin = 0; CL_ConnectToServer(viams); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 582649eb..975f7701 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -759,6 +759,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_playername4); CV_RegisterVar(&cv_playercolor4); CV_RegisterVar(&cv_skin4); + // preferred number of players + CV_RegisterVar(&cv_splitplayers); #ifdef SEENAMES CV_RegisterVar(&cv_seenames); diff --git a/src/g_game.h b/src/g_game.h index 10eb4c68..40e21035 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -62,6 +62,7 @@ extern consvar_t cv_turnaxis2,cv_moveaxis2,cv_brakeaxis2,cv_aimaxis2,cv_lookaxis extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis3,cv_fireaxis3,cv_driftaxis3; extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4; extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff; +extern consvar_t cv_splitplayers; typedef enum { diff --git a/src/m_menu.c b/src/m_menu.c index 45803c6c..f4f5ae3e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -463,9 +463,9 @@ consvar_t cv_ghost_staff = {"ghost_staff", "Show", CV_SAVE, ghost2_cons_ //todo: add a way to use non-console variables in the menu // or make these consvars legitimate like color or skin. #ifndef NOFOURPLAYER -static void Dummysplitplayers_OnChange(void); -static CV_PossibleValue_t dummysplitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; -static consvar_t cv_dummysplitplayers = {"dummysplitplayers", "One", CV_HIDEN|CV_CALL, dummysplitplayers_cons_t, Dummysplitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static void Splitplayers_OnChange(void); +CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; +consvar_t cv_splitplayers = {"splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; @@ -949,7 +949,7 @@ menuitem_t PlayerMenu[32] = static menuitem_t MP_SetPlayersMenu[] = { #ifndef NOFOURPLAYER - {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_dummysplitplayers, 10}, + {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_splitplayers, 10}, #endif #ifdef NOFOURPLAYER @@ -1002,13 +1002,13 @@ static menuitem_t MP_OfflineServerMenu[] = }; #ifndef NOFOURPLAYER -static void Dummysplitplayers_OnChange(void) +static void Splitplayers_OnChange(void) { UINT8 i = 1; // player 1 is the last unchanging setup while (i < 4) { - if (i < cv_dummysplitplayers.value) + if (i < cv_splitplayers.value) MP_SetPlayersMenu[i+1].status = IT_STRING|IT_CALL; else MP_SetPlayersMenu[i+1].status = IT_GRAYEDOUT; @@ -3144,7 +3144,7 @@ void M_Init(void) // Menu hacks #ifndef NOFOURPLAYER - CV_RegisterVar(&cv_dummysplitplayers); + CV_RegisterVar(&cv_splitplayers); #endif CV_RegisterVar(&cv_dummyteam); CV_RegisterVar(&cv_dummyscramble); @@ -7398,7 +7398,7 @@ static void M_StartServer(INT32 choice) #ifdef NOFOURPLAYER 1; #else - cv_dummysplitplayers.value-1; + cv_splitplayers.value-1; #endif (void)choice; @@ -7643,7 +7643,7 @@ static void M_DrawServerMenu(void) pskin = 0; #ifndef NOFOURPLAYER - if (!trans && i > cv_dummysplitplayers.value) + if (!trans && i > cv_splitplayers.value) trans = V_TRANSLUCENT; #endif From 71e40f68cdacf3fbb573e4b97bb1d356dc58d90c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 30 Sep 2018 21:47:04 -0400 Subject: [PATCH 16/36] Foolish error --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index d2f4cee7..b5ba6f06 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3132,7 +3132,7 @@ boolean G_GametypeHasSpectators(void) #if 0 return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); #else - return (multiplayer && !netgame); //true + return (netgame); //true #endif } From f5eee19d9bd18865a699d4b3edab142a07e97584 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 01:22:45 -0400 Subject: [PATCH 17/36] Online splitscreen voting Forgot I added in that quick edit to make it not send anything in splitscreen mode, oops! --- src/d_netcmd.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 975f7701..48c1835b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2109,16 +2109,20 @@ void D_SetupVote(void) void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer) { - char buf[1]; + char buf[2]; char *p = buf; + UINT8 player = consoleplayer; - if (splitplayer > 0) // Don't actually send anything for splitscreen - votes[splitplayer] = voted; - else - { - WRITESINT8(p, voted); - SendNetXCmd(XD_MODIFYVOTE, &buf, 1); - } + if (splitplayer == 1) + player = secondarydisplayplayer; + else if (splitplayer == 2) + player = thirddisplayplayer; + else if (splitplayer == 3) + player = fourthdisplayplayer; + + WRITESINT8(p, voted); + WRITEUINT8(p, player); + SendNetXCmd(XD_MODIFYVOTE, &buf, 2); } void D_PickVote(void) @@ -4722,7 +4726,10 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) { SINT8 voted = READSINT8(*cp); - votes[playernum] = voted; + UINT8 p = READUINT8(*cp); + + (void)playernum; + votes[p] = voted; } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) From 66c1b9d598c45b9f4cf8896d77dc7b8143493cf4 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 01:25:10 -0400 Subject: [PATCH 18/36] If multiple players are just joining, don't count them in the player count Prevents awkward situations where only the last player of your node gets added immediately and not the others. Shouldn't affect anything otherwise? --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 5c341737..9b449d36 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10091,6 +10091,8 @@ void P_SpawnPlayer(INT32 playernum) continue; if (!playeringame[i] || players[i].spectator) continue; + if (players[i].jointime <= 1) // Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers + continue; pcount++; } From ac521015ff4b7a30737f69924863a168d025151c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 01:26:13 -0400 Subject: [PATCH 19/36] Don't draw the challenger screen multiple times Another minor bug that could only crop up in online splitscreen --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index c22dec0c..2f9a4a12 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7319,7 +7319,7 @@ void K_drawKartHUD(void) K_drawKartMinimap(); // Draw full screen stuff that turns off the rest of the HUD - if (mapreset) + if (mapreset && stplyr == &players[displayplayer]) { K_drawChallengerScreen(); return; From 506c70ce2738e68873332e880cd81f721fdd3a52 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 01:28:48 -0400 Subject: [PATCH 20/36] Don't scale player arrows in splitscreen --- src/p_mobj.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b449d36..cb68bfef 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6835,10 +6835,13 @@ void P_MobjThinker(mobj_t *mobj) } P_SetThingPosition(mobj); - scale += FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, - players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*FRACUNIT) - scale = 16*FRACUNIT; + if (!splitscreen) + { + scale += FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, + players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + if (scale > 16*FRACUNIT) + scale = 16*FRACUNIT; + } mobj->destscale = scale; if (!mobj->tracer) From 7590153b67fc17268374e07cd531ff40fbdaac86 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 02:10:20 -0400 Subject: [PATCH 21/36] Finish music in splitscreen now depends on the best player's rank In offline splitscreen it should now always pick the win theme (the one that's timed with the signpost), and in online splitscreen it should now pick the best ranked local player (previously it'd always play the OK theme, unless if you time over'd) Will also be extremely relevant for SMK-style cooperative grand prix! --- src/p_user.c | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 1b63e35c..39e7ec0e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1147,34 +1147,57 @@ boolean P_EndingMusic(player_t *player) { char buffer[9]; boolean looping = true; + INT32 bestlocalpos; + player_t *bestlocalplayer; if (!P_IsLocalPlayer(player)) // Only applies to a local player return false; // Event - Level Finish - if (splitscreen - && (players[displayplayer].exiting - || players[secondarydisplayplayer].exiting - || ((splitscreen < 2) && players[thirddisplayplayer].exiting) - || ((splitscreen < 3) && players[fourthdisplayplayer].exiting))) + // Check for if this is valid or not + if (splitscreen) { - sprintf(buffer, "k*ok"); + if (!((players[displayplayer].exiting || (players[displayplayer].pflags & PF_TIMEOVER)) + || (players[secondarydisplayplayer].exiting || (players[secondarydisplayplayer].pflags & PF_TIMEOVER)) + || ((splitscreen < 2) && (players[thirddisplayplayer].exiting || (players[thirddisplayplayer].pflags & PF_TIMEOVER))) + || ((splitscreen < 3) && (players[fourthdisplayplayer].exiting || (players[fourthdisplayplayer].pflags & PF_TIMEOVER))))) + return false; + + bestlocalplayer = &players[displayplayer]; + bestlocalpos = ((players[displayplayer].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[displayplayer].kartstuff[k_position]); +#define setbests(p) \ + if (((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]) < bestlocalpos) \ + { \ + bestlocalplayer = &players[p]; \ + bestlocalpos = ((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]); \ } - else if (player->pflags & PF_TIMEOVER) // || !player->lives) -- outta lives, outta time - { - sprintf(buffer, "k*lose"); + setbests(secondarydisplayplayer); + if (splitscreen > 1) + setbests(thirddisplayplayer); + if (splitscreen > 2) + setbests(fourthdisplayplayer); +#undef setbests } - else if (player->exiting) + else { - if (player->kartstuff[k_position] == 1) + if (!(player->exiting || (player->pflags & PF_TIMEOVER))) + return false; + + bestlocalplayer = player; + bestlocalpos = ((player->pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : player->kartstuff[k_position]); + } + + if (G_RaceGametype() && bestlocalpos == MAXPLAYERS+1) + sprintf(buffer, "k*lose"); // krfail, for eventual F-Zero death results theme + else + { + if (bestlocalpos == 1) sprintf(buffer, "k*win"); - else if (K_IsPlayerLosing(player)) + else if (K_IsPlayerLosing(bestlocalplayer)) sprintf(buffer, "k*lose"); else sprintf(buffer, "k*ok"); } - else - return false; S_SpeedMusic(1.0f); From 527642323e3b6a392bc971f4e93312a1da78b55b Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 02:23:13 -0400 Subject: [PATCH 22/36] Splitscreen spectator info --- src/st_stuff.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 72266ba2..b9a44b34 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1927,7 +1927,7 @@ static void ST_overlayDrawer(void) ) ST_drawLevelTitle(); - if (!hu_showscores && !splitscreen && netgame && displayplayer == consoleplayer && !mapreset) + if (!hu_showscores && netgame && !mapreset) { /*if (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1) V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press F12 to watch another player.")); @@ -1952,16 +1952,30 @@ static void ST_overlayDrawer(void) ) { // SRB2kart: changed positions & text - V_DrawString(2, BASEVIDHEIGHT-50, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); - if (stplyr->pflags & PF_WANTSTOJOIN) - V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); - /*else if (G_GametypeHasTeams()) - V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/ + if (splitscreen) + { + INT32 splitflags = K_calcSplitFlags(0); + V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|V_6WIDTHSPACE|splitflags, M_GetText("- SPECTATING -")); + if (stplyr->pflags & PF_WANTSTOJOIN) + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|V_6WIDTHSPACE|splitflags, M_GetText("Item - Cancel Join")); + /*else if (G_GametypeHasTeams()) + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|V_6WIDTHSPACE|splitflags, M_GetText("Item - Join Team"));*/ + else + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|V_6WIDTHSPACE|splitflags, M_GetText("Item - Join Game")); + } else - V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Join Game")); - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("F12 - Change View")); - V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float")); - V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink")); + { + V_DrawString(2, BASEVIDHEIGHT-50, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); + if (stplyr->pflags & PF_WANTSTOJOIN) + V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); + /*else if (G_GametypeHasTeams()) + V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/ + else + V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Item - Join Game")); + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("F12 - Change View")); + V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float")); + V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink")); + } } } From d2ec4d2be5522613e058b51502a3cc094721dc83 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 2 Oct 2018 14:10:38 -0400 Subject: [PATCH 23/36] Only play one player's roulette sounds at a time Don't stack the sounds :WutFace: --- src/k_kart.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 2f9a4a12..99f751db 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -904,7 +904,35 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // This makes the roulette produce the random noises. if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsLocalPlayer(player)) - S_StartSound(NULL, sfx_mkitm1 + ((player->kartstuff[k_itemroulette] / 3) % 8)); + { +#define PLAYROULETTESND S_StartSound(NULL, sfx_mkitm1 + ((player->kartstuff[k_itemroulette] / 3) % 8)); + if (splitscreen) + { + if (players[displayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[displayplayer]) + PLAYROULETTESND; + } + else if (players[secondarydisplayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[secondarydisplayplayer]) + PLAYROULETTESND; + } + else if (players[thirddisplayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[thirddisplayplayer]) + PLAYROULETTESND; + } + else if (players[fourthdisplayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[fourthdisplayplayer]) + PLAYROULETTESND; + } + } + else + PLAYROULETTESND; +#undef PLAYROULETTESND + } roulettestop = (TICRATE*1) + (3*(pingame - player->kartstuff[k_position])); From bb9e77f2a1326d16892087a0d72f1a2ab33e7ccb Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Wed, 3 Oct 2018 13:43:36 -0400 Subject: [PATCH 24/36] Add a few more splitscreen checks here --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 99f751db..29b99d48 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -918,12 +918,12 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if (player == &players[secondarydisplayplayer]) PLAYROULETTESND; } - else if (players[thirddisplayplayer].kartstuff[k_itemroulette]) + else if (players[thirddisplayplayer].kartstuff[k_itemroulette] && splitscreen > 1) { if (player == &players[thirddisplayplayer]) PLAYROULETTESND; } - else if (players[fourthdisplayplayer].kartstuff[k_itemroulette]) + else if (players[fourthdisplayplayer].kartstuff[k_itemroulette] && splitscreen > 2) { if (player == &players[fourthdisplayplayer]) PLAYROULETTESND; From 34aa3762c9e3c3ea15e06942b69611c56341c305 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Thu, 4 Oct 2018 23:55:28 -0400 Subject: [PATCH 25/36] -splitscreen launcher option Now you can join a game in splitscreen mode from a launcher --- src/d_main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index e56a631a..a953c020 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1377,11 +1377,26 @@ void D_SRB2Main(void) #endif } + // Set up splitscreen players before joining! + if (!dedicated && (M_CheckParm("-splitscreen") && M_IsNextParm())) + { + UINT8 num = atoi(M_GetNextParm()); + if (num >= 1 && num <= 4) + { + CV_StealthSetValue(&cv_splitplayers, num); + splitscreen = num-1; + SplitScreen_OnChange(); + } + } + // init all NETWORK CONS_Printf("D_CheckNetGame(): Checking network game status.\n"); if (D_CheckNetGame()) autostart = true; + if (splitscreen) // Make sure multiplayer & autostart is set if you have splitscreen, even after D_CheckNetGame + multiplayer = autostart = true; + // check for a driver that wants intermission stats // start the apropriate game based on parms if (M_CheckParm("-metal")) From 3101eb1a1865acf3ac91b33f035b6355e290225a Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 8 Oct 2018 00:14:29 -0400 Subject: [PATCH 26/36] Don't let chat/console eat inputs from anyone besides player 1 --- src/console.c | 26 ++++++++++++++++++++++++++ src/hu_stuff.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/console.c b/src/console.c index f79a6faf..2ddb9913 100644 --- a/src/console.c +++ b/src/console.c @@ -745,9 +745,35 @@ boolean CON_Responder(event_t *ev) // check for console toggle key if (ev->type != ev_console) { + INT32 i, j; + if (modeattacking || metalrecording) return false; + if (splitscreen && ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder + { + for (i = 0; i < num_gamecontrols; i++) + { + for (j = 0; j < 2; j++) + { + if (gamecontrolbis[i][j] == ev->data1) + return false; + + if (splitscreen > 1) + { + if (gamecontrol3[i][j] == ev->data1) + return false; + + if (splitscreen > 2) + { + if (gamecontrol4[i][j] == ev->data1) + return false; + } + } + } + } + } + if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) { if (consdown) // ignore repeat diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e503e2a6..0879aedf 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1056,12 +1056,44 @@ static boolean justscrolledup; boolean HU_Responder(event_t *ev) { INT32 c=0; + INT32 i, j; if (ev->type != ev_keydown) return false; // only KeyDown events now... - + + // Shoot, to prevent P1 chatting from ruining the game for everyone else, it's either: + // A. completely disallow opening chat entirely in online splitscreen + // or B. iterate through all controls to make sure it's not bound to another player's + // You can see which one I chose. + // (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...) + // (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...) + + if (chat_on && splitscreen && ev->data1 >= KEY_MOUSE1) + { + for (i = 0; i < num_gamecontrols; i++) + { + for (j = 0; j < 2; j++) + { + if (gamecontrolbis[i][j] == ev->data1) + return false; + + if (splitscreen > 1) + { + if (gamecontrol3[i][j] == ev->data1) + return false; + + if (splitscreen > 2) + { + if (gamecontrol4[i][j] == ev->data1) + return false; + } + } + } + } + } + if (!chat_on) { // enter chat mode From 9e51c10337043a7206bc227a1c48a489db807030 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 8 Oct 2018 00:16:27 -0400 Subject: [PATCH 27/36] Fix Hyudoro arrows being visible --- src/p_mobj.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 536ecb74..afa9a78b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6815,8 +6815,6 @@ void P_MobjThinker(mobj_t *mobj) #endif ) mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; P_UnsetThingPosition(mobj); mobj->x = mobj->target->x; From 18074664745e7893ff2a48a16a14edf1d2fe95f8 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 8 Oct 2018 13:58:16 -0400 Subject: [PATCH 28/36] Simpler loop --- src/console.c | 28 ++++++++++------------------ src/hu_stuff.c | 29 +++++++++++------------------ 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/src/console.c b/src/console.c index 2ddb9913..c5675609 100644 --- a/src/console.c +++ b/src/console.c @@ -745,33 +745,25 @@ boolean CON_Responder(event_t *ev) // check for console toggle key if (ev->type != ev_console) { - INT32 i, j; - if (modeattacking || metalrecording) return false; - if (splitscreen && ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder + if (ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder { + INT32 i; + boolean p1control = false; + for (i = 0; i < num_gamecontrols; i++) { - for (j = 0; j < 2; j++) + if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) { - if (gamecontrolbis[i][j] == ev->data1) - return false; - - if (splitscreen > 1) - { - if (gamecontrol3[i][j] == ev->data1) - return false; - - if (splitscreen > 2) - { - if (gamecontrol4[i][j] == ev->data1) - return false; - } - } + p1control = true; + break; } } + + if (!p1control) + return false; } if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 0879aedf..7a62c749 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1056,7 +1056,6 @@ static boolean justscrolledup; boolean HU_Responder(event_t *ev) { INT32 c=0; - INT32 i, j; if (ev->type != ev_keydown) return false; @@ -1065,33 +1064,27 @@ boolean HU_Responder(event_t *ev) // Shoot, to prevent P1 chatting from ruining the game for everyone else, it's either: // A. completely disallow opening chat entirely in online splitscreen - // or B. iterate through all controls to make sure it's not bound to another player's + // or B. iterate through all controls to make sure it's bound to player 1 before eating // You can see which one I chose. // (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...) // (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...) - if (chat_on && splitscreen && ev->data1 >= KEY_MOUSE1) + if (ev->data1 >= KEY_MOUSE1) { + INT32 i; + boolean p1control = false; + for (i = 0; i < num_gamecontrols; i++) { - for (j = 0; j < 2; j++) + if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) { - if (gamecontrolbis[i][j] == ev->data1) - return false; - - if (splitscreen > 1) - { - if (gamecontrol3[i][j] == ev->data1) - return false; - - if (splitscreen > 2) - { - if (gamecontrol4[i][j] == ev->data1) - return false; - } - } + p1control = true; + break; } } + + if (!p1control) + return false; } if (!chat_on) From 7838a29f3d73e80a9cc1d9eaecb65a9880af7c6c Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 8 Oct 2018 14:38:29 -0400 Subject: [PATCH 29/36] Scale chat in splitscreen Only covers things on P1's screen now --- src/hu_stuff.c | 91 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7a62c749..6fb6035d 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1288,6 +1288,7 @@ static void HU_drawMiniChat(void) INT32 x = chatx+2; INT32 charwidth = 4, charheight = 6; + INT32 boxw = cv_chatwidth.value; INT32 dx = 0, dy = 0; size_t i = chat_nummsg_min; boolean prev_linereturn = false; // a hack to prevent double \n while I have no idea why they happen in the first place. @@ -1295,9 +1296,12 @@ static void HU_drawMiniChat(void) INT32 msglines = 0; // process all messages once without rendering anything or doing anything fancy so that we know how many lines each message has... + if (splitscreen > 1) + boxw = max(1, boxw/2); + for (; i>0; i--) { - const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); + const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); size_t j = 0; INT32 linescount = 0; @@ -1330,7 +1334,7 @@ static void HU_drawMiniChat(void) } prev_linereturn = false; dx += charwidth; - if (dx >= cv_chatwidth.value) + if (dx >= boxw) { dx = 0; linescount += 1; @@ -1341,7 +1345,17 @@ static void HU_drawMiniChat(void) msglines += linescount+1; } - INT32 y = chaty - charheight*(msglines+1) - (cv_kartspeedometer.value ? 16 : 0); + INT32 y = chaty - charheight*(msglines+1); + + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + y += 16; + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + dx = 0; dy = 0; i = 0; @@ -1353,7 +1367,7 @@ static void HU_drawMiniChat(void) INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below... INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one. size_t j = 0; - const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. + const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. UINT8 *colormap = NULL; while(msg[j]) // iterate through msg @@ -1391,7 +1405,7 @@ static void HU_drawMiniChat(void) dx += charwidth; prev_linereturn = false; - if (dx >= cv_chatwidth.value) + if (dx >= boxw) { dx = 0; dy += charheight; @@ -1412,6 +1426,7 @@ static void HU_drawMiniChat(void) static void HU_drawChatLog(INT32 offset) { INT32 charwidth = 4, charheight = 6; + INT32 boxw = cv_chatwidth.value, boxh = cv_chatheight.value; INT32 x = chatx+2, y, dx = 0, dy = 0; UINT32 i = 0; INT32 chat_topy, chat_bottomy; @@ -1421,17 +1436,34 @@ static void HU_drawChatLog(INT32 offset) if (chat_scroll > chat_maxscroll) chat_scroll = chat_maxscroll; - y = chaty - offset*charheight - (chat_scroll*charheight) - cv_chatheight.value*charheight - 12 - (cv_kartspeedometer.value ? 16 : 0); - chat_topy = y + chat_scroll*charheight; - chat_bottomy = chat_topy + cv_chatheight.value*charheight; + if (splitscreen) + { + boxh = max(1, boxh/2); + if (splitscreen > 1) + boxw = max(1, boxw/2); + } - V_DrawFillConsoleMap(chatx, chat_topy, cv_chatwidth.value, cv_chatheight.value*charheight +2, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box + y = chaty - offset*charheight - (chat_scroll*charheight) - boxh*charheight - 12; + + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + y += 16; + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + + chat_topy = y + chat_scroll*charheight; + chat_bottomy = chat_topy + boxh*charheight; + + V_DrawFillConsoleMap(chatx, chat_topy, boxw, boxh*charheight +2, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box for (i=0; i= cv_chatwidth.value-charwidth-2 && i= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!! + if (dx >= boxw-charwidth-2 && i= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!! { dx = 0; dy += charheight; @@ -1481,10 +1513,10 @@ static void HU_drawChatLog(INT32 offset) // getmaxscroll through a lazy hack. We do all these loops, so let's not do more loops that are gonna lag the game more. :P chat_maxscroll = (dy/charheight); // welcome to C, we don't know what min() and max() are. - if (chat_maxscroll <= (UINT32)cv_chatheight.value) + if (chat_maxscroll <= (UINT32)boxh) chat_maxscroll = 0; else - chat_maxscroll -= cv_chatheight.value; + chat_maxscroll -= boxh; // if we're not bound by the time, autoscroll for next frame: if (atbottom) @@ -1517,13 +1549,26 @@ static INT16 typelines = 1; // number of drawfill lines we need. it's some weird static void HU_DrawChat(void) { INT32 charwidth = 4, charheight = 6; - INT32 t = 0, c = 0, y = chaty - (typelines*charheight) - (cv_kartspeedometer.value ? 16 : 0); + INT32 boxw = cv_chatwidth.value; + INT32 t = 0, c = 0, y = chaty - (typelines*charheight); UINT32 i = 0, saylen = strlen(w_chat); // You learn new things everyday! INT32 cflag = 0; const char *ntalk = "Say: ", *ttalk = "Team: "; const char *talk = ntalk; const char *mute = "Chat has been muted."; + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + { + y += 16; + boxw = max(1, boxw/2); + } + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + if (teamtalk) { talk = ttalk; @@ -1542,7 +1587,7 @@ static void HU_DrawChat(void) cflag = V_GRAYMAP; // set text in gray if chat is muted. } - V_DrawFillConsoleMap(chatx, y-1, cv_chatwidth.value, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT); + V_DrawFillConsoleMap(chatx, y-1, boxw, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT); while (talk[i]) { @@ -1575,7 +1620,7 @@ static void HU_DrawChat(void) boolean skippedline = false; if (c_input == (i+1)) { - int cursorx = (c+charwidth < cv_chatwidth.value-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down. + int cursorx = (c+charwidth < boxw-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down. int cursory = (cursorx != chatx+1) ? (y) : (y+charheight); if (hu_tick < 4) V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL); @@ -1595,7 +1640,7 @@ static void HU_DrawChat(void) V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, !cv_allcaps.value, NULL); c += charwidth; - if (c > cv_chatwidth.value-(charwidth*2) && !skippedline) + if (c > boxw-(charwidth*2) && !skippedline) { c = 0; y += charheight; @@ -1609,6 +1654,14 @@ static void HU_DrawChat(void) i = 0; INT32 count = 0; INT32 p_dispy = chaty - charheight -1; + if (splitscreen) + { + p_dispy -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + p_dispy += 16; + } + else + p_dispy -= (cv_kartspeedometer.value ? 16 : 0); for(i=0; (i Date: Mon, 8 Oct 2018 14:49:48 -0400 Subject: [PATCH 30/36] use cvar mins --- src/hu_stuff.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 6fb6035d..e456d8cf 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1297,7 +1297,7 @@ static void HU_drawMiniChat(void) // process all messages once without rendering anything or doing anything fancy so that we know how many lines each message has... if (splitscreen > 1) - boxw = max(1, boxw/2); + boxw = max(64, boxw/2); for (; i>0; i--) { @@ -1438,9 +1438,9 @@ static void HU_drawChatLog(INT32 offset) if (splitscreen) { - boxh = max(1, boxh/2); + boxh = max(6, boxh/2); if (splitscreen > 1) - boxw = max(1, boxw/2); + boxw = max(64, boxw/2); } y = chaty - offset*charheight - (chat_scroll*charheight) - boxh*charheight - 12; @@ -1563,7 +1563,7 @@ static void HU_DrawChat(void) if (splitscreen > 1) { y += 16; - boxw = max(1, boxw/2); + boxw = max(64, boxw/2); } } else From ba16f2bfcf3eac89f1ed14b9aed69ec8320f42f4 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 15 Oct 2018 20:28:35 -0400 Subject: [PATCH 31/36] Spectate/Enter menu for online splitscreen Just like the menu option --- src/m_menu.c | 148 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 116 insertions(+), 32 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index b6928d16..f8a316f2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -242,12 +242,13 @@ static void M_ConfirmSpectate(INT32 choice); static void M_ConfirmEnterGame(INT32 choice); static void M_ConfirmTeamScramble(INT32 choice); static void M_ConfirmTeamChange(INT32 choice); +static void M_ConfirmSpectateChange(INT32 choice); //static void M_SecretsMenu(INT32 choice); static void M_SetupChoosePlayer(INT32 choice); static void M_QuitSRB2(INT32 choice); menu_t SP_MainDef, MP_MainDef, OP_MainDef; menu_t MP_SetPlayersDef; -menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; +menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; // Single Player //static void M_LoadGame(INT32 choice); @@ -394,6 +395,7 @@ static void M_HandleMonitorToggles(INT32 choice); // Consvar onchange functions static void Nextmap_OnChange(void); static void Newgametype_OnChange(void); +static void Dummymenuplayer_OnChange(void); //static void Dummymares_OnChange(void); static void Dummystaff_OnChange(void); @@ -467,7 +469,9 @@ CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"} consvar_t cv_splitplayers = {"splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif +static CV_PossibleValue_t dummymenuplayer_cons_t[] = {{0, "NOPE"}, {1, "P1"}, {2, "P2"}, {3, "P3"}, {4, "P4"}, {0, NULL}}; static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; +static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; @@ -476,7 +480,9 @@ static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NU };*/ static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}}; +static consvar_t cv_dummymenuplayer = {"dummymenuplayer", "P1", CV_HIDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyteam = {"dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_dummyspectate = {"dummyspectate", "Spectator", CV_HIDEN, dummyspectate_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyscramble = {"dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyrings = {"dummyrings", "0", CV_HIDEN, ringlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -555,10 +561,11 @@ static menuitem_t MPauseMenu[] = {IT_CALL | IT_STRING, NULL, "P4 Setup...", M_SetupMultiPlayer4, 72}, // splitscreen #endif - {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, - {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, - {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, + {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, // alone + {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, // alone + {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, // alone {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, + {IT_STRING | IT_SUBMENU, NULL, "Enter/Spectate...", &MISC_ChangeSpectateDef,48}, {IT_CALL | IT_STRING, NULL, "Player Setup...", M_SetupMultiPlayer, 56}, // alone {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, @@ -583,6 +590,7 @@ typedef enum mpause_entergame, mpause_canceljoin, mpause_switchteam, + mpause_switchspectate, mpause_psetup, mpause_options, @@ -633,10 +641,18 @@ static menuitem_t MISC_ScrambleTeamMenu[] = static menuitem_t MISC_ChangeTeamMenu[] = { - {IT_STRING|IT_CVAR, NULL, "Select Team", &cv_dummyteam, 30}, + {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, + {IT_STRING|IT_CVAR, NULL, "Team", &cv_dummyteam, 40}, {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90}, }; +static menuitem_t MISC_ChangeSpectateMenu[] = +{ + {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, + {IT_STRING|IT_CVAR, NULL, "Status", &cv_dummyspectate, 40}, + {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmSpectateChange, 90}, +}; + static menuitem_t MISC_ChangeLevelMenu[] = { {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, @@ -1599,6 +1615,7 @@ menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); // Misc Main Menu menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40); menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40); +menu_t MISC_ChangeSpectateDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeSpectateMenu, &MPauseDef, 27, 40); menu_t MISC_ChangeLevelDef = MAPICONMENUSTYLE(NULL, MISC_ChangeLevelMenu, &MPauseDef); menu_t MISC_HelpDef = IMAGEDEF(MISC_HelpMenu); @@ -2135,6 +2152,14 @@ static void Nextmap_OnChange(void) } } +static void Dummymenuplayer_OnChange(void) +{ + if (cv_dummymenuplayer.value < 1) + CV_StealthSetValue(&cv_dummymenuplayer, splitscreen+1); + else if (cv_dummymenuplayer.value > splitscreen+1) + CV_StealthSetValue(&cv_dummymenuplayer, 1); +} + /*static void Dummymares_OnChange(void) { if (!nightsrecords[cv_nextmap.value-1]) @@ -2926,11 +2951,17 @@ void M_StartControlPanel(void) MPauseMenu[mpause_entergame].status = IT_DISABLED; MPauseMenu[mpause_canceljoin].status = IT_DISABLED; MPauseMenu[mpause_switchteam].status = IT_DISABLED; + MPauseMenu[mpause_switchspectate].status = IT_DISABLED; MPauseMenu[mpause_psetup].status = IT_DISABLED; + MISC_ChangeTeamMenu[0].status = IT_DISABLED; + MISC_ChangeSpectateMenu[0].status = IT_DISABLED; // Reset these in case splitscreen messes things up + MPauseMenu[mpause_switchteam].alphaKey = 48; + MPauseMenu[mpause_switchspectate].alphaKey = 48; MPauseMenu[mpause_options].alphaKey = 64; MPauseMenu[mpause_title].alphaKey = 80; MPauseMenu[mpause_quit].alphaKey = 88; + Dummymenuplayer_OnChange(); if ((server || IsPlayerAdmin(consoleplayer))) { @@ -2943,25 +2974,43 @@ void M_StartControlPanel(void) if (splitscreen) { MPauseMenu[mpause_psetupsplit].status = MPauseMenu[mpause_psetupsplit2].status = IT_STRING | IT_CALL; + MISC_ChangeTeamMenu[0].status = MISC_ChangeSpectateMenu[0].status = IT_STRING|IT_CVAR; + + if (netgame) + { + if (G_GametypeHasTeams()) + { + MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; + MPauseMenu[mpause_switchteam].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; + } + else if (G_GametypeHasSpectators()) + { + MPauseMenu[mpause_switchspectate].status = IT_STRING | IT_SUBMENU; + MPauseMenu[mpause_switchspectate].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; + } + } #ifndef NOFOURPLAYER if (splitscreen > 1) { MPauseMenu[mpause_psetupsplit3].status = IT_STRING | IT_CALL; - if (splitscreen == 2) - { - MPauseMenu[mpause_options].alphaKey = 72; - MPauseMenu[mpause_title].alphaKey = 88; - MPauseMenu[mpause_quit].alphaKey = 96; - } + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; - if (splitscreen == 3) + if (splitscreen > 2) { MPauseMenu[mpause_psetupsplit4].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_options].alphaKey = 80; - MPauseMenu[mpause_title].alphaKey = 96; - MPauseMenu[mpause_quit].alphaKey = 104; + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; } } #endif @@ -3092,7 +3141,9 @@ void M_Init(void) #ifndef NOFOURPLAYER CV_RegisterVar(&cv_splitplayers); #endif + CV_RegisterVar(&cv_dummymenuplayer); CV_RegisterVar(&cv_dummyteam); + CV_RegisterVar(&cv_dummyspectate); CV_RegisterVar(&cv_dummyscramble); CV_RegisterVar(&cv_dummyrings); CV_RegisterVar(&cv_dummylives); @@ -4864,11 +4915,11 @@ static void M_ConfirmSpectate(INT32 choice) static void M_ConfirmEnterGame(INT32 choice) { (void)choice; - /*if (!cv_allowteamchange.value) + if (!cv_allowteamchange.value) { M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); return; - }*/ + } M_ClearMenus(true); COM_ImmedExecute("changeteam playing"); } @@ -4878,20 +4929,16 @@ static void M_ConfirmTeamScramble(INT32 choice) (void)choice; M_ClearMenus(true); - switch (cv_dummyscramble.value) - { - case 0: - COM_ImmedExecute("teamscramble 1"); - break; - case 1: - COM_ImmedExecute("teamscramble 2"); - break; - } + COM_ImmedExecute(va("teamscramble %d", cv_dummyscramble.value+1)); } static void M_ConfirmTeamChange(INT32 choice) { (void)choice; + + if (cv_dummymenuplayer.value > splitscreen+1) + return; + if (!cv_allowteamchange.value && cv_dummyteam.value) { M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); @@ -4900,16 +4947,53 @@ static void M_ConfirmTeamChange(INT32 choice) M_ClearMenus(true); - switch (cv_dummyteam.value) + switch (cv_dummymenuplayer.value) { - case 0: - COM_ImmedExecute("changeteam spectator"); - break; case 1: - COM_ImmedExecute("changeteam red"); + default: + COM_ImmedExecute(va("changeteam %s", cv_dummyteam.string)); break; case 2: - COM_ImmedExecute("changeteam blue"); + COM_ImmedExecute(va("changeteam2 %s", cv_dummyteam.string)); + break; + case 3: + COM_ImmedExecute(va("changeteam3 %s", cv_dummyteam.string)); + break; + case 4: + COM_ImmedExecute(va("changeteam4 %s", cv_dummyteam.string)); + break; + } +} + +static void M_ConfirmSpectateChange(INT32 choice) +{ + (void)choice; + + if (cv_dummymenuplayer.value > splitscreen+1) + return; + + if (!cv_allowteamchange.value && cv_dummyspectate.value) + { + M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); + return; + } + + M_ClearMenus(true); + + switch (cv_dummymenuplayer.value) + { + case 1: + default: + COM_ImmedExecute(va("changeteam %s", cv_dummyspectate.string)); + break; + case 2: + COM_ImmedExecute(va("changeteam2 %s", cv_dummyspectate.string)); + break; + case 3: + COM_ImmedExecute(va("changeteam3 %s", cv_dummyspectate.string)); + break; + case 4: + COM_ImmedExecute(va("changeteam4 %s", cv_dummyspectate.string)); break; } } From ec048b73c4e933294b42839bf6b1e31a34c95075 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 15 Oct 2018 20:31:26 -0400 Subject: [PATCH 32/36] Show Spectator controls for P2-P3 again --- src/m_menu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index f8a316f2..fa13e704 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8519,12 +8519,13 @@ static void M_Setup1PControlsMenu(INT32 choice) OP_AllControlsMenu[21].status = IT_CONTROL; // GIF OP_AllControlsMenu[22].status = IT_CONTROL; // System Menu OP_AllControlsMenu[23].status = IT_CONTROL; // Console - OP_AllControlsMenu[24].status = IT_HEADER; // Spectator Controls header + /*OP_AllControlsMenu[24].status = IT_HEADER; // Spectator Controls header OP_AllControlsMenu[25].status = IT_SPACE; // Spectator Controls space OP_AllControlsMenu[26].status = IT_CONTROL; // Spectate OP_AllControlsMenu[27].status = IT_CONTROL; // Look Up OP_AllControlsMenu[28].status = IT_CONTROL; // Look Down OP_AllControlsMenu[29].status = IT_CONTROL; // Center View + */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -8551,12 +8552,13 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // Console - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header + /*OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls space OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectate OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Look Up OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Down OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Center View + */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -8584,12 +8586,13 @@ static void M_Setup3PControlsMenu(INT32 choice) OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // Console - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header + /*OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls space OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectate OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Look Up OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Down OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Center View + */ M_SetupNextMenu(&OP_AllControlsDef); } @@ -8616,12 +8619,13 @@ static void M_Setup4PControlsMenu(INT32 choice) OP_AllControlsMenu[21].status = IT_GRAYEDOUT2; // GIF OP_AllControlsMenu[22].status = IT_GRAYEDOUT2; // System Menu OP_AllControlsMenu[23].status = IT_GRAYEDOUT2; // Console - OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header + /*OP_AllControlsMenu[24].status = IT_GRAYEDOUT2; // Spectator Controls header OP_AllControlsMenu[25].status = IT_GRAYEDOUT2; // Spectator Controls space OP_AllControlsMenu[26].status = IT_GRAYEDOUT2; // Spectate OP_AllControlsMenu[27].status = IT_GRAYEDOUT2; // Look Up OP_AllControlsMenu[28].status = IT_GRAYEDOUT2; // Look Down OP_AllControlsMenu[29].status = IT_GRAYEDOUT2; // Center View + */ M_SetupNextMenu(&OP_AllControlsDef); } From 32f3088e017fb31fc9ef0e503037ae4ebbcaffbd Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Mon, 15 Oct 2018 20:34:53 -0400 Subject: [PATCH 33/36] Minor whitespace --- src/g_input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 101fa8e4..fa23c5d4 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1321,21 +1321,21 @@ void G_Controldefault(void) gamecontrolbis[gc_accelerate ][0] = KEY_2JOY1+0; // A gamecontrolbis[gc_lookback ][0] = KEY_2JOY1+1; // X gamecontrolbis[gc_brake ][0] = KEY_2JOY1+2; // B - gamecontrolbis[gc_fire ][0] = KEY_2JOY1+4; // LB + gamecontrolbis[gc_fire ][0] = KEY_2JOY1+4; // LB gamecontrolbis[gc_drift ][0] = KEY_2JOY1+5; // RB // Player 3 controls gamecontrol3[gc_accelerate ][0] = KEY_3JOY1+0; // A gamecontrol3[gc_lookback ][0] = KEY_3JOY1+1; // X gamecontrol3[gc_brake ][0] = KEY_3JOY1+2; // B - gamecontrol3[gc_fire ][0] = KEY_3JOY1+4; // LB + gamecontrol3[gc_fire ][0] = KEY_3JOY1+4; // LB gamecontrol3[gc_drift ][0] = KEY_3JOY1+5; // RB // Player 4 controls gamecontrol4[gc_accelerate ][0] = KEY_4JOY1+0; // A gamecontrol4[gc_lookback ][0] = KEY_4JOY1+1; // X gamecontrol4[gc_brake ][0] = KEY_4JOY1+2; // B - gamecontrol4[gc_fire ][0] = KEY_4JOY1+4; // LB + gamecontrol4[gc_fire ][0] = KEY_4JOY1+4; // LB gamecontrol4[gc_drift ][0] = KEY_4JOY1+5; // RB } //#endif From 35528276d286f65a44c12a365a4d5985fd4b11f8 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 16 Oct 2018 12:25:51 -0400 Subject: [PATCH 34/36] Optimize --- src/console.c | 7 +------ src/hu_stuff.c | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/console.c b/src/console.c index c5675609..a7d5fcef 100644 --- a/src/console.c +++ b/src/console.c @@ -751,18 +751,13 @@ boolean CON_Responder(event_t *ev) if (ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder { INT32 i; - boolean p1control = false; - for (i = 0; i < num_gamecontrols; i++) { if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) - { - p1control = true; break; - } } - if (!p1control) + if (i == num_gamecontrols) return false; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index c6c9c50f..c394e033 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1076,18 +1076,13 @@ boolean HU_Responder(event_t *ev) if (ev->data1 >= KEY_MOUSE1) { INT32 i; - boolean p1control = false; - for (i = 0; i < num_gamecontrols; i++) { if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) - { - p1control = true; break; - } } - if (!p1control) + if (i == num_gamecontrols) return false; } From b34cbe4032e84327194745afd1bdfb70098d0eaf Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 16 Oct 2018 22:11:47 +0100 Subject: [PATCH 35/36] `[22:03] TehRealSalt: Not organized code-wise, figured toaster would want to help with that since she's the Menu Queen and she probably has better ideas on how to do it` The Menu Queen is in the house~ :sparkles: * Magical, single-page player select and general netgamey stuff, while still remaining both pretty and functional. * Death to NOFOURPLAYER, now that the cat's out the bag. * Clean up NONET, assuming people try to make DD builds on release. * Minor tweaks across the board, mostly places where I wanted to pilfer minor code from and realised it wasn't done optimally originally. --- src/m_menu.c | 373 +++++++++++++++++++++++++++------------------------ 1 file changed, 198 insertions(+), 175 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 7cecd63a..cff29377 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -247,7 +247,6 @@ static void M_ConfirmSpectateChange(INT32 choice); static void M_SetupChoosePlayer(INT32 choice); static void M_QuitSRB2(INT32 choice); menu_t SP_MainDef, MP_MainDef, OP_MainDef; -menu_t MP_SetPlayersDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; // Single Player @@ -282,33 +281,27 @@ static void M_ChooseRoom(INT32 choice); #endif static void M_SetupMultiPlayer(INT32 choice); static void M_SetupMultiPlayer2(INT32 choice); -#ifndef NOFOURPLAYER static void M_SetupMultiPlayer3(INT32 choice); static void M_SetupMultiPlayer4(INT32 choice); -#endif +static void M_SetupMultiHandler(INT32 choice); // Options // Split into multiple parts due to size // Controls menu_t OP_ControlsDef, OP_AllControlsDef; menu_t OP_MouseOptionsDef, OP_Mouse2OptionsDef; -menu_t OP_Joystick1Def, OP_Joystick2Def; -#ifndef NOFOURPLAYER -menu_t OP_Joystick3Def, OP_Joystick4Def; -#endif +menu_t OP_Joystick1Def, OP_Joystick2Def, OP_Joystick3Def, OP_Joystick4Def; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); -#ifndef NOFOURPLAYER static void M_Setup3PControlsMenu(INT32 choice); static void M_Setup4PControlsMenu(INT32 choice); -#endif + static void M_Setup1PJoystickMenu(INT32 choice); static void M_Setup2PJoystickMenu(INT32 choice); -#ifndef NOFOURPLAYER static void M_Setup3PJoystickMenu(INT32 choice); static void M_Setup4PJoystickMenu(INT32 choice); -#endif + static void M_AssignJoystick(INT32 choice); static void M_ChangeControl(INT32 choice); @@ -363,9 +356,9 @@ static void M_DrawMonitorToggles(void); static void M_OGL_DrawFogMenu(void); static void M_OGL_DrawColorMenu(void); #endif +static void M_DrawMPMainMenu(void); #ifndef NONET static void M_DrawConnectMenu(void); -static void M_DrawMPMainMenu(void); static void M_DrawRoomMenu(void); #endif static void M_DrawJoystick(void); @@ -463,11 +456,9 @@ consvar_t cv_ghost_staff = {"ghost_staff", "Show", CV_SAVE, ghost2_cons_ //Console variables used solely in the menu system. //todo: add a way to use non-console variables in the menu // or make these consvars legitimate like color or skin. -#ifndef NOFOURPLAYER static void Splitplayers_OnChange(void); CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; consvar_t cv_splitplayers = {"splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; -#endif static CV_PossibleValue_t dummymenuplayer_cons_t[] = {{0, "NOPE"}, {1, "P1"}, {2, "P2"}, {3, "P3"}, {4, "P4"}, {0, NULL}}; static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; @@ -506,7 +497,7 @@ static menuitem_t MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_SetPlayersDef, 92}, + {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, @@ -556,10 +547,8 @@ static menuitem_t MPauseMenu[] = {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,40}, {IT_CALL | IT_STRING, NULL, "P1 Setup...", M_SetupMultiPlayer, 48}, // splitscreen {IT_CALL | IT_STRING, NULL, "P2 Setup...", M_SetupMultiPlayer2, 56}, // splitscreen -#ifndef NOFOURPLAYER {IT_CALL | IT_STRING, NULL, "P3 Setup...", M_SetupMultiPlayer3, 64}, // splitscreen {IT_CALL | IT_STRING, NULL, "P4 Setup...", M_SetupMultiPlayer4, 72}, // splitscreen -#endif {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, // alone {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, // alone @@ -582,10 +571,9 @@ typedef enum mpause_continue, mpause_psetupsplit, mpause_psetupsplit2, -#ifndef NOFOURPLAYER mpause_psetupsplit3, mpause_psetupsplit4, -#endif + mpause_spectate, mpause_entergame, mpause_canceljoin, @@ -959,48 +947,40 @@ menuitem_t PlayerMenu[32] = // ----------------------------------- // Prefix: MP_ -#ifndef NONET - -// Set number of players first! -static menuitem_t MP_SetPlayersMenu[] = -{ -#ifndef NOFOURPLAYER - {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_splitplayers, 10}, -#endif - -#ifdef NOFOURPLAYER - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 90}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 100}, -#else - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 80}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 90}, - {IT_GRAYEDOUT, NULL, "P3 Setup...", M_SetupMultiPlayer3, 100}, - {IT_GRAYEDOUT, NULL, "P4 Setup... ", M_SetupMultiPlayer4, 110}, -#endif - {IT_SUBMENU|IT_STRING, NULL, "Next...", &MP_MainDef, 130}, -}; - static menuitem_t MP_MainMenu[] = { - {IT_HEADER, NULL, "Host a game", NULL, 0}, - {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 10}, - {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 18}, - {IT_HEADER, NULL, "Join a game", NULL, 32}, - {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 42}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 50}, + {IT_HEADER, NULL, "Players", NULL, 0}, + {IT_STRING|IT_CVAR, NULL, "Number of local players", &cv_splitplayers, 10}, + + {IT_STRING|IT_KEYHANDLER,NULL, "Player setup...", M_SetupMultiHandler,18}, + + {IT_HEADER, NULL, "Host a game", NULL, 100-24}, +#ifndef NONET + {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 110-24}, +#else + {IT_GRAYEDOUT, NULL, "Internet/LAN...", NULL, 110-24}, +#endif + {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 118-24}, + + {IT_HEADER, NULL, "Join a game", NULL, 132-24}, +#ifndef NONET + {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, +#else + {IT_GRAYEDOUT, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, +#endif //{IT_HEADER, NULL, "Player setup", NULL, 80}, //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, }; -#endif +#ifndef NONET static menuitem_t MP_ServerMenu[] = { {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 10}, -#ifndef NONET {IT_STRING|IT_CALL, NULL, "Room...", M_RoomMenu, 20}, {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 30}, -#endif {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, @@ -1008,6 +988,8 @@ static menuitem_t MP_ServerMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; +#endif + // Separated offline and normal servers. static menuitem_t MP_OfflineServerMenu[] = { @@ -1017,22 +999,6 @@ static menuitem_t MP_OfflineServerMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; -#ifndef NOFOURPLAYER -static void Splitplayers_OnChange(void) -{ - UINT8 i = 1; // player 1 is the last unchanging setup - - while (i < 4) - { - if (i < cv_splitplayers.value) - MP_SetPlayersMenu[i+1].status = IT_STRING|IT_CALL; - else - MP_SetPlayersMenu[i+1].status = IT_GRAYEDOUT; - i++; - } -} -#endif - static menuitem_t MP_PlayerSetupMenu[] = { {IT_KEYHANDLER | IT_STRING, NULL, "Name", M_HandleSetupMultiPlayer, 0}, @@ -1121,14 +1087,10 @@ static menuitem_t OP_ControlsMenu[] = {IT_CALL | IT_STRING, NULL, "Player 1 Controls...", M_Setup1PControlsMenu, 10}, {IT_CALL | IT_STRING, NULL, "Player 2 Controls...", M_Setup2PControlsMenu, 20}, -#ifdef NOFOURPLAYER - {IT_STRING | IT_CVAR, NULL, "Controls per key", &cv_controlperkey, 40}, -#else {IT_CALL | IT_STRING, NULL, "Player 3 Controls...", &M_Setup3PControlsMenu, 30}, {IT_CALL | IT_STRING, NULL, "Player 4 Controls...", &M_Setup4PControlsMenu, 40}, {IT_STRING | IT_CVAR, NULL, "Controls per key", &cv_controlperkey, 60}, -#endif }; static menuitem_t OP_AllControlsMenu[] = @@ -1196,7 +1158,6 @@ static menuitem_t OP_Joystick2Menu[] = {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis2 , 90}, }; -#ifndef NOFOURPLAYER static menuitem_t OP_Joystick3Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup3PJoystickMenu, 10}, @@ -1220,7 +1181,6 @@ static menuitem_t OP_Joystick4Menu[] = {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis4 , 80}, {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis4 , 90}, }; -#endif static menuitem_t OP_JoystickSetMenu[] = { @@ -1871,17 +1831,16 @@ menu_t MP_MainDef = { "M_MULTI", sizeof (MP_MainMenu)/sizeof (menuitem_t), - &MP_SetPlayersDef, + &MainDef, MP_MainMenu, M_DrawMPMainMenu, - 42, 50, + 42, 30, 0, M_CancelConnect }; menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); #endif menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); -menu_t MP_SetPlayersDef = MAPICONMENUSTYLE("M_MULTI", MP_SetPlayersMenu, &MainDef); #ifndef NONET menu_t MP_ConnectDef = { @@ -1935,10 +1894,8 @@ menu_t OP_ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlsMenu, &OP_MainDe menu_t OP_AllControlsDef = CONTROLMENUSTYLE(OP_AllControlsMenu, &OP_ControlsDef); menu_t OP_Joystick1Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_AllControlsDef, 60, 30); menu_t OP_Joystick2Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_AllControlsDef, 60, 30); -#ifndef NOFOURPLAYER menu_t OP_Joystick3Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick3Menu, &OP_AllControlsDef, 60, 30); menu_t OP_Joystick4Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick4Menu, &OP_AllControlsDef, 60, 30); -#endif menu_t OP_JoystickSetDef = { "M_CONTRO", @@ -2943,10 +2900,8 @@ void M_StartControlPanel(void) MPauseMenu[mpause_scramble].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; -#ifndef NOFOURPLAYER MPauseMenu[mpause_psetupsplit3].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit4].status = IT_DISABLED; -#endif MPauseMenu[mpause_spectate].status = IT_DISABLED; MPauseMenu[mpause_entergame].status = IT_DISABLED; MPauseMenu[mpause_canceljoin].status = IT_DISABLED; @@ -2996,7 +2951,6 @@ void M_StartControlPanel(void) } } -#ifndef NOFOURPLAYER if (splitscreen > 1) { MPauseMenu[mpause_psetupsplit3].status = IT_STRING | IT_CALL; @@ -3013,7 +2967,6 @@ void M_StartControlPanel(void) MPauseMenu[mpause_quit].alphaKey += 8; } } -#endif } else { @@ -3138,9 +3091,7 @@ void M_Init(void) return; // Menu hacks -#ifndef NOFOURPLAYER CV_RegisterVar(&cv_splitplayers); -#endif CV_RegisterVar(&cv_dummymenuplayer); CV_RegisterVar(&cv_dummyteam); CV_RegisterVar(&cv_dummyspectate); @@ -6307,7 +6258,7 @@ static void M_DrawStatsMaps(int location) bottomarrow: if (dobottomarrow) V_DrawCharacter(10, y-8 + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // up arrow + '\x1B' | highlightflags, false); // down arrow } static void M_DrawLevelStats(void) @@ -7435,12 +7386,7 @@ static INT32 M_FindFirstMap(INT32 gtype) static void M_StartServer(INT32 choice) { - UINT8 ssplayers = -#ifdef NOFOURPLAYER - 1; -#else - cv_splitplayers.value-1; -#endif + UINT8 ssplayers = cv_splitplayers.value-1; (void)choice; @@ -7617,8 +7563,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) static void M_DrawServerMenu(void) { - if (currentMenu != &MP_SetPlayersDef) - M_DrawLevelSelectOnly(false, false); + M_DrawLevelSelectOnly(false, false); M_DrawGenericMenu(); #ifndef NONET @@ -7634,68 +7579,7 @@ static void M_DrawServerMenu(void) highlightflags, room_list[menuRoomIndex].name); #undef mp_server_room } - else #endif - if (currentMenu == &MP_SetPlayersDef) - // character bar, ripped off the color bar :V - { -#define iconwidth 32 -#define spacingwidth 32 -#define incrwidth (iconwidth + spacingwidth) - UINT8 i = 0, pskin, pcol; - // player arrangement width, but there's also a chance i'm a furry, shhhhhh - const INT32 paw = iconwidth + -#ifndef NOFOURPLAYER - 3* -#endif - incrwidth; - INT32 x = BASEVIDWIDTH/2 - paw/2, y = currentMenu->y + 27, trans = 0; - patch_t *face; - - while (++i <= -#ifdef NOFOURPLAYER - 2 -#else - 4 -#endif - ) - { - switch (i) - { - default: - pskin = R_SkinAvailable(cv_skin.string); - pcol = cv_playercolor.value; - break; - case 2: - pskin = R_SkinAvailable(cv_skin2.string); - pcol = cv_playercolor2.value; - break; - case 3: - pskin = R_SkinAvailable(cv_skin3.string); - pcol = cv_playercolor3.value; - break; - case 4: - pskin = R_SkinAvailable(cv_skin4.string); - pcol = cv_playercolor4.value; - break; - } - - if (pskin >= MAXSKINS) - pskin = 0; - -#ifndef NOFOURPLAYER - if (!trans && i > cv_splitplayers.value) - trans = V_TRANSLUCENT; -#endif - - face = W_CachePatchName(skins[pskin].face, PU_CACHE); - V_DrawFixedPatch(x<y + 32; + + while (++i <= 4) + { + switch (i) + { + default: + pskin = R_SkinAvailable(cv_skin.string); + pcol = cv_playercolor.value; + break; + case 2: + pskin = R_SkinAvailable(cv_skin2.string); + pcol = cv_playercolor2.value; + break; + case 3: + pskin = R_SkinAvailable(cv_skin3.string); + pcol = cv_playercolor3.value; + break; + case 4: + pskin = R_SkinAvailable(cv_skin4.string); + pcol = cv_playercolor4.value; + break; + } + + if (pskin >= MAXSKINS) + pskin = 0; + + if (!trans && i > cv_splitplayers.value) + trans = V_TRANSLUCENT; + + colmap = R_GetTranslationColormap(pskin, pcol, 0); + + face = W_CachePatchName(skins[pskin].face, PU_CACHE); + V_DrawFixedPatch(x< 1) + { + if (--setupm_pselect < 1) + setupm_pselect = cv_splitplayers.value; + S_StartSound(NULL,sfx_menu1); // Tails + } + break; + + case KEY_RIGHTARROW: + if (cv_splitplayers.value > 1) + { + if (++setupm_pselect > cv_splitplayers.value) + setupm_pselect = 1; + S_StartSound(NULL,sfx_menu1); // Tails + } + break; + + case KEY_DOWNARROW: + M_NextOpt(); + S_StartSound(NULL,sfx_menu1); // Tails + break; + + case KEY_UPARROW: + M_PrevOpt(); + S_StartSound(NULL,sfx_menu1); // Tails + break; + + case KEY_ENTER: + { + S_StartSound(NULL,sfx_menu1); // Tails + currentMenu->lastOn = itemOn; + switch (setupm_pselect) + { + case 2: + M_SetupMultiPlayer2(0); + return; + case 3: + M_SetupMultiPlayer3(0); + return; + case 4: + M_SetupMultiPlayer4(0); + return; + default: + M_SetupMultiPlayer(0); + return; + } + break; + } + + case KEY_ESCAPE: + exitmenu = true; + break; + } + + if (exitmenu) + { + if (currentMenu->prevMenu) + M_SetupNextMenu (currentMenu->prevMenu); + else + M_ClearMenus(true); + } +} + +#ifndef NONET + // Tails 11-19-2002 static void M_ConnectIP(INT32 choice) { @@ -8026,6 +8051,7 @@ static void M_DrawSetupMultiPlayerMenu(void) INT32 offx = 8, offy = 8; patch_t *cursor = W_CachePatchName("K_CHRCUR", PU_CACHE); patch_t *face; + UINT8 *colmap; if (col < 0) col += numskins; @@ -8044,9 +8070,10 @@ static void M_DrawSetupMultiPlayerMenu(void) offy = 8; } face = W_CachePatchName(skins[col].face, PU_CACHE); - V_DrawFixedPatch((x+offx)<= numskins) col -= numskins; x += FixedMul(iconwidth<x - 16, y-(skullAnimCounter/5), highlightflags, "\x1A"); // up arrow + V_DrawCharacter(currentMenu->x - 16, y-(skullAnimCounter/5), + '\x1A' | highlightflags, false); // up arrow if (max != currentMenu->numitems) - V_DrawString(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5), highlightflags, "\x1B"); // down arrow + V_DrawCharacter(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5) + (skullAnimCounter/5), + '\x1B' | highlightflags, false); // down arrow for (; i < max; i++) { From 5a1e40f9871c96e4f8db63e2901a1df353777176 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 16 Oct 2018 21:39:39 -0400 Subject: [PATCH 36/36] Quick fix for attack/protect being too big --- src/k_kart.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 31a50bf5..a119b452 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6941,10 +6941,15 @@ static void K_drawBattleFullscreen(void) } else { - if (stplyr == &players[secondarydisplayplayer]) - x = BASEVIDWIDTH-96; + if (stplyr->exiting) + { + if (stplyr == &players[secondarydisplayplayer]) + x = BASEVIDWIDTH-96; + else + x = 96; + } else - x = 96; + scale /= 2; } }