Allow hosting and joining by IP

This commit is contained in:
SinnamonLat 2021-11-14 21:24:09 +01:00
parent cbf108a627
commit fdf778c72f
4 changed files with 407 additions and 49 deletions

View file

@ -183,6 +183,12 @@ extern menu_t PLAY_TimeAttackDef;
extern menuitem_t PLAY_MP_OptSelect[];
extern menu_t PLAY_MP_OptSelectDef;
extern menuitem_t PLAY_MP_Host[];
extern menu_t PLAY_MP_HostDef;
extern menuitem_t PLAY_MP_JoinIP[];
extern menu_t PLAY_MP_JoinIPDef;
extern menuitem_t PLAY_MP_RoomSelect[];
extern menu_t PLAY_MP_RoomSelectDef;
@ -331,7 +337,8 @@ extern struct cupgrid_s {
SINT8 pageno;
UINT8 numpages;
tic_t previewanim;
boolean grandprix; // Setup grand prix server after picking
boolean grandprix; // Setup grand prix server after picking
boolean netgame; // Start the game in an actual server
} cupgrid;
extern struct levellist_s {
@ -342,6 +349,7 @@ extern struct levellist_s {
INT16 choosemap;
UINT8 newgametype;
boolean timeattack; // Setup time attack menu after picking
boolean netgame; // Start the game in an actual server
} levellist;
boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt);
@ -361,6 +369,9 @@ void M_LevelSelectTick(void);
extern struct mpmenu_s {
UINT8 modechoice;
INT16 modewinextend[3][3]; // Used to "extend" the options in the mode select screen.
// format for each option: {extended?, max extension, # lines extended}
// See M_OptSelectTick, it'll make more sense there. Sorry if this is a bit of a mess!
UINT8 room;
@ -371,6 +382,18 @@ extern struct mpmenu_s {
void M_MPOptSelect(INT32 choice);
void M_MPOptSelectInit(INT32 choice);
void M_MPOptSelectTick(void);
boolean M_MPResetOpts(void);
consvar_t cv_dummygametype; // lazy hack to allow us to select the GT on the server host submenu
consvar_t cv_dummyip; // I HAVE
// HAVE YOUR IP ADDRESS (This just the hack Cvar we'll type into and then it apends itself to "connect" in the console for IP join)
// MP Host
void M_MPHostInit(INT32 choice);
void M_MPSetupNetgameMapSelect(INT32 choice);
// MP join by IP
void M_MPJoinIPInit(INT32 choice);
void M_JoinIP(void);
// Server browser room selection
void M_MPRoomSelect(INT32 choice);
@ -414,6 +437,8 @@ void M_DrawTimeAttack(void);
// Multiplayer menu stuff
void M_DrawMPOptSelect(void);
void M_DrawMPHost(void);
void M_DrawMPJoinIP(void);
void M_DrawMPRoomSelect(void);
// Replay Playback

View file

@ -176,10 +176,10 @@ menuitem_t PLAY_MP_OptSelect[] =
{
//{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_MPOptSelect, 0, 0},
{IT_STRING | IT_CALL, "Host Game", "Start your own online game!",
NULL, NULL, 0, 0},
NULL, M_MPHostInit, 0, 0},
{IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.",
NULL, NULL, 0, 0},
NULL, M_MPJoinIPInit, 0, 0},
{IT_STRING | IT_CALL, "Server Browser", "Search for game servers to play in.",
NULL, M_MPRoomSelectInit, 0, 0},
@ -191,12 +191,69 @@ menu_t PLAY_MP_OptSelectDef = {
0,
PLAY_MP_OptSelect,
0, 0,
0, 0,
-1, 1,
M_DrawMPOptSelect,
M_MPOptSelectTick,
NULL
};
// MULTIPLAYER HOST SCREEN
menuitem_t PLAY_MP_Host[] =
{
//{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_MPOptSelect, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Server Name", "Display name for your game online. Other players will see this.",
NULL, &cv_servername, 0, 0},
{IT_STRING | IT_CVAR, "Public Server", "Display or not your game in the Server Browser for other players.",
NULL, &cv_advertise, 0, 0},
{IT_STRING | IT_CVAR, "Max. Players", "Set how many players can play at once. Others will spectate.",
NULL, &cv_ingamecap, 0, 0},
{IT_STRING | IT_CVAR, "Gamemode", "Are we racing? Or perhaps battling?",
NULL, &cv_dummygametype, 0, 0},
{IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode",
NULL, M_MPSetupNetgameMapSelect, 0, 0},
};
menu_t PLAY_MP_HostDef = {
sizeof (PLAY_MP_Host) / sizeof (menuitem_t),
&PLAY_MP_OptSelectDef,
0,
PLAY_MP_Host,
0, 0,
-1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe
M_DrawMPHost,
M_MPOptSelectTick, // This handles the unfolding options
M_MPResetOpts
};
// MULTIPLAYER JOIN BY IP
menuitem_t PLAY_MP_JoinIP[] =
{
//{IT_NOTHING | IT_KEYHANDLER, NULL, NULL, NULL, M_MPOptSelect, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Address: ", "Type the IPv4 address of the server you wish to connect to.",
NULL, &cv_dummyip, 0, 0},
{IT_STRING | IT_CALL, "GO", "Select a map with the currently selected gamemode",
NULL, M_JoinIP, 0, 0},
};
menu_t PLAY_MP_JoinIPDef = {
sizeof (PLAY_MP_JoinIP) / sizeof (menuitem_t),
&PLAY_MP_OptSelectDef,
0,
PLAY_MP_JoinIP,
0, 0,
-1, 1, // 1 frame transition.... This is really just because I don't want the black fade when we press esc, hehe
M_DrawMPJoinIP,
M_MPOptSelectTick, // This handles the unfolding options
M_MPResetOpts
};
// MULTIPLAYER ROOM SELECT (CORE / MODDED)
menuitem_t PLAY_MP_RoomSelect[] =

