8216bafe50f8a9ea64d6332dcd44d4ecfaa92cd2
[xonotic/darkplaces.git] / com_game.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 Copyright (C) 2000-2020 Ashley Rose "LadyHavoc" Hale
4 Copyright (C) 2020 David "Cloudwalk" Knapp
5 Copyright (C) 2020 Kristus <kristustf@gmail.com>
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
22 */
23
24 #include "quakedef.h"
25
26 // Game mods
27
28 gamemode_t gamemode;
29 const char *gamename;
30 const char *gamenetworkfiltername; // same as gamename currently but with _ in place of spaces so that "getservers" packets parse correctly (this also means the 
31 const char *gamedirname1;
32 const char *gamedirname2;
33 const char *gamescreenshotname;
34 const char *gameuserdirname;
35 char com_modname[MAX_OSPATH] = "";
36
37 gamemode_t com_startupgamemode;
38 gamemode_t com_startupgamegroup;
39
40 typedef struct gamemode_info_s
41 {
42         gamemode_t mode; // this gamemode
43         gamemode_t group; // different games with same group can switch automatically when gamedirs change
44         const char* prog_name; // not null
45         const char* cmdline; // not null
46         const char* gamename; // not null
47         const char*     gamenetworkfiltername; // not null
48         const char* gamedirname1; // not null
49         const char* gamedirname2; // null
50         const char* gamescreenshotname; // not nul
51         const char* gameuserdirname; // not null
52 } gamemode_info_t;
53
54 static const gamemode_info_t gamemode_info [GAME_COUNT] =
55 {// game                                                basegame                                        prog_name                               cmdline                                         gamename                                        gamenetworkfilername            basegame        modgame                 screenshot                      userdir                                    // commandline option
56 { GAME_NORMAL,                                  GAME_NORMAL,                            "",                                             "-quake",                                       "DarkPlaces-Quake",                     "DarkPlaces-Quake",                     "id1",          NULL,                   "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
57 { GAME_HIPNOTIC,                                GAME_NORMAL,                            "hipnotic",                             "-hipnotic",                            "Darkplaces-Hipnotic",          "Darkplaces-Hipnotic",          "id1",          "hipnotic",             "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
58 { GAME_ROGUE,                                   GAME_NORMAL,                            "rogue",                                "-rogue",                                       "Darkplaces-Rogue",                     "Darkplaces-Rogue",                     "id1",          "rogue",                "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
59 { GAME_NEHAHRA,                                 GAME_NORMAL,                            "nehahra",                              "-nehahra",                                     "DarkPlaces-Nehahra",           "DarkPlaces-Nehahra",           "id1",          "nehahra",              "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
60 { GAME_QUOTH,                                   GAME_NORMAL,                            "quoth",                                "-quoth",                                       "Darkplaces-Quoth",                     "Darkplaces-Quoth",                     "id1",          "quoth",                "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -quoth runs the Quoth mod for playing community maps made for it
61 { GAME_NEXUIZ,                                  GAME_NEXUIZ,                            "nexuiz",                               "-nexuiz",                                      "Nexuiz",                                       "Nexuiz",                                       "data",         NULL,                   "nexuiz",                       "nexuiz"                                }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
62 { GAME_XONOTIC,                                 GAME_XONOTIC,                           "xonotic",                              "-xonotic",                                     "Xonotic",                                      "Xonotic",                                      "data",         NULL,                   "xonotic",                      "xonotic"                               }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
63 { GAME_TRANSFUSION,                             GAME_TRANSFUSION,                       "transfusion",                  "-transfusion",                         "Transfusion",                          "Transfusion",                          "basetf",       NULL,                   "transfusion",          "transfusion"                   }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
64 { GAME_GOODVSBAD2,                              GAME_GOODVSBAD2,                        "gvb2",                                 "-goodvsbad2",                          "GoodVs.Bad2",                          "GoodVs.Bad2",                          "rts",          NULL,                   "gvb2",                         "gvb2"                                  }, // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
65 { GAME_TEU,                                             GAME_TEU,                                       "teu",                                  "-teu",                                         "TheEvilUnleashed",                     "TheEvilUnleashed",                     "baseteu",      NULL,                   "teu",                          "teu"                                   }, // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
66 { GAME_BATTLEMECH,                              GAME_BATTLEMECH,                        "battlemech",                   "-battlemech",                          "Battlemech",                           "Battlemech",                           "base",         NULL,                   "battlemech",           "battlemech"                    }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
67 { GAME_ZYMOTIC,                                 GAME_ZYMOTIC,                           "zymotic",                              "-zymotic",                                     "Zymotic",                                      "Zymotic",                                      "basezym",      NULL,                   "zymotic",                      "zymotic"                               }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
68 { GAME_SETHERAL,                                GAME_SETHERAL,                          "setheral",                             "-setheral",                            "Setheral",                                     "Setheral",                                     "data",         NULL,                   "setheral",                     "setheral"                              }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
69 { GAME_TENEBRAE,                                GAME_NORMAL,                            "tenebrae",                             "-tenebrae",                            "DarkPlaces-Tenebrae",          "DarkPlaces-Tenebrae",          "id1",          "tenebrae",             "dp",                           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
70 { GAME_NEOTERIC,                                GAME_NORMAL,                            "neoteric",                             "-neoteric",                            "Neoteric",                                     "Neoteric",                                     "id1",          "neobase",              "neo",                          "darkplaces"                    }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
71 { GAME_OPENQUARTZ,                              GAME_NORMAL,                            "openquartz",                   "-openquartz",                          "OpenQuartz",                           "OpenQuartz",                           "id1",          NULL,                   "openquartz",           "darkplaces"                    }, // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
72 { GAME_PRYDON,                                  GAME_NORMAL,                            "prydon",                               "-prydon",                                      "PrydonGate",                           "PrydonGate",                           "id1",          "prydon",               "prydon",                       "darkplaces"                    }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
73 { GAME_DELUXEQUAKE,                             GAME_DELUXEQUAKE,                       "dq",                                   "-dq",                                          "Deluxe Quake",                         "Deluxe_Quake",                         "basedq",       "extradq",              "basedq",                       "dq"                                    }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
74 { GAME_THEHUNTED,                               GAME_THEHUNTED,                         "thehunted",                    "-thehunted",                           "The Hunted",                           "The_Hunted",                           "thdata",       NULL,                   "th",                           "thehunted"                             }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
75 { GAME_DEFEATINDETAIL2,                 GAME_DEFEATINDETAIL2,           "did2",                                 "-did2",                                        "Defeat In Detail 2",           "Defeat_In_Detail_2",           "data",         NULL,                   "did2_",                        "did2"                                  }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
76 { GAME_DARSANA,                                 GAME_DARSANA,                           "darsana",                              "-darsana",                                     "Darsana",                                      "Darsana",                                      "ddata",        NULL,                   "darsana",                      "darsana"                               }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
77 { GAME_CONTAGIONTHEORY,                 GAME_CONTAGIONTHEORY,           "contagiontheory",              "-contagiontheory",                     "Contagion Theory",                     "Contagion_Theory",                     "ctdata",       NULL,                   "ct",                           "contagiontheory"               }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
78 { GAME_EDU2P,                                   GAME_EDU2P,                                     "edu2p",                                "-edu2p",                                       "EDU2 Prototype",                       "EDU2_Prototype",                       "id1",          "edu2",                 "edu2_p",                       "edu2prototype"                 }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
79 { GAME_PROPHECY,                                GAME_PROPHECY,                          "prophecy",                             "-prophecy",                            "Prophecy",                                     "Prophecy",                                     "gamedata",     NULL,                   "phcy",                         "prophecy"                              }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
80 { GAME_BLOODOMNICIDE,                   GAME_BLOODOMNICIDE,                     "omnicide",                             "-omnicide",                            "Blood Omnicide",                       "Blood_Omnicide",                       "kain",         NULL,                   "omnicide",                     "omnicide"                              }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
81 { GAME_STEELSTORM,                              GAME_STEELSTORM,                        "steelstorm",                   "-steelstorm",                          "Steel-Storm",                          "Steel-Storm",                          "gamedata",     NULL,                   "ss",                           "steelstorm"                    }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
82 { GAME_STEELSTORM2,                             GAME_STEELSTORM2,                       "steelstorm2",                  "-steelstorm2",                         "Steel Storm 2",                        "Steel_Storm_2",                        "gamedata",     NULL,                   "ss2",                          "steelstorm2"                   }, // COMMANDLINEOPTION: Game: -steelstorm2 runs the game Steel Storm 2
83 { GAME_SSAMMO,                                  GAME_SSAMMO,                            "steelstorm-ammo",              "-steelstormammo",                      "Steel Storm A.M.M.O.",         "Steel_Storm_A.M.M.O.",         "gamedata", NULL,                       "ssammo",                       "steelstorm-ammo"               }, // COMMANDLINEOPTION: Game: -steelstormammo runs the game Steel Storm A.M.M.O.
84 { GAME_STEELSTORMREVENANTS,             GAME_STEELSTORMREVENANTS,       "steelstorm-revenants", "-steelstormrev",                       "Steel Storm: Revenants",       "Steel_Storm_Revenants",        "base", NULL,                           "ssrev",                        "steelstorm-revenants"  }, // COMMANDLINEOPTION: Game: -steelstormrev runs the game Steel Storm: Revenants
85 { GAME_TOMESOFMEPHISTOPHELES,   GAME_TOMESOFMEPHISTOPHELES,     "tomesofmephistopheles","-tomesofmephistopheles",       "Tomes of Mephistopheles",      "Tomes_of_Mephistopheles",      "gamedata",     NULL,                   "tom",                          "tomesofmephistopheles" }, // COMMANDLINEOPTION: Game: -tomesofmephistopheles runs the game Tomes of Mephistopheles
86 { GAME_STRAPBOMB,                               GAME_STRAPBOMB,                         "strapbomb",                    "-strapbomb",                           "Strap-on-bomb Car",            "Strap-on-bomb_Car",            "id1",          NULL,                   "strap",                        "strapbomb"                             }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
87 { GAME_MOONHELM,                                GAME_MOONHELM,                          "moonhelm",                             "-moonhelm",                            "MoonHelm",                                     "MoonHelm",                                     "data",         NULL,                   "mh",                           "moonhelm"                              }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm
88 { GAME_VORETOURNAMENT,                  GAME_VORETOURNAMENT,            "voretournament",               "-voretournament",                      "Vore Tournament",                      "Vore_Tournament",                      "data",         NULL,                   "voretournament",       "voretournament"                }, // COMMANDLINEOPTION: Game: -voretournament runs the multiplayer game Vore Tournament
89 { GAME_DOOMBRINGER,                             GAME_DOOMBRINGER,                       "doombringer",                  "-doombringer",                         "DOOMBRINGER",                          "DOOMBRINGER",                          "dbdata",       NULL,                   "doombringer",          "doombringer"                   }, // COMMANDLINEOPTION: Game: -doombringer runs the game DOOMBRINGER
90 { GAME_BATTLEMETAL,                             GAME_NORMAL,                            "battlemetal",                  "-battlemetal",                         "battlemetal",                          "battlemetal",                          "metaldata",    NULL,           "battlemetal",          "battlemetal"                   }, // COMMANDLINEOPTION: Game: -battlemetal runs the game battleMETAL
91 };
92
93 static void COM_SetGameType(int index);
94 void COM_InitGameType (void)
95 {
96         char name [MAX_OSPATH];
97         int i;
98         int index = 0;
99
100 #ifdef FORCEGAME
101         COM_ToLowerString(FORCEGAME, name, sizeof (name));
102 #else
103         // check executable filename for keywords, but do it SMARTLY - only check the last path element
104         FS_StripExtension(FS_FileWithoutPath(sys.argv[0]), name, sizeof (name));
105         COM_ToLowerString(name, name, sizeof (name));
106 #endif
107         for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
108                 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
109                         index = i;
110
111         // check commandline options for keywords
112         for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
113                 if (Sys_CheckParm (gamemode_info[i].cmdline))
114                         index = i;
115
116         com_startupgamemode = gamemode_info[index].mode;
117         com_startupgamegroup = gamemode_info[index].group;
118         COM_SetGameType(index);
119 }
120
121 void COM_ChangeGameTypeForGameDirs(void)
122 {
123         int i;
124         int index = -1;
125         // this will not not change the gamegroup
126         // first check if a base game (single gamedir) matches
127         for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
128         {
129                 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
130                 {
131                         index = i;
132                         break;
133                 }
134         }
135         // now that we have a base game, see if there is a matching derivative game (two gamedirs)
136         if (fs_numgamedirs)
137         {
138                 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
139                 {
140                         if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
141                         {
142                                 index = i;
143                                 break;
144                         }
145                 }
146         }
147         // we now have a good guess at which game this is meant to be...
148         if (index >= 0 && gamemode != gamemode_info[index].mode)
149                 COM_SetGameType(index);
150 }
151
152 static void COM_SetGameType(int index)
153 {
154         static char gamenetworkfilternamebuffer[64];
155         int i, t;
156         if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
157                 index = 0;
158         gamemode = gamemode_info[index].mode;
159         gamename = gamemode_info[index].gamename;
160         gamenetworkfiltername = gamemode_info[index].gamenetworkfiltername;
161         gamedirname1 = gamemode_info[index].gamedirname1;
162         gamedirname2 = gamemode_info[index].gamedirname2;
163         gamescreenshotname = gamemode_info[index].gamescreenshotname;
164         gameuserdirname = gamemode_info[index].gameuserdirname;
165
166         if (gamemode == com_startupgamemode)
167         {
168                 if((t = Sys_CheckParm("-customgamename")) && t + 1 < sys.argc)
169                         gamename = gamenetworkfiltername = sys.argv[t+1];
170                 if((t = Sys_CheckParm("-customgamenetworkfiltername")) && t + 1 < sys.argc)
171                         gamenetworkfiltername = sys.argv[t+1];
172                 if((t = Sys_CheckParm("-customgamedirname1")) && t + 1 < sys.argc)
173                         gamedirname1 = sys.argv[t+1];
174                 if((t = Sys_CheckParm("-customgamedirname2")) && t + 1 < sys.argc)
175                         gamedirname2 = *sys.argv[t+1] ? sys.argv[t+1] : NULL;
176                 if((t = Sys_CheckParm("-customgamescreenshotname")) && t + 1 < sys.argc)
177                         gamescreenshotname = sys.argv[t+1];
178                 if((t = Sys_CheckParm("-customgameuserdirname")) && t + 1 < sys.argc)
179                         gameuserdirname = sys.argv[t+1];
180         }
181
182         if (gamedirname2 && gamedirname2[0])
183                 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
184         else
185                 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
186         for (i = 0;i < fs_numgamedirs;i++)
187         {
188                 if (i == 0)
189                         Con_Printf(", with mod gamedirs");
190                 Con_Printf(" %s", fs_gamedirs[i]);
191         }
192         Con_Printf("\n");
193
194         if (strchr(gamenetworkfiltername, ' '))
195         {
196                 char *s;
197                 // if there are spaces in the game's network filter name it would
198                 // cause parse errors in getservers in dpmaster, so we need to replace
199                 // them with _ characters
200                 strlcpy(gamenetworkfilternamebuffer, gamenetworkfiltername, sizeof(gamenetworkfilternamebuffer));
201                 while ((s = strchr(gamenetworkfilternamebuffer, ' ')) != NULL)
202                         *s = '_';
203                 gamenetworkfiltername = gamenetworkfilternamebuffer;
204         }
205
206         Con_Printf("gamename for server filtering: %s\n", gamenetworkfiltername);
207 }