Files
Descent3/Descent3/multi_ui.cpp
2024-08-15 11:50:36 +03:00

1825 lines
54 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/main/multi_ui.cpp $
* $Revision: 105 $
* $Date: 7/09/01 3:34p $
* $Author: Matt $
*
*
*
* $Log: /DescentIII/main/multi_ui.cpp $
*
* 105 7/09/01 3:34p Matt
* Require at least one allowed ship when starting a netgame.
*
* 104 4/20/00 6:25p Matt
* Netgame info dialog was looking at wrong variable for the difficulty
* level.
*
* 103 8/02/99 9:57a Kevin
* fixed port parameter with -pxo
*
* 102 5/19/99 1:10p Kevin
* set the default (or previously selected) difficulty level
*
* 101 5/09/99 4:55p Kevin
* Added some options for directplay games
*
* 100 5/09/99 1:34p Kevin
* Added diffuculty level system to multiplayer
*
* 99 5/08/99 3:58p Kevin
* made ESC clear the game info dialog
*
* 98 5/06/99 6:11p Kevin
* fixes for save/load game syste. Also require CD again and added some
* heat.net stuff
*
* 97 5/06/99 1:04a Kevin
* Fixed stupid default selection problem
*
* 96 5/05/99 11:59p Kevin
* fixed command line parms for auto connecting
*
* 95 5/05/99 11:16p Kevin
* heat.net stuff among other things
*
* 94 4/28/99 10:04p Kevin
* doh! forgot to return a value
*
* 93 4/28/99 6:39p Kevin
* Build 182 fixes
*
* 92 4/26/99 9:11p Matt
* Use small font instead of old UI font.
*
* 91 4/25/99 5:02p Kevin
* Bunches of multiplayer UI improvements
*
* 90 4/25/99 9:44a Kevin
* localized remaining game info strings
*
* 89 4/25/99 8:58a Kevin
* fixes for server info dialog
*
* 88 4/24/99 11:58p Kevin
* Game info list (hit I in the pxo game list)
*
* 87 4/23/99 5:32p Kevin
* Fixed a few mission bugs.
*
* 86 4/20/99 11:47a Samir
* converted protocol help to newui and fixed connection menu so enter
* worked on listbox.
*
* 85 4/17/99 3:44p Kevin
* Demo2 changes & fixes
*
* 84 4/16/99 6:00p Kevin
* Bunches of Demo stuff
*
* 83 4/16/99 3:17p Kevin
* More mouselook support
*
* 82 4/16/99 11:56a Matt
* Changed directplay code to be "ifdef _WIN32" instead of "ifndef
* __LINUX__" so it will work on the Mac.
*
* 81 4/15/99 3:36p Kevin
* Added mouselook UI stuff to the multiplayer options menu
*
* 80 4/15/99 1:41a Jeff
* changes for linux compile
*
* 79 4/14/99 4:19a Jeff
* more case mismatch fixes in #includes
*
* 78 4/14/99 2:51a Jeff
* fixed some case mismatched #includes
*
* 77 4/08/99 4:54p Kevin
* Display level warp dialog for multiplayer
*
* 76 4/03/99 9:26p Jeff
* changed dialogs that weren't using UID_OK and UID_CANCEL to use and
* handle them properly
*
* 75 3/25/99 3:29p Jason
* added option to randomize powerup respawn points
*
* 74 3/03/99 12:44p Jason
* made options mirror that of the 1.1 demo
*
* 73 3/01/99 12:55a Matt
* Deleted some obsolete strings from the string table, and moved some
* formatting info from the table to the code.
*
* 72 2/28/99 6:00p Jeff
* converted to new ui
*
* 71 2/24/99 4:00p Jason
* fixed flush problem when going to the join menu
*
* 70 2/20/99 2:31p Kevin
* Made multiplayer DLLs return to the game list after a game.
*
* 69 2/15/99 7:50p Jeff
* new pilot file class and read/write system checked in...should be more
* robust than old
*
* 68 2/10/99 1:32p Kevin
* Added tablefile ignore thingy
*
* 67 2/08/99 2:39p Kevin
* Fixed command line joining & disabled gamespy launching in OEM builds
*
* 66 1/29/99 5:22p Jeff
* localization
*
* 65 1/23/99 3:21p Kevin
* Fixed default selection to work with new sorted listboxes
*
* 64 1/05/99 5:09p Jason
* added permissable server networking (ala Quake/Unreal) to Descent3
*
* 63 1/04/99 6:56p Kevin
* Fixed unmatched if/else
*
* 62 12/30/98 3:49p Kevin
* Moved multiplayer options out of DLL and into main app
*
* 61 11/20/98 11:16a Kevin
* Fixed command line game launching
*
* 60 11/19/98 5:40p Kevin
* Demo system
*
* 59 10/24/98 10:49a Kevin
* Fixed Direct Serial Game
*
* 58 10/20/98 5:47p Kevin
* Gunboy and other fixes
*
* 57 10/19/98 11:54a Kevin
*
* 56 10/19/98 10:54a Kevin
* Fixed help option
*
* 55 10/16/98 11:55a Kevin
* Made dlls loadable in a hog
*
* 54 10/15/98 10:58a Kevin
* fixed ~ thingy for the first file in the dir
*
* 53 10/14/98 2:48p Kevin
* Changed memory code to comply with mem lib
*
* 52 10/09/98 12:59a Craig
* Fixed ship name for demo
*
* 51 10/06/98 5:34p Jeff
* various UI changes/improvements
*
* 50 10/01/98 11:45a Kevin
* fixed hotspot colors in allow/disallow screen
*
* 49 9/30/98 10:36a Kevin
* Added command line launching of URLs and command line directory
* specification
*
* 48 9/29/98 2:23p Kevin
* More UI tweaks
*
* 47 9/28/98 6:53p Kevin
* localized some multiplayer menus
*
* 46 9/28/98 4:35p Jeff
* general UI changes and improvements
*
* 45 9/28/98 4:21p Kevin
* Redesigned game list menus
*
* 44 9/28/98 9:53a Kevin
* Fixing misc UI problems, and fixed some bugs that VC 6 found
*
* 43 9/25/98 11:07a Kevin
* fixed columns to line up and cleaned up some PXO bugs
*
* 42 9/23/98 6:33p Kevin
* Fixed load settings
*
* 41 9/23/98 2:54p Kevin
* Saved multi config and changed UI to conform
*
* 40 9/22/98 3:55p Kevin
* Removed obsolete function
*
* 39 9/22/98 2:29p Kevin
* moved ships allowed code out of dll and into main app. Also added
* powerup exclusions
*
* 38 8/26/98 1:31p Jason
* Flush buffers before starting a game
*
* 37 8/17/98 11:00a Kevin
* Moved DLLs into subdirectories
*
* 36 8/15/98 5:16p Matt
* Added new Base_directory variable. Got rid of D3_LOCAL check and
* 'local directory' registry variable.
*
* 35 7/10/98 10:47a Kevin
* Added command line connecting to games
*
* 34 7/01/98 2:52p Kevin
* coop -- adding sound index
*
* 33 6/24/98 6:40p Kevin
* Added help to main dll menu
*
* 32 6/18/98 4:49p Kevin
* Updated multiplayer menus
*
* 31 6/16/98 10:54a Jeff
*
* 30 6/11/98 2:33p Kevin
* Updated dsps for new dll names
*
* 29 6/11/98 2:11p Kevin
* New Main multiplayer menu & dlls renamed to d3c
*
* 28 6/01/98 12:09p Kevin
* closed the menu before loading DLLs
*
* 27 6/01/98 10:09a Kevin
* Added DLL connection interface and auto update DLL
*
* 26 5/12/98 5:59p Jason
* fixed stupid timer bug
*
* 25 5/05/98 3:02p Jason
* attempting to add different screen resolutions
*
* 24 5/04/98 10:56a Kevin
* Mastertracker fixes/enhancements
*
* 23 5/01/98 12:28p Kevin
* Added new user registration button for MT
*
* 22 4/30/98 3:50p Kevin
* Mastertracker pilot stats
*
* 21 4/28/98 12:50p Kevin
* Master tracker login
*
* 20 4/27/98 7:12p Kevin
* Mastertracker pilot tracker
*
* 19 4/24/98 3:50p Kevin
* Added mastertracker game tracking support
*
* 18 4/23/98 4:49p Kevin
* Added Master tracker Game tracker support
*
* 17 4/23/98 2:12p Kevin
* Adding Mastertracker stuff
*
* 16 4/14/98 7:56p Matt
* Moved MSN_NAMELEN from mission.h to descent,h, so multi.h didn't need
* to include mission.h.
* Changed code to use ddio_MakePath() instead of sprintf() to make file
* spec.
*
*/
#include <algorithm>
#include <cstdlib>
#include <filesystem>
#include <regex>
#include <string>
#include "args.h"
#include "ui.h"
#include "newui.h"
#include "game.h"
#include "gamefont.h"
#include "descent.h"
#include "multi.h"
#include "multi_dll_mgr.h"
#include "multi_save_settings.h"
#include "multi_ui.h"
#include "networking.h"
#include "player.h"
#include "manage.h"
#include "menu.h"
#include "pilot.h"
#include "ddio.h"
#include "objinfo.h"
#include "ship.h"
#include "stringtable.h"
#include "ConfigItem.h"
#include "Mission.h"
#include "appdatabase.h"
// #define USE_DIRECTPLAY
#ifdef USE_DIRECTPLAY
#include "directplay.h"
#endif
#define MAIN_MULTI_MENU_W 384
#define MAIN_MULTI_MENU_H 256
#define MAIN_MULTI_MENU_X (320 - (MAIN_MULTI_MENU_W / 2))
#define MAIN_MULTI_MENU_Y (240 - (MAIN_MULTI_MENU_H / 2))
#define HELP_MULTI_MENU_W 512
#define HELP_MULTI_MENU_H 192
#define HELP_MULTI_MENU_X (320 - (MAIN_MULTI_MENU_W / 2))
#define HELP_MULTI_MENU_Y (240 - (MAIN_MULTI_MENU_H / 2))
#define MAX_HELP_TEXT_LEN 1000
char HelpText1[MAX_HELP_TEXT_LEN];
char HelpText2[MAX_HELP_TEXT_LEN];
char HelpText3[MAX_HELP_TEXT_LEN];
char HelpText4[MAX_HELP_TEXT_LEN];
int MultiDLLGameStarting = 0;
void DisplayNetDLLHelp(const char *topic);
// The first multiplayer menu that the user will see...all multiplayer stuff is
// reached from this menu
// Returns true if we're starting a multiplayer game
#define MAX_DLLS 10
#define JEFF_RED GR_RGB(255, 40, 40)
#define MAX_NET_DLL_LEN 100
#define UID_MULTILB 0x1000
#define PXO_NAME "Parallax Online"
int MainMultiplayerMenu() {
mprintf(0, "Entering MainMultiplayerMenu()\n");
#ifdef USE_DIRECTPLAY
Num_directplay_games = 0;
#endif
int exit_menu = 0;
int ret = 0;
char sznetgame[MAX_NET_DLL_LEN] = "";
int netgamelen = MAX_NET_DLL_LEN;
int i;
uint32_t j;
for (i = 0; i < MAX_OBJECT_IDS; i++) {
if (Object_info[i].type == OBJ_POWERUP) {
Object_info[i].multi_allowed = 1;
}
}
for (i = 0; i < MAX_SHIPS; i++) {
if (Ships[i].used) {
#ifdef DEMO
if (stricmp(Ships[i].name, "pyro-gl") == 0)
#endif
PlayerSetShipPermission(-1, Ships[i].name, 1);
#ifdef DEMO
else
PlayerSetShipPermission(-1, Ships[i].name, 0);
#endif
}
}
// Clear out residual junk
MultiFlushAllIncomingBuffers();
SetScreenMode(SM_MENU);
Database->read("DefaultNetConn", sznetgame, &netgamelen);
if (*sznetgame == '\0') {
strcpy(sznetgame, PXO_NAME);
Database->write("DefaultNetConn", sznetgame, strlen(sznetgame) + 1);
}
newuiTiledWindow menu_wnd;
newuiListBox *lists;
newuiSheet *sheet;
menu_wnd.Create(TXT_MULTIPLAYER, 0, 0, MAIN_MULTI_MENU_W, MAIN_MULTI_MENU_H);
sheet = menu_wnd.GetSheet();
sheet->NewGroup(TXT_MLTCHOOSETYPE, 25, 0);
lists = sheet->AddListBox(256, 128, UID_MULTILB, UILB_NOSORT);
lists->RemoveAll();
sheet->NewGroup(NULL, 75, 145);
sheet->AddLongButton(TXT_SETITEMDEFAULT, 0x30);
sheet->NewGroup(NULL, 55, 160, NEWUI_ALIGN_HORIZ);
sheet->AddButton(TXT_OK, UID_OK);
sheet->AddButton(TXT_REALHELP, 0x20);
sheet->AddButton(TXT_CANCEL, UID_CANCEL);
int dftidx = -1;
int dllcount = 0;
std::vector<std::string> dllnames;
ddio_DoForeachFile(std::filesystem::path(Base_directory) / "online", std::regex(".*\\.d3c"),
[&dllnames](const std::filesystem::path &path) {
std::string filename = path.stem().string();
std::replace(filename.begin(), filename.end(), '~', '/');
// Place PXO_NAME first in list
if (stricmp(filename.c_str(), PXO_NAME) == 0) {
dllnames.insert(dllnames.begin(), filename);
} else {
dllnames.push_back(filename);
}
});
for (auto const &name : dllnames) {
lists->AddItem(name.c_str());
dllcount++;
if (stricmp(name.c_str(), sznetgame) != 0) {
dftidx = dllcount;
}
}
if (dllcount == 0) {
DoMessageBox(TXT_MULTIPLAYER, TXT_MULTINOFILES, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
exit_menu = 1;
menu_wnd.Destroy();
return 0;
}
if (dftidx != -1) {
lists->SetCurrentItem(sznetgame); //>SetCurrentIndex(dftidx);
}
MultiDLLGameStarting = 0;
menu_wnd.Open();
// Menu loop
char seldll[_MAX_PATH];
while (!exit_menu) {
int res;
res = menu_wnd.DoUI();
// handle all UI results.
switch (res) {
case UID_CANCEL:
menu_wnd.Close();
exit_menu = 1;
break;
case UID_MULTILB:
case UID_OK: {
menu_wnd.Close();
lists->GetCurrentItem(seldll, _MAX_PATH);
uint32_t len = strlen(seldll);
for (j = 0; j < len; j++) {
if (seldll[j] == '/') {
seldll[j] = '~';
}
}
// ddio_MakePath(fulldll,Base_directory,"online",seldll,NULL);
if (LoadMultiDLL(seldll)) {
CallMultiDLL(MT_EVT_LOGIN);
exit_menu = 1;
ret = MultiDLLGameStarting;
} else {
exit_menu = 1;
ret = 0;
}
} break;
case 0x20:
// Help
{
lists->GetCurrentItem(seldll, _MAX_PATH);
uint32_t len = strlen(seldll);
for (j = 0; j < len; j++) {
if (seldll[j] == '/') {
seldll[j] = '~';
}
}
// ddio_MakePath(fulldll,Base_directory,"online",seldll,NULL);
if (LoadMultiDLL(seldll)) {
CallMultiDLL(MT_EVT_GET_HELP);
DisplayNetDLLHelp(seldll);
FreeMultiDLL();
}
}
break;
case 0x30:
// case 3:
{
char fmtmsg[200];
char def[256];
// Mark this baby as default.
lists->GetCurrentItem(def, 256);
Database->write("DefaultNetConn", def, strlen(def) + 1);
snprintf(fmtmsg, sizeof(fmtmsg), TXT_SETDEFAULT, def);
DoMessageBox(TXT_MENUMULTIPLAYER, fmtmsg, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
break;
}
}
}
menu_wnd.Destroy();
return ret;
}
void DisplayNetDLLHelp(const char *topic) {
// samir- converted to newui.
newuiTiledWindow menu_wnd;
newuiSheet *sheet;
int exit_menu = 0;
char str[128];
SetScreenMode(SM_MENU);
// Create our buttons
snprintf(str, sizeof(str), "%s: %s", TXT_REALHELP, topic);
menu_wnd.Create(str, 0, 0, HELP_MULTI_MENU_W, HELP_MULTI_MENU_H);
sheet = menu_wnd.GetSheet();
sheet->NewGroup(NULL, 10, 30);
sheet->AddText(HelpText1);
sheet->AddText(HelpText2);
sheet->AddText(HelpText3);
sheet->AddText(HelpText4);
sheet->NewGroup(NULL, (HELP_MULTI_MENU_W - 140), HELP_MULTI_MENU_H - 95, NEWUI_ALIGN_HORIZ);
sheet->AddButton(TXT_CLOSE, UID_OK);
menu_wnd.Open();
// Menu loop
while (!exit_menu) {
int res;
res = menu_wnd.DoUI();
// handle all UI results.
switch (res) {
case UID_OK:
exit_menu = 1;
break;
}
}
menu_wnd.Close();
menu_wnd.Destroy();
}
int AutoConnectPXO() {
// char seldll[_MAX_PATH];
int iparg;
int portarg;
MultiDLLGameStarting = 0;
iparg = FindArg("-pxo");
if (!iparg) {
return 0;
}
strcpy(Auto_login_addr, GameArgs[iparg + 1]);
char *port = strchr(Auto_login_addr, ':');
if (port) {
// terminate the hostname
*port = '\0';
// Increment to the first character of the port name
port++;
// get the port number
strcpy(Auto_login_port, port);
} else {
portarg = FindArg("port");
if (portarg) {
strcpy(Auto_login_port, GameArgs[portarg + 1]);
} else {
Auto_login_port[0] = '\0';
}
}
// ddio_MakePath(seldll,Base_directory,"online","parallax online.d3c",NULL);
if (LoadMultiDLL("parallax online")) {
CallMultiDLL(MT_AUTO_LOGIN);
}
return MultiDLLGameStarting;
}
int AutoConnectLANIP() {
// char seldll[_MAX_PATH];
int iparg;
int portarg;
MultiDLLGameStarting = 0;
iparg = FindArg("ip");
if (!iparg) {
int connarg = FindArg("-directip");
if (!connarg)
return 0;
strcpy(Auto_login_addr, GameArgs[connarg + 1]);
char *port = strchr(Auto_login_addr, ':');
if (port) {
// terminate the hostname
*port = '\0';
// Increment to the first character of the port name
port++;
// get the port number
strcpy(Auto_login_port, port);
}
} else {
strcpy(Auto_login_addr, GameArgs[iparg + 1]);
portarg = FindArg("port");
if (portarg) {
strcpy(Auto_login_port, GameArgs[portarg + 1]);
} else {
Auto_login_port[0] = '\0';
}
}
// ddio_MakePath(seldll,Base_directory,"online","Direct TCP~IP Game.d3c",NULL);
if (LoadMultiDLL("Direct TCP~IP")) {
CallMultiDLL(MT_AUTO_LOGIN);
}
return MultiDLLGameStarting;
}
int AutoConnectHeat() {
// char seldll[_MAX_PATH];
int iparg;
int portarg;
MultiDLLGameStarting = 0;
iparg = FindArg("ip");
if (!iparg) {
int connarg = FindArg("-heat");
if (!connarg)
return 0;
strcpy(Auto_login_addr, GameArgs[connarg + 1]);
char *port = strchr(Auto_login_addr, ':');
if (port) {
// terminate the hostname
*port = '\0';
// Increment to the first character of the port name
port++;
// get the port number
strcpy(Auto_login_port, port);
}
} else {
strcpy(Auto_login_addr, GameArgs[iparg + 1]);
portarg = FindArg("port");
if (portarg) {
strcpy(Auto_login_port, GameArgs[portarg + 1]);
} else {
Auto_login_port[0] = '\0';
}
}
if (LoadMultiDLL("HEAT.NET")) {
CallMultiDLL(MT_AUTO_LOGIN);
}
return MultiDLLGameStarting;
}
#include "mem.h"
void DoMultiAllowed(void) {
rendering_state rs;
rend_GetRenderState(&rs);
int cury = 30;
int i;
const char *p;
int objid;
int *index_to_id = NULL;
bool shipsallowed[MAX_SHIPS];
bool objsallowed[MAX_OBJECTS];
ConfigItem **ship_list = NULL;
size_t strMax = std::max(strlen(TXT_ALLOW), strlen(TXT_DISALLOW)) + 3;
char *str = (char *)mem_malloc(strMax);
// Create Text Items and Window
UITextItem cancel_on_text(TXT_CANCEL, UICOL_HOTSPOT_HI);
UITextItem cancel_off_text(TXT_CANCEL, UICOL_HOTSPOT_LO);
UITextItem exit_on_text(TXT_DONE, UICOL_HOTSPOT_HI);
UITextItem exit_off_text(TXT_DONE, UICOL_HOTSPOT_LO);
snprintf(str, strMax, "\x18 %s", TXT_ALLOW);
UITextItem add_on(str, UICOL_HOTSPOT_HI);
UITextItem add_off(str, UICOL_HOTSPOT_LO);
snprintf(str, strMax, "%s \x1a", TXT_DISALLOW);
UITextItem remove_on(str, UICOL_HOTSPOT_HI);
UITextItem remove_off(str, UICOL_HOTSPOT_LO);
mem_free(str);
UITextItem allowed_ships(TXT_ALLOWEDSHIPS, UICOL_TEXT_NORMAL);
UITextItem banned_ships(TXT_DISALLOWDSHIPS, UICOL_TEXT_NORMAL);
UITextItem allowed_gen(TXT_ALLOWEDITEMS, UICOL_TEXT_NORMAL);
UITextItem banned_gen(TXT_DISALLOWEDITEM, UICOL_TEXT_NORMAL);
UITextItem obj_ti[MAX_OBJECT_IDS];
UITextItem ship_ti[MAX_SHIPS];
NewUIWindow menu_wnd;
menu_wnd.Create(0, 0, rs.screen_width, rs.screen_height, UIF_PROCESS_ALL);
int xcol1 = 110;
int yrow1 = 50;
int xcol2 = 374;
int yrow2 = 250;
int list_xsize = 160;
int list_ysize = 160;
NewUIListBox lb_ships_allowed;
NewUIListBox lb_ships_banned;
NewUIListBox lb_generic_allowed;
NewUIListBox lb_generic_banned;
UIHotspot exit_hs;
UIHotspot add_ship_hs;
UIHotspot remove_ship_hs;
UIHotspot add_gen_hs;
UIHotspot remove_gen_hs;
UIHotspot cancel_hs;
UIText ship_allowed_txt;
UIText ship_banned_txt;
UIText gen_allowed_txt;
UIText gen_banned_txt;
int textw;
int startx;
grtext_SetFont(SMALL_FONT);
add_ship_hs.Create(&menu_wnd, 10, 0, &add_off, &add_on, 10, (yrow1 + (list_ysize / 2)) - 25, 130, 30,
UIF_FIT | UIF_CENTER);
remove_ship_hs.Create(&menu_wnd, 11, 0, &remove_off, &remove_on, 10, (yrow1 + (list_ysize / 2)) - 5, 130, 30,
UIF_FIT | UIF_CENTER);
add_gen_hs.Create(&menu_wnd, 12, 0, &add_off, &add_on, 10, (yrow2 + (list_ysize / 2)) - 25, 130, 30,
UIF_FIT | UIF_CENTER);
remove_gen_hs.Create(&menu_wnd, 13, 0, &remove_off, &remove_on, 10, (yrow2 + (list_ysize / 2)) - 5, 130, 30,
UIF_FIT | UIF_CENTER);
textw = grtext_GetTextLineWidth(allowed_ships.GetBuffer());
startx = ((list_xsize / 2) + xcol1) - (textw / 2);
ship_allowed_txt.Create(&menu_wnd, &allowed_ships, startx, yrow1 - 15, 0);
textw = grtext_GetTextLineWidth(banned_ships.GetBuffer());
startx = ((list_xsize / 2) + xcol2) - (textw / 2);
ship_banned_txt.Create(&menu_wnd, &banned_ships, startx, yrow1 - 15, 0);
textw = grtext_GetTextLineWidth(allowed_gen.GetBuffer());
startx = ((list_xsize / 2) + xcol1) - (textw / 2);
gen_allowed_txt.Create(&menu_wnd, &allowed_gen, startx, yrow2 - 15, 0);
textw = grtext_GetTextLineWidth(banned_gen.GetBuffer());
startx = ((list_xsize / 2) + xcol2) - (textw / 2);
gen_banned_txt.Create(&menu_wnd, &banned_gen, startx, yrow2 - 15, 0);
lb_ships_allowed.Create(&menu_wnd, 2, xcol1, yrow1, list_xsize, list_ysize, 0);
lb_ships_allowed.SetSelectedColor(UICOL_LISTBOX_HI);
lb_ships_allowed.SetHiliteColor(UICOL_LISTBOX_HI);
lb_ships_banned.Create(&menu_wnd, 3, xcol2, yrow1, list_xsize, list_ysize, 0);
lb_ships_banned.SetSelectedColor(UICOL_LISTBOX_HI);
lb_ships_banned.SetHiliteColor(UICOL_LISTBOX_HI);
lb_generic_allowed.Create(&menu_wnd, 4, xcol1, yrow2, list_xsize, list_ysize, 0);
lb_generic_allowed.SetSelectedColor(UICOL_LISTBOX_HI);
lb_generic_allowed.SetHiliteColor(UICOL_LISTBOX_HI);
lb_generic_banned.Create(&menu_wnd, 5, xcol2, yrow2, list_xsize, list_ysize, 0);
lb_generic_banned.SetSelectedColor(UICOL_LISTBOX_HI);
lb_generic_banned.SetHiliteColor(UICOL_LISTBOX_HI);
// Exit out Hotspot
exit_hs.Create(&menu_wnd, UID_OK, KEY_ESC, &exit_off_text, &exit_on_text, 10, 420, 180, 30, UIF_FIT | UIF_CENTER);
cury += 20;
cancel_hs.Create(&menu_wnd, UID_CANCEL, 0, &cancel_off_text, &cancel_on_text, 10, 445, 180, 30, UIF_FIT | UIF_CENTER);
cury += 20;
NewUIWindowLoadBackgroundImage(&menu_wnd, "multimain.ogf");
// Object_info[MAX_OBJECT_IDS];
//
// if(Object_info[i].type==OBJ_POWERUP)
for (i = 0; i < MAX_OBJECT_IDS; i++) {
if (Object_info[i].type == OBJ_POWERUP) {
obj_ti[i] = UITextItem(Object_info[i].name, UICOL_TEXT_NORMAL);
if (Object_info[i].multi_allowed) {
objsallowed[i] = true;
lb_generic_allowed.AddItem(&obj_ti[i]);
} else {
objsallowed[i] = false;
lb_generic_banned.AddItem(&obj_ti[i]);
}
}
}
for (i = 0; i < MAX_SHIPS; i++) {
if (Ships[i].used) {
ship_ti[i] = UITextItem(Ships[i].name, UICOL_TEXT_NORMAL);
if (PlayerIsShipAllowed(0, i)) {
shipsallowed[i] = true;
lb_ships_allowed.AddItem(&ship_ti[i]);
} else {
shipsallowed[i] = false;
lb_ships_banned.AddItem(&ship_ti[i]);
}
}
}
//
// Open the window and process
menu_wnd.Open();
int exit_menu = 0;
while (!exit_menu) {
int res;
res = DoUI();
switch (res) {
case UID_OK: {
// Check for at least one ship allowed
for (i = 0; i < MAX_SHIPS; i++) {
if (Ships[i].used && PlayerIsShipAllowed(0, i)) {
break;
}
}
// If no allowed ships found, put up message
if (i == MAX_SHIPS) {
DoMessageBox(TXT_MENUMULTIPLAYER, "You must have at least one allowed ship.", MSGBOX_OK, UICOL_WINDOW_TITLE,
UICOL_TEXT_NORMAL);
break;
}
// exit
exit_menu = true;
} break;
case UID_CANCEL:
// restore old settings
for (i = 0; i < MAX_OBJECT_IDS; i++) {
if (Object_info[i].type == OBJ_POWERUP) {
if (objsallowed[i]) {
Object_info[i].multi_allowed = 1;
} else {
Object_info[i].multi_allowed = 0;
}
}
}
for (i = 0; i < MAX_SHIPS; i++) {
if (Ships[i].used) {
if (shipsallowed[i]) {
PlayerSetShipPermission(-1, Ships[i].name, 1);
} else {
PlayerSetShipPermission(-1, Ships[i].name, 0);
}
}
}
// now exit
exit_menu = true;
break;
case 10:
#ifndef DEMO
{
// Make ship allowed
UITextItem *selti = (UITextItem *)lb_ships_banned.GetItem(lb_ships_banned.GetSelectedIndex());
if (!selti)
break;
p = selti->GetBuffer();
PlayerSetShipPermission(-1, (char *)p, 1);
lb_ships_banned.RemoveItem(selti);
lb_ships_allowed.AddItem(selti);
break;
}
#else
DoMessageBox(TXT_ERROR, TXT_WRONGVERSION, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
break;
#endif
case 11:
#ifndef DEMO
{
// Make ship not allowed
UITextItem *selti = (UITextItem *)lb_ships_allowed.GetItem(lb_ships_allowed.GetSelectedIndex());
if (!selti)
break;
p = selti->GetBuffer();
PlayerSetShipPermission(-1, (char *)p, 0);
lb_ships_allowed.RemoveItem(selti);
lb_ships_banned.AddItem(selti);
break;
}
#else
DoMessageBox(TXT_ERROR, TXT_WRONGVERSION, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
break;
#endif
case 12: {
// make obj allowed
UITextItem *selti = (UITextItem *)lb_generic_banned.GetItem(lb_generic_banned.GetSelectedIndex());
if (!selti)
break;
p = selti->GetBuffer();
objid = FindObjectIDName(IGNORE_TABLE(p));
if (objid != -1) {
ASSERT(Object_info[objid].type == OBJ_POWERUP);
ASSERT(Object_info[objid].multi_allowed == 0);
Object_info[objid].multi_allowed = 1;
lb_generic_banned.RemoveItem(&obj_ti[objid]);
lb_generic_allowed.AddItem(&obj_ti[objid]);
}
break;
}
case 13: {
// make obj not allowed
UITextItem *selti = (UITextItem *)lb_generic_allowed.GetItem(lb_generic_allowed.GetSelectedIndex());
if (!selti)
break;
p = selti->GetBuffer();
objid = FindObjectIDName(IGNORE_TABLE(p));
if (objid != -1) {
ASSERT(Object_info[objid].type == OBJ_POWERUP);
ASSERT(Object_info[objid].multi_allowed == 1);
Object_info[objid].multi_allowed = 0;
lb_generic_allowed.RemoveItem(&obj_ti[objid]);
lb_generic_banned.AddItem(&obj_ti[objid]);
}
break;
}
default: {
}
}
}
// handle all UI results.
menu_wnd.Close();
menu_wnd.Destroy();
}
void MultiDoConfigSave() {
std::filesystem::path file = std::filesystem::path(Base_directory) / "custom" / "settings";
if (DoPathFileDialog(true, file, TXT_MULTISAVESET, {"*.mps"}, 0)) {
file.replace_extension(".mps");
MultiSaveSettings(file);
}
}
void MultiDoConfigLoad() {
std::filesystem::path file = std::filesystem::path(Base_directory) / "custom" / "settings";
if (DoPathFileDialog(false, file, TXT_MULTILOADSET, {"*.mps"}, PFDF_FILEMUSTEXIST))
MultiLoadSettings(file);
}
#define CHAR_LEFT_ARROW 24
#define CHAR_UP_ARROW 25
#define CHAR_RIGHT_ARROW 26
#define CHAR_DOWN_ARROW 27
#define CHAR_CHECKBOX_OFF 28
#define CHAR_CHECKBOX_ON 29
#define CHAR_RADIO_OFF 30
#define CHAR_RADIO_ON 31
#define CS_MODE_HS_ID 20
#define PP_MODE_HS_ID 21
#define ROT_VEL_HS_ID 22
#define ACC_WEAP_HS_ID 24
#define BRIGHT_SHIP_HS_ID 25
#define RAND_POWERUP_ID 26
#define PS_MODE_HS_ID 27
#define MLOOK_HS_ID 28
#define DIFF_LIST_ID 30
#define SHIP_ALLOW_HS_ID 0xdd
void MultiGameOptionsMenu(int alloptions) {
#define MULTI_OPT_TITLE_Y 30
#define MULTI_OPT_EDITS_Y 80
#define MULTI_OPT_EDITS_X_LCOL1 40
#define MULTI_OPT_EDITS_X_COL1 160
#define MULTI_OPT_EDITS_X_LCOL2 300
#define MULTI_OPT_EDITS_X_COL2 460
#define MULTI_OPT_TOGGLES_Y 210
#define MULTI_OPT_TOGGLES_X 40
#define MULTI_OPT_TOGGLES_COL2_X 300
#define MULTI_OPT_LABEL_OFS 10
#define MULTI_OPT_HOTSPOT_X_MID 410
#define MULTI_OPT_HOTSPOT_Y 360
UITextItem options_title_text(BIG_BRIEFING_FONT, TXT_GEN_MPLYROPTIONS, UICOL_WINDOW_TITLE);
UITextItem time_limit_text(TXT_GEN_TIMELIMIT, UICOL_TEXT_NORMAL);
UITextItem kill_goal_text(TXT_GEN_KILLGOAL, UICOL_TEXT_NORMAL);
UITextItem pps_text(TXT_GEN_PPS, UICOL_TEXT_NORMAL);
UITextItem respawn_rate_text(TXT_GEN_RESPAWNRATE, UICOL_TEXT_NORMAL);
UITextItem max_players_text(TXT_GEN_MAXPLAYERS, UICOL_TEXT_NORMAL);
UITextItem exit_on_text(TXT_DONE, UICOL_HOTSPOT_HI);
UITextItem exit_off_text(TXT_DONE, UICOL_HOTSPOT_LO);
UITextItem cancel_on_text(TXT_CANCEL, UICOL_HOTSPOT_HI);
UITextItem cancel_off_text(TXT_CANCEL, UICOL_HOTSPOT_LO);
UITextItem ship_on_text(TXT_GEN_CFGALLOWEDSHIP, UICOL_HOTSPOT_HI);
UITextItem ship_off_text(TXT_GEN_CFGALLOWEDSHIP, UICOL_HOTSPOT_LO);
UITextItem blank_text("", UICOL_TEXT_NORMAL);
char str[100];
int cancel_id;
rendering_state rs;
rend_GetRenderState(&rs);
NewUIWindow main_wnd;
main_wnd.Create(0, 0, rs.screen_width, rs.screen_height, UIF_PROCESS_ALL);
int num_text = 0, num_edit = 0;
int return_id;
int id = 0;
UIText title_txt;
title_txt.Create(&main_wnd, &options_title_text, 0, MULTI_OPT_TITLE_Y, UIF_CENTER);
int cury = MULTI_OPT_EDITS_Y;
// Time limit
UIText time_limit;
time_limit.Create(&main_wnd, &time_limit_text, MULTI_OPT_EDITS_X_LCOL1, cury + MULTI_OPT_LABEL_OFS, 0);
NewUIEdit time_limit_edit;
time_limit_edit.Create(&main_wnd, id++, MULTI_OPT_EDITS_X_COL1, cury, 100, 15, 0);
cury += 20;
cury += 20;
// Kill goal
UIText kill_goal;
kill_goal.Create(&main_wnd, &kill_goal_text, MULTI_OPT_EDITS_X_LCOL1, cury + MULTI_OPT_LABEL_OFS, 0);
NewUIEdit kill_goal_edit;
kill_goal_edit.Create(&main_wnd, id++, MULTI_OPT_EDITS_X_COL1, cury, 100, 15, 0);
cury += 20;
cury += 20;
NewUIEdit max_players_edit;
UIText max_players;
if (alloptions) {
// Max Players
max_players.Create(&main_wnd, &max_players_text, MULTI_OPT_EDITS_X_LCOL1, cury + MULTI_OPT_LABEL_OFS, 0);
max_players_edit.Create(&main_wnd, id++, MULTI_OPT_EDITS_X_COL1, cury, 100, 15, 0);
cury += 20;
}
cury += 20;
cury = MULTI_OPT_EDITS_Y;
// Packets per second
UIText pps;
pps.Create(&main_wnd, &pps_text, MULTI_OPT_EDITS_X_LCOL2, cury + MULTI_OPT_LABEL_OFS, 0);
NewUIEdit pps_edit;
pps_edit.Create(&main_wnd, id++, MULTI_OPT_EDITS_X_COL2, cury, 100, 15, 0);
cury += 20;
cury += 20;
// Respawn rate
UIText respawn;
respawn.Create(&main_wnd, &respawn_rate_text, MULTI_OPT_EDITS_X_LCOL2, cury + MULTI_OPT_LABEL_OFS, 0);
NewUIEdit respawn_edit;
respawn_edit.Create(&main_wnd, id++, MULTI_OPT_EDITS_X_COL2, cury, 100, 15, 0);
cury += 20;
cury = MULTI_OPT_TOGGLES_Y;
UIHotspot cs_mode_hs;
UIHotspot pp_mode_hs;
UIHotspot pcs_mode_hs;
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_ON, TXT_GEN_USEROTVEL);
UITextItem rot_vel_sel_txt_on(str, UICOL_HOTSPOT_LO);
UITextItem rot_vel_sel_txt_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_OFF, TXT_GEN_USEROTVEL);
UITextItem rot_vel_unsel_txt_on(str, UICOL_HOTSPOT_LO);
UITextItem rot_vel_unsel_txt_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_ON, TXT_GEN_BRIGHT_PLAYERS);
UITextItem bright_players_sel_on(str, UICOL_HOTSPOT_LO);
UITextItem bright_players_sel_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_OFF, TXT_GEN_BRIGHT_PLAYERS);
UITextItem bright_players_unsel_on(str, UICOL_HOTSPOT_LO);
UITextItem bright_players_unsel_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_ON, TXT_GEN_CLIENTSERVER);
UITextItem cs_mode_sel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem cs_mode_sel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_OFF, TXT_GEN_CLIENTSERVER);
UITextItem cs_mode_unsel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem cs_mode_unsel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_ON, TXT_GEN_PEERPEER);
UITextItem pp_mode_sel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem pp_mode_sel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_OFF, TXT_GEN_PEERPEER);
UITextItem pp_mode_unsel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem pp_mode_unsel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_ON, TXT_GEN_PERMISSABLE_CS);
UITextItem pcs_mode_sel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem pcs_mode_sel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), "%c %s", CHAR_RADIO_OFF, TXT_GEN_PERMISSABLE_CS);
UITextItem pcs_mode_unsel_text_on(str, UICOL_HOTSPOT_HI);
UITextItem pcs_mode_unsel_text_off(str, UICOL_HOTSPOT_LO);
snprintf(str, sizeof(str), TXT_GEN_ACC_WEAP_COLL, CHAR_CHECKBOX_ON);
UITextItem acc_weap_coll_sel_off(str, UICOL_HOTSPOT_LO);
UITextItem acc_weap_coll_sel_on(str, UICOL_HOTSPOT_HI);
snprintf(str, sizeof(str), TXT_GEN_ACC_WEAP_COLL, CHAR_CHECKBOX_OFF);
UITextItem acc_weap_coll_unsel_off(str, UICOL_HOTSPOT_LO);
UITextItem acc_weap_coll_unsel_on(str, UICOL_HOTSPOT_HI);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_ON, TXT_RANDOMPOWERUPRESPAWN);
UITextItem powerup_respawn_sel_off(str, UICOL_HOTSPOT_LO);
UITextItem powerup_respawn_sel_on(str, UICOL_HOTSPOT_HI);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_OFF, TXT_RANDOMPOWERUPRESPAWN);
UITextItem powerup_respawn_unsel_off(str, UICOL_HOTSPOT_LO);
UITextItem powerup_respawn_unsel_on(str, UICOL_HOTSPOT_HI);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_ON, TXT_ALLOWMLOOK);
UITextItem mouselookers_sel_off(str, UICOL_HOTSPOT_LO);
UITextItem mouselookers_sel_on(str, UICOL_HOTSPOT_HI);
snprintf(str, sizeof(str), "%c %s", CHAR_CHECKBOX_OFF, TXT_ALLOWMLOOK);
UITextItem mouselookers_unsel_off(str, UICOL_HOTSPOT_LO);
UITextItem mouselookers_unsel_on(str, UICOL_HOTSPOT_HI);
int cs_y;
int pp_y;
int pcs_y;
UIHotspot rot_vel_hs;
UIHotspot acc_weap_hs;
UIHotspot powerup_hs;
UIHotspot mlook_hs;
UIHotspot bright_players_hs;
int rotvely;
int acc_weap_y;
int powerup_y;
int mlook_y;
int bright_players_y;
int diff_y;
cury -= 15;
diff_y = cury;
if (alloptions) {
cury += 15;
if (Netgame.flags & NF_PEER_PEER) {
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_unsel_text_off, &cs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
cs_y = cury;
cury += 20;
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_sel_text_off, &pp_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pp_y = cury;
cury += 20;
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_unsel_text_off, &pcs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pcs_y = cury;
cury += 20;
} else if (Netgame.flags & NF_PERMISSABLE) {
////
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_unsel_text_off, &cs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
cs_y = cury;
cury += 20;
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_unsel_text_off, &pp_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pp_y = cury;
cury += 20;
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_sel_text_off, &pcs_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pcs_y = cury;
cury += 20;
} else {
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_sel_text_off, &cs_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
cs_y = cury;
cury += 20;
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_unsel_text_off, &pp_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pp_y = cury;
cury += 20;
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_unsel_text_off, &pcs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cury, 180, 30, UIF_FIT);
pcs_y = cury;
cury += 20;
}
cury += 10;
diff_y = cury;
// Rotvel toggle
cury = MULTI_OPT_TOGGLES_Y;
if (Netgame.flags & NF_SENDROTVEL) {
rot_vel_hs.Create(&main_wnd, ROT_VEL_HS_ID, 0, &rot_vel_sel_txt_off, &rot_vel_sel_txt_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
} else {
rot_vel_hs.Create(&main_wnd, ROT_VEL_HS_ID, 0, &rot_vel_unsel_txt_off, &rot_vel_unsel_txt_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
}
rotvely = cury;
cury += 20;
}
// Accurate collisions toggle
if (Netgame.flags & NF_USE_ACC_WEAP) {
acc_weap_hs.Create(&main_wnd, ACC_WEAP_HS_ID, KEY_A, &acc_weap_coll_sel_off, &acc_weap_coll_sel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
} else {
acc_weap_hs.Create(&main_wnd, ACC_WEAP_HS_ID, KEY_A, &acc_weap_coll_unsel_off, &acc_weap_coll_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
}
acc_weap_y = cury;
cury += 20;
// Bright players toggle
if (Netgame.flags & NF_BRIGHT_PLAYERS) {
bright_players_hs.Create(&main_wnd, BRIGHT_SHIP_HS_ID, KEY_B, &bright_players_sel_off, &bright_players_sel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
} else {
bright_players_hs.Create(&main_wnd, BRIGHT_SHIP_HS_ID, KEY_B, &bright_players_unsel_off, &bright_players_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
}
bright_players_y = cury;
cury += 20;
if (Netgame.flags & NF_RANDOMIZE_RESPAWN) {
powerup_hs.Create(&main_wnd, RAND_POWERUP_ID, KEY_B, &powerup_respawn_sel_off, &powerup_respawn_sel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
} else {
powerup_hs.Create(&main_wnd, RAND_POWERUP_ID, KEY_B, &powerup_respawn_unsel_off, &powerup_respawn_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
}
powerup_y = cury;
cury += 20;
if (Netgame.flags & NF_ALLOW_MLOOK) {
mlook_hs.Create(&main_wnd, MLOOK_HS_ID, KEY_B, &mouselookers_sel_off, &mouselookers_sel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
} else {
mlook_hs.Create(&main_wnd, MLOOK_HS_ID, KEY_B, &mouselookers_unsel_off, &mouselookers_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, cury, 180, 30, UIF_FIT);
}
mlook_y = cury;
cury += 20;
// Difficulty Listbox & title
UITextItem diff_title_text(TXT_PLTDIFFICULT, UICOL_WINDOW_TITLE);
UITextItem trainee(TXT_TRAINEE, GR_LIGHTGRAY);
UITextItem rookie(TXT_ROOKIE, GR_LIGHTGRAY);
UITextItem hotshot(TXT_HOTSHOT, GR_LIGHTGRAY);
UITextItem ace(TXT_ACE, GR_LIGHTGRAY);
UITextItem insane(TXT_INSANE, GR_LIGHTGRAY);
UIText diff_title;
diff_title.Create(&main_wnd, &diff_title_text, MULTI_OPT_TOGGLES_X, diff_y, 0);
diff_y += 15;
NewUIListBox diff_list;
diff_list.SetSelectedColor(UICOL_LISTBOX_HI);
diff_list.SetHiliteColor(UICOL_LISTBOX_HI);
diff_list.Create(&main_wnd, DIFF_LIST_ID, MULTI_OPT_TOGGLES_X, diff_y, 160, 96, UILB_NOSORT);
diff_list.AddItem(&trainee);
diff_list.AddItem(&rookie);
diff_list.AddItem(&hotshot);
diff_list.AddItem(&ace);
diff_list.AddItem(&insane);
switch (Netgame.difficulty) {
case 0:
diff_list.SelectItem(&trainee);
break;
case 1:
diff_list.SelectItem(&rookie);
break;
case 2:
diff_list.SelectItem(&hotshot);
break;
case 3:
diff_list.SelectItem(&ace);
break;
case 4:
diff_list.SelectItem(&insane);
break;
}
cury = MULTI_OPT_HOTSPOT_Y;
// int hsmid = MULTI_OPT_HOTSPOT_X_MID - (DLLgrtext_GetTextLineWidth(TXT_GEN_CFGALLOWEDSHIP)/2);
UIHotspot ship_hs;
ship_hs.Create(&main_wnd, SHIP_ALLOW_HS_ID, KEY_S, &ship_off_text, &ship_on_text, 0, cury, 180, 30,
UIF_FIT | UIF_CENTER);
cury += 20;
return_id = UID_OK;
cury += 10;
// hsmid = MULTI_OPT_HOTSPOT_X_MID - (DLLgrtext_GetTextLineWidth(TXT_GEN_PREVMENU)/2);
UIHotspot exit_hs;
exit_hs.Create(&main_wnd, UID_OK, KEY_ESC, &exit_off_text, &exit_on_text, 0, cury, 180, 30, UIF_FIT | UIF_CENTER);
cury += 20;
cancel_id = UID_CANCEL;
/// hsmid = MULTI_OPT_HOTSPOT_X_MID - (DLLgrtext_GetTextLineWidth(TXT_GEN_CANCEL)/2);
UIHotspot cancel_hs;
cancel_hs.Create(&main_wnd, UID_CANCEL, 0, &cancel_off_text, &cancel_on_text, 0, cury, 180, 30, UIF_FIT | UIF_CENTER);
cury += 20;
// Bash some values
if (Netgame.flags & NF_TIMER)
snprintf(str, sizeof(str), "%d", Netgame.timelimit);
else
snprintf(str, sizeof(str), "%d", 0);
time_limit_edit.SetText(str);
if (Netgame.flags & NF_KILLGOAL)
snprintf(str, sizeof(str), "%d", Netgame.killgoal);
else
snprintf(str, sizeof(str), "%d", 0);
kill_goal_edit.SetText(str);
snprintf(str, sizeof(str), "%d", Netgame.packets_per_second);
pps_edit.SetText(str);
snprintf(str, sizeof(str), "%d", Netgame.max_players);
if (alloptions) {
max_players_edit.SetText(str);
}
snprintf(str, sizeof(str), "%d", Netgame.respawn_time);
respawn_edit.SetText(str);
main_wnd.LoadBackgroundImage("multimain.ogf");
main_wnd.Open();
int exit_menu = 0;
while (!exit_menu) {
int res;
res = DoUI();
if (res == cancel_id) {
exit_menu = true;
break;
}
if (alloptions) {
if (res == CS_MODE_HS_ID) {
cs_mode_hs.Destroy();
pp_mode_hs.Destroy();
pcs_mode_hs.Destroy();
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_sel_text_off, &cs_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, cs_y, 180, 30, UIF_FIT);
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_unsel_text_off, &pp_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, pp_y, 180, 30, UIF_FIT);
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_unsel_text_off, &pcs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, pcs_y, 180, 30, UIF_FIT);
Netgame.flags &= ~NF_PEER_PEER;
Netgame.flags &= ~NF_PERMISSABLE;
mprintf(0, "Using Client/Server model\n");
} else if (res == PP_MODE_HS_ID) {
cs_mode_hs.Destroy();
pp_mode_hs.Destroy();
pcs_mode_hs.Destroy();
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_unsel_text_off, &cs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cs_y, 180, 30, UIF_FIT);
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_sel_text_off, &pp_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, pp_y, 180, 30, UIF_FIT);
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_unsel_text_off, &pcs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, pcs_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_PEER_PEER;
Netgame.flags &= ~NF_PERMISSABLE;
mprintf(0, "Using Peer/Peer model\n");
} else if (res == PS_MODE_HS_ID) {
cs_mode_hs.Destroy();
pp_mode_hs.Destroy();
pcs_mode_hs.Destroy();
cs_mode_hs.Create(&main_wnd, CS_MODE_HS_ID, KEY_C, &cs_mode_unsel_text_off, &cs_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, cs_y, 180, 30, UIF_FIT);
pp_mode_hs.Create(&main_wnd, PP_MODE_HS_ID, KEY_C, &pp_mode_unsel_text_off, &pp_mode_unsel_text_on,
MULTI_OPT_TOGGLES_X, pp_y, 180, 30, UIF_FIT);
pcs_mode_hs.Create(&main_wnd, PS_MODE_HS_ID, KEY_C, &pcs_mode_sel_text_off, &pcs_mode_sel_text_on,
MULTI_OPT_TOGGLES_X, pcs_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_PERMISSABLE;
Netgame.flags &= ~NF_PEER_PEER;
mprintf(0, "Using Permissable model\n");
} else if (res == ROT_VEL_HS_ID) {
rot_vel_hs.Destroy();
if (Netgame.flags & NF_SENDROTVEL) {
rot_vel_hs.Create(&main_wnd, ROT_VEL_HS_ID, 0, &rot_vel_unsel_txt_off, &rot_vel_unsel_txt_on,
MULTI_OPT_TOGGLES_COL2_X, rotvely, 180, 30, UIF_FIT);
Netgame.flags &= ~NF_SENDROTVEL;
} else {
rot_vel_hs.Create(&main_wnd, ROT_VEL_HS_ID, 0, &rot_vel_sel_txt_off, &rot_vel_sel_txt_on,
MULTI_OPT_TOGGLES_COL2_X, rotvely, 180, 30, UIF_FIT);
Netgame.flags |= NF_SENDROTVEL;
}
}
}
if (res == SHIP_ALLOW_HS_ID) {
// Ships allowed
main_wnd.Close();
DoMultiAllowed();
main_wnd.Open();
} else if (res == ACC_WEAP_HS_ID) {
acc_weap_hs.Destroy();
if (Netgame.flags & NF_USE_ACC_WEAP) {
acc_weap_hs.Create(&main_wnd, ACC_WEAP_HS_ID, KEY_A, &acc_weap_coll_unsel_off, &acc_weap_coll_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, acc_weap_y, 180, 30, UIF_FIT);
Netgame.flags &= ~NF_USE_ACC_WEAP;
} else {
acc_weap_hs.Create(&main_wnd, ACC_WEAP_HS_ID, KEY_A, &acc_weap_coll_sel_off, &acc_weap_coll_sel_on,
MULTI_OPT_TOGGLES_COL2_X, acc_weap_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_USE_ACC_WEAP;
}
} else if (res == BRIGHT_SHIP_HS_ID) {
bright_players_hs.Destroy();
if (Netgame.flags & NF_BRIGHT_PLAYERS) {
bright_players_hs.Create(&main_wnd, BRIGHT_SHIP_HS_ID, KEY_B, &bright_players_unsel_off,
&bright_players_unsel_on, MULTI_OPT_TOGGLES_COL2_X, bright_players_y, 180, 30,
UIF_FIT);
Netgame.flags &= ~NF_BRIGHT_PLAYERS;
} else {
bright_players_hs.Create(&main_wnd, BRIGHT_SHIP_HS_ID, KEY_B, &bright_players_sel_off, &bright_players_sel_on,
MULTI_OPT_TOGGLES_COL2_X, bright_players_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_BRIGHT_PLAYERS;
}
}
else if (res == RAND_POWERUP_ID) {
powerup_hs.Destroy();
if (Netgame.flags & NF_RANDOMIZE_RESPAWN) {
powerup_hs.Create(&main_wnd, RAND_POWERUP_ID, KEY_B, &powerup_respawn_unsel_off, &powerup_respawn_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, powerup_y, 180, 30, UIF_FIT);
Netgame.flags &= ~NF_RANDOMIZE_RESPAWN;
} else {
powerup_hs.Create(&main_wnd, RAND_POWERUP_ID, KEY_B, &powerup_respawn_sel_off, &powerup_respawn_sel_on,
MULTI_OPT_TOGGLES_COL2_X, powerup_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_RANDOMIZE_RESPAWN;
}
}
else if (res == MLOOK_HS_ID) {
mlook_hs.Destroy();
if (Netgame.flags & NF_ALLOW_MLOOK) {
mlook_hs.Create(&main_wnd, MLOOK_HS_ID, KEY_B, &mouselookers_unsel_off, &mouselookers_unsel_on,
MULTI_OPT_TOGGLES_COL2_X, mlook_y, 180, 30, UIF_FIT);
Netgame.flags &= ~NF_ALLOW_MLOOK;
} else {
mlook_hs.Create(&main_wnd, MLOOK_HS_ID, KEY_B, &mouselookers_sel_off, &mouselookers_sel_on,
MULTI_OPT_TOGGLES_COL2_X, mlook_y, 180, 30, UIF_FIT);
Netgame.flags |= NF_ALLOW_MLOOK;
}
} else if (res == return_id) {
int val;
// Get kill goal
// edits[killgoal_edit].GetText (str,100);
kill_goal_edit.GetText(str, 100);
val = atoi(str);
if (val > 1) {
if (val > 10000)
val = 10000;
Netgame.flags |= NF_KILLGOAL;
} else {
Netgame.flags &= ~NF_KILLGOAL;
val = 0;
}
Netgame.killgoal = val;
// Get timelimit
// edits[timer_edit].GetText (str,100);
time_limit_edit.GetText(str, 100);
val = atoi(str);
if (val > 0) {
if (val > 10000)
val = 10000;
Netgame.flags |= NF_TIMER;
} else {
Netgame.flags &= ~NF_TIMER;
val = 0;
}
Netgame.timelimit = val;
// Get packets per second
pps_edit.GetText(str, 100);
val = atoi(str);
Netgame.packets_per_second = val;
if (val > 20)
val = 20;
if (val < 2)
val = 2;
if (alloptions) {
// Get Max players
max_players_edit.GetText(str, 100);
val = atoi(str);
Netgame.max_players = val;
if (val > MAX_NET_PLAYERS)
Netgame.max_players = MAX_NET_PLAYERS;
if (val < 2)
val = 2;
}
// Get respawn rate
// edits[respawn_edit].GetText (str,100);
respawn_edit.GetText(str, 100);
val = atoi(str);
if (val < 15)
val = 15;
if (val > 300)
val = 300;
Netgame.respawn_time = val;
int difficulty = diff_list.GetSelectedIndex();
Netgame.difficulty = difficulty;
exit_menu = 1;
}
}
main_wnd.Close();
main_wnd.Destroy();
}
int ReturnMultiplayerGameMenu(void) {
MultiFlushAllIncomingBuffers();
CallMultiDLL(MT_RETURN_TO_GAME_LIST);
return MultiDLLGameStarting;
}
int MultiLevelSelection(void) {
if (Current_mission.num_levels == 1)
return 1;
Current_mission.cur_level = DisplayLevelWarpDlg(Current_mission.num_levels);
if (Current_mission.cur_level < 1) {
Current_mission.cur_level = 1;
return -1;
}
return Current_mission.cur_level;
}
bool DoPlayerMouselookCheck(uint32_t flags) {
if (Current_pilot.mouselook_control) {
if (flags & NF_ALLOW_MLOOK) {
return true;
} else {
int ret = DoMessageBox(TXT_NOMOUSELOOK, TXT_MLOOK_JOINANYWAY, MSGBOX_YESNO);
return ret ? true : false;
}
}
return true;
}
#define GAME_INFO_MENU_W 384
#define GAME_INFO_MENU_H 384
#define GAME_INFO_MENU_X 320 - (GAME_INFO_MENU_W / 2)
#define GAME_INFO_MENU_Y 240 - (GAME_INFO_MENU_H / 2)
#define GAME_INFO_COL1 10
#define GAME_INFO_GOTO_NEXT_LINE cury += 13
#define UID_GAMEINFO_PLAYERS 1000
extern char *Multi_recieved_player_list;
extern bool Multi_got_player_list;
void RequestPlayerList(network_address *addr);
#define ASK_PLAYERS_RETRY_INTERVAL 2.0
#define ASK_PLAYERS_RETRIES 4
// Display a dialog box showing the information relating to this particular net game
void ShowNetgameInfo(network_game *game) {
char str[200];
int cury = 10;
int exit_menu = 0;
newuiTiledWindow menu_wnd;
newuiListBox *lists;
newuiSheet *sheet;
char *plyr;
ASSERT(game);
menu_wnd.Create(TXT_GAME_INFO, 0, 0, GAME_INFO_MENU_W, GAME_INFO_MENU_H);
sheet = menu_wnd.GetSheet();
sheet->NewGroup(game->name, GAME_INFO_COL1, cury);
cury += 15;
snprintf(str, sizeof(str), TXT_GINFO_MISSION, game->mission_name);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), TXT_PLAYERS_X_OF_X, game->curr_num_players, game->max_num_players);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
const char *szdiff = TXT_ERROR;
switch (game->difficulty) {
case 0:
szdiff = TXT_TRAINEE;
break;
case 1:
szdiff = TXT_ROOKIE;
break;
case 2:
szdiff = TXT_HOTSHOT;
break;
case 3:
szdiff = TXT_ACE;
break;
case 4:
szdiff = TXT_INSANE;
break;
default:
szdiff = TXT_ERROR;
}
snprintf(str, sizeof(str), "%s: %s", TXT_PLTDIFFICULT, szdiff);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
const char *mode;
if ((game->flags & NF_PEER_PEER)) {
mode = TXT_GEN_PEERPEER;
} else if ((game->flags & NF_PERMISSABLE)) {
mode = TXT_GEN_PERMISSABLE_CS;
} else {
mode = TXT_GEN_CLIENTSERVER;
}
if (game->dedicated_server)
snprintf(str, sizeof(str), TXT_DEDICATED_SERVER, mode);
else
snprintf(str, sizeof(str), TXT_NONDEDICATED_SERVER, mode);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), TXT_GINFO_ALLOWMOUSELOOK, (game->flags & NF_ALLOW_MLOOK) ? TXT_DOES : TXT_DOESNOT);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), "%s: %s", TXT_GEN_BRIGHT_PLAYERS, (game->flags & NF_BRIGHT_PLAYERS) ? TXT_ON : TXT_OFF);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), TXT_GINFO_ACC_WEAPCOLL, (game->flags & NF_USE_ACC_WEAP) ? TXT_ON : TXT_OFF);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), TXT_USE_ROTATIONAL_VEL, (game->flags & NF_SENDROTVEL) ? TXT_ON : TXT_OFF);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), TXT_RANDOMIZEPOWERUPSPAWN, (game->flags & NF_RANDOMIZE_RESPAWN) ? TXT_ON : TXT_OFF);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
// GAME_INFO_GOTO_NEXT_LINE;
snprintf(str, sizeof(str), "%s:", TXT_GAMEINFOPLAYERSTITLE);
sheet->NewGroup(str, GAME_INFO_COL1, cury);
GAME_INFO_GOTO_NEXT_LINE;
lists = sheet->AddListBox(256, 128, UID_GAMEINFO_PLAYERS);
lists->RemoveAll();
sheet->NewGroup(NULL, (GAME_INFO_MENU_W - 140), GAME_INFO_MENU_H - 95, NEWUI_ALIGN_HORIZ);
sheet->AddButton(TXT_DONE, UID_CANCEL);
// Get players
Multi_recieved_player_list = (char *)mem_malloc(((CALLSIGN_LEN + 1) * MAX_NET_PLAYERS) + 1);
memset(Multi_recieved_player_list, 0, ((CALLSIGN_LEN + 1) * MAX_NET_PLAYERS) + 1);
Multi_got_player_list = false;
CreateSplashScreen(TXT_GETTINGPLAYERLIST, 1);
RequestPlayerList(&game->addr);
float last_asked_time = timer_GetTime();
int retries = 0;
do {
MultiProcessIncoming();
int res = PollUI();
// If the user hit cancel...
if (res == 99) {
CloseSplashScreen();
goto no_players;
}
if ((timer_GetTime() - last_asked_time) > ASK_PLAYERS_RETRY_INTERVAL) {
last_asked_time = timer_GetTime();
RequestPlayerList(&game->addr);
retries++;
}
if (retries >= ASK_PLAYERS_RETRIES) {
DoMessageBox(TXT_ERROR, TXT_CANTGETPLAYERLIST, MSGBOX_OK);
CloseSplashScreen();
goto no_players;
}
} while (!Multi_got_player_list);
CloseSplashScreen();
// Ok, now we've got the list of players.. let's parse it and add the players to the list
plyr = Multi_recieved_player_list;
while (*plyr) {
lists->AddItem(plyr);
// Move on to the next item
while (*plyr) {
plyr++;
}
// Move past the NULL
plyr++;
}
if (Multi_recieved_player_list) {
mem_free(Multi_recieved_player_list);
Multi_recieved_player_list = NULL;
}
menu_wnd.Open();
while (!exit_menu) {
int res;
res = menu_wnd.DoUI();
// handle all UI results.
switch (res) {
case UID_CANCEL:
menu_wnd.Close();
exit_menu = 1;
break;
}
}
menu_wnd.Destroy();
no_players:
if (Multi_recieved_player_list) {
mem_free(Multi_recieved_player_list);
Multi_recieved_player_list = NULL;
}
}