View file

@ -1306,23 +1306,19 @@ void M_DrawTimeAttack(void)
}
// This draws the options of a given menu in a fashion specific to the multiplayer option select screen (host game / server browser etc)
// TODO: Add 2nd argument that lets us "expand" a given option via an array
// First argument is the menu to draw the options from, the 2nd one is a table that contains which option is to be "extendded"
// Format for each option: {extended? (only used by the ticker), max extension (likewise), # of lines to extend}
static void M_MPOptDrawer(menu_t *m)
// NOTE: This is pretty rigid and only intended for use with the multiplayer options menu which has *3* choices.
static void M_MPOptDrawer(menu_t *m, INT16 extend[3][3])
{
// This is a copypaste of the generic gamemode menu code with a few changes.
// TODO: Allow specific options to "expand" into smaller ones.
patch_t *buttback = W_CachePatchName("M_PLAT2", PU_CACHE);
UINT8 n = m->numitems-1;
INT32 i, x = 142, y = 32; // Dirty magic numbers for now but they work out.
if (menutransition.tics)
{
x += 24 * menutransition.tics;
}
for (i = 0; i < m->numitems; i++)
{
@ -1331,8 +1327,9 @@ static void M_MPOptDrawer(menu_t *m)
case IT_STRING:
{
UINT8 *colormap = NULL;
INT16 j = 0;
if (i == itemOn)
if ((currentMenu == m && i == itemOn) || extend[i][0]) // Selected / unfolded
{
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
}
@ -1341,28 +1338,184 @@ static void M_MPOptDrawer(menu_t *m)
colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_MOSS, GTC_CACHE);
}
V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, 0, buttback, colormap);
if (extend[i][2])
{
for (j=0; j < extend[i][2]/2; j++)
{
// Draw rectangles that look like the current selected item starting from the top of the actual selection graphic and going up to where it's supposed to go.
// With colour 169 (that's the index of the shade of black the plague colourization gives us. ...No I don't like using a magic number either.
V_DrawFill(x + (extend[i][2]/2) - j - (buttback->width/2), (y + extend[i][2]) - (2*j), 225, 2, 169);
}
}
V_DrawFixedPatch((x + (extend[i][2]/2)) *FRACUNIT, (y + extend[i][2])*FRACUNIT, FRACUNIT, 0, buttback, colormap);
V_DrawCenteredGamemodeString(x, y - 3, V_ALLOWLOWERCASE, colormap, m->menuitems[i].text);
}
break;
}
x += GM_XOFFSET;
y += GM_YOFFSET;
y += GM_YOFFSET + extend[i][2];
}
}
// Draws the EGGA CHANNEL background.
static void M_DrawEggaChannel(void)
{
patch_t *background = W_CachePatchName("M_EGGACH", PU_CACHE);
V_DrawFill(0, 0, 999, 999, 25);
V_DrawFixedPatch(160<<FRACBITS, 104<<FRACBITS, FRACUNIT, 0, background, NULL);
V_DrawVhsEffect(false); // VHS the background! (...sorry OGL my love)
}
// Multiplayer mode option select
void M_DrawMPOptSelect(void)
{
patch_t *background = W_CachePatchName("M_EGGACH", PU_CACHE);
V_DrawFill(0, 0, 999, 999, 25);
V_DrawFixedPatch(160<<FRACBITS, 104<<FRACBITS, FRACUNIT, 0, background, NULL);
M_DrawEggaChannel();
M_DrawMenuTooltips();
M_MPOptDrawer(currentMenu);
M_MPOptDrawer(&PLAY_MP_OptSelectDef, mpmenu.modewinextend);
}
// Multiplayer mode option select: HOST GAME!
// A rehash of the generic menu drawer adapted to fit into that cramped space. ...A small sacrifice for utility
void M_DrawMPHost(void)
{
patch_t *gobutt = W_CachePatchName("M_BUTTGO", PU_CACHE); // I'm very mature
INT32 xp = 50, yp = 64, i = 0, w = 0; // Starting position for the text drawing.
M_DrawMPOptSelect(); // Draw the Multiplayer option select menu first
// Now draw our host options...
for (i = 0; i < currentMenu->numitems; i++)
{
if (i == currentMenu->numitems-1)
{
UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_MOSS, GTC_CACHE);
if (i == itemOn)
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
// Ideally we'd calculate this but it's not worth it for a 1-off menu probably.....
V_DrawFixedPatch(212<<FRACBITS, 100<<FRACBITS, FRACUNIT, 0, gobutt, colormap);
V_DrawCenteredGamemodeString(212 + (gobutt->width/2), 100 -3, V_ALLOWLOWERCASE, colormap, currentMenu->menuitems[i].text);
}
else
{
switch (currentMenu->menuitems[i].status & IT_DISPLAY)
{
case IT_STRING:
{
V_DrawString(xp, yp, V_ALLOWLOWERCASE | (i == itemOn ? highlightflags : 0), currentMenu->menuitems[i].text);
// Cvar specific handling
switch (currentMenu->menuitems[i].status & IT_TYPE)
{
case IT_CVAR:
{
consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction;
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CV_STRING:
V_DrawThinString(xp + 96, yp, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(xp + 93 + V_ThinStringWidth(cv->string, 0), yp +1, '_' | 0x80, false);
break;
default:
w = V_StringWidth(cv->string, 0);
V_DrawString(xp + 138 - w, yp, ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags), cv->string);
if (i == itemOn)
{
V_DrawCharacter(xp + 138 - 10 - w - (skullAnimCounter/5), yp, '\x1C' | highlightflags, false); // left arrow
V_DrawCharacter(xp + 138 + 2 + (skullAnimCounter/5), yp, '\x1D' | highlightflags, false); // right arrow
}
break;
}
break;
}
}
xp += 5;
yp += 11;
break;
}
break;
}
}
}
}
// Multiplayer mode option select: JOIN BY IP
// Once again we'll copypaste 1 bit of the generic menu handler we used for hosting but we only need it for IT_CV_STRING since that's all we got :)
// (I don't like duplicating code but I rather this than some horrible all-in-one function with too many options...)
void M_DrawMPJoinIP(void)
{
patch_t *gobutt = W_CachePatchName("M_BUTTGO", PU_CACHE); // I'm very mature
INT32 xp = 70, yp = 100, i = 0; // Starting position for the text drawing.
M_DrawMPOptSelect(); // Draw the Multiplayer option select menu first
// Now draw our host options...
for (i = 0; i < currentMenu->numitems; i++)
{
if (i == currentMenu->numitems-1)
{
UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_MOSS, GTC_CACHE);
if (i == itemOn)
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE);
// Ideally we'd calculate this but it's not worth it for a 1-off menu probably.....
V_DrawFixedPatch(219<<FRACBITS, 114<<FRACBITS, FRACUNIT, 0, gobutt, colormap);
V_DrawCenteredGamemodeString(219 + (gobutt->width/2), 114 -3, V_ALLOWLOWERCASE, colormap, currentMenu->menuitems[i].text);
}
else
{
switch (currentMenu->menuitems[i].status & IT_DISPLAY)
{
case IT_STRING:
{
V_DrawString(xp, yp, V_ALLOWLOWERCASE | (i == itemOn ? highlightflags : 0), currentMenu->menuitems[i].text);
// Cvar specific handling
switch (currentMenu->menuitems[i].status & IT_TYPE)
{
case IT_CVAR:
{
consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction;
switch (currentMenu->menuitems[i].status & IT_CVARTYPE)
{
case IT_CV_STRING:
V_DrawThinString(xp + 65, yp-1, V_ALLOWLOWERCASE, cv->string);
if (skullAnimCounter < 4 && i == itemOn)
V_DrawCharacter(xp + 65 + V_ThinStringWidth(cv->string, 0), yp, '_' | 0x80, false);
break;
default:
break;
}
break;
}
}
xp += 5;
yp += 11;
break;
}
break;
}
}
}
}
// Multiplayer room select

View file

@ -164,12 +164,15 @@ static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2
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 dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}};
static CV_PossibleValue_t dummygametype_cons_t[] = {{0, "Race"}, {1, "Battle"}, {0, NULL}};
static consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange);
static consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDDEN, dummyteam_cons_t, NULL);
static consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDDEN, dummyspectate_cons_t, NULL);
static consvar_t cv_dummyscramble = CVAR_INIT ("dummyscramble", "Random", CV_HIDDEN, dummyscramble_cons_t, NULL);
static consvar_t cv_dummystaff = CVAR_INIT ("dummystaff", "0", CV_HIDDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange);
consvar_t cv_dummygametype = CVAR_INIT ("dummygametype", "Race", CV_HIDDEN, dummygametype_cons_t, NULL);
consvar_t cv_dummyip = CVAR_INIT ("dummyip", "", CV_HIDDEN, NULL, NULL);
// ==========================================================================
// CVAR ONCHANGE EVENTS GO HERE
@ -1559,6 +1562,8 @@ void M_Init(void)
CV_RegisterVar(&cv_dummyspectate);
CV_RegisterVar(&cv_dummyscramble);
CV_RegisterVar(&cv_dummystaff);
CV_RegisterVar(&cv_dummygametype);
CV_RegisterVar(&cv_dummyip);
M_UpdateMenuBGImage(true);
@ -2286,30 +2291,10 @@ static void M_LevelSelectScrollDest(void)
levellist.dest = (6*m)-3;
}
void M_LevelSelectInit(INT32 choice)
// Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu.
static void M_LevelListFromGametype(INT16 gt)
{
(void)choice;
switch (currentMenu->menuitems[itemOn].mvar1)
{
case 0:
cupgrid.grandprix = false;
levellist.timeattack = false;
break;
case 1:
cupgrid.grandprix = false;
levellist.timeattack = true;
break;
case 2:
cupgrid.grandprix = true;
levellist.timeattack = false;
break;
default:
CONS_Alert(CONS_WARNING, "Bad level select init\n");
return;
}
levellist.newgametype = currentMenu->menuitems[itemOn].mvar2;
levellist.newgametype = gt;
PLAY_CupSelectDef.prevMenu = currentMenu;
// Obviously go to Cup Select in gametypes that have cups.
@ -2351,6 +2336,41 @@ void M_LevelSelectInit(INT32 choice)
PLAY_LevelSelectDef.prevMenu = currentMenu;
M_SetupNextMenu(&PLAY_LevelSelectDef, false);
}
// Init level select for use in local play using the last choice we made.
// For the online MP version, see M_MPSetupNetgameMapSelect()
void M_LevelSelectInit(INT32 choice)
{
(void)choice;
levellist.netgame = false; // Make sure this is reset as we'll only be using this function for offline games!
cupgrid.netgame = false; // Ditto
switch (currentMenu->menuitems[itemOn].mvar1)
{
case 0:
cupgrid.grandprix = false;
levellist.timeattack = false;
break;
case 1:
cupgrid.grandprix = false;
levellist.timeattack = true;
break;
case 2:
cupgrid.grandprix = true;
levellist.timeattack = false;
break;
default:
CONS_Alert(CONS_WARNING, "Bad level select init\n");
return;
}
levellist.newgametype = currentMenu->menuitems[itemOn].mvar2;
M_LevelListFromGametype(levellist.newgametype);
}
void M_CupSelectHandler(INT32 choice)
@ -2433,6 +2453,7 @@ void M_CupSelectHandler(INT32 choice)
paused = false;
SV_StartSinglePlayerServer();
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
netgame = levellist.netgame; // ^ ditto.
D_MapChange(
grandprixinfo.cup->levellist[0] + 1,
GT_RACE,
@ -2567,6 +2588,8 @@ void M_LevelSelectHandler(INT32 choice)
paused = false;
SV_StartSinglePlayerServer();
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
netgame = levellist.netgame; // ^ ditto.
D_MapChange(levellist.choosemap+1, levellist.newgametype, (cv_kartencore.value == 1), 1, 1, false, false);
M_ClearMenus(true);
@ -2609,22 +2632,121 @@ void M_LevelSelectTick(void)
struct mpmenu_s mpmenu;
// MULTIPLAYER OPTION SELECT
void M_MPOptSelect(INT32 choice)
{
// Use this as a quit routine within the HOST GAME and JOIN BY IP "sub" menus
boolean M_MPResetOpts(void)
{
UINT8 i = 0;
for (; i < 3; i++)
mpmenu.modewinextend[i][0] = 0; // Undo this
return true;
}
void M_MPOptSelectInit(INT32 chocie)
void M_MPOptSelectInit(INT32 choice)
{
INT16 arrcpy[3][3] = {{0,68,0}, {0,48,0}, {0,12,0}};
UINT8 i = 0, j = 0; // To copy the array into the struct
(void)choice;
mpmenu.modechoice = 0;
mpmenu.ticker = 0;
for (; i < 3; i++)
for (j = 0; j < 3; j++)
mpmenu.modewinextend[i][j] = arrcpy[i][j]; // I miss Lua already
M_SetupNextMenu(&PLAY_MP_OptSelectDef, false);
}
void M_MPOptSelectTick(void)
{
UINT8 i = 0;
// 3 Because we have 3 options in the menu
for (; i < 3; i++)
{
if (mpmenu.modewinextend[i][0])
mpmenu.modewinextend[i][2] += 8;
else
mpmenu.modewinextend[i][2] -= 8;
mpmenu.modewinextend[i][2] = min(mpmenu.modewinextend[i][1], max(0, mpmenu.modewinextend[i][2]));
//CONS_Printf("%d - %d,%d,%d\n", i, mpmenu.modewinextend[i][0], mpmenu.modewinextend[i][1], mpmenu.modewinextend[i][2]);
}
}
// MULTIPLAYER HOST
void M_MPHostInit(INT32 choice)
{
(void)choice;
mpmenu.modewinextend[0][0] = 1;
M_SetupNextMenu(&PLAY_MP_HostDef, true);
}
void M_MPSetupNetgameMapSelect(INT32 choice)
{
INT16 gt = GT_RACE;
(void)choice;
levellist.netgame = true; // Yep, we'll be starting a netgame.
cupgrid.netgame = true; // Ditto
levellist.timeattack = false; // Make sure we reset those
cupgrid.grandprix = false; // Ditto
// In case we ever want to add new gamemodes there somehow, have at it!
switch (cv_dummygametype.value)
{
case 1: // Battle
{
gt = GT_BATTLE;
break;
}
default:
{
gt = GT_RACE;
break;
}
}
M_LevelListFromGametype(gt); // Setup the level select.
// (This will also automatically send us to the apropriate menu)
}
// MULTIPLAYER JOIN BY IP
void M_MPJoinIPInit(INT32 choice)
{
(void)choice;
mpmenu.modewinextend[1][0] = 1;
M_SetupNextMenu(&PLAY_MP_JoinIPDef, true);
}
// Attempts to join a given IP from the menu.
void M_JoinIP(void)
{
if (*(cv_dummyip.string) == '\0') // Jack shit
{
M_StartMessage("Please specify an address.\n", NULL, MM_NOTHING);
return;
}
COM_BufAddText(va("connect \"%s\"\n", cv_dummyip.string));
M_ClearMenus(true);
// A little "please wait" message.
M_DrawTextBox(56, BASEVIDHEIGHT/2-12, 24, 2);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Connecting to server...");
I_OsPolling();
I_UpdateNoBlit();
if (rendermode == render_soft)
I_FinishUpdate(); // page flip or blit buffer
}
// MULTIPLAYER ROOM SELECT MENU
@ -2664,6 +2786,7 @@ void M_MPRoomSelectTick(void)
void M_MPRoomSelectInit(INT32 choice)
{
(void)choice;
mpmenu.room = 0;
mpmenu.ticker = 0;