1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 // DOOM Network game communication and protocol,
17 // all OS independend parts.
18 //
19
20 #include <stdlib.h>
21
22 #include "d_main.h"
23 #include "m_argv.h"
24 #include "m_menu.h"
25 #include "m_misc.h"
26 #include "i_system.h"
27 #include "i_timer.h"
28 #include "i_video.h"
29 #include "g_game.h"
30 #include "doomdef.h"
31 #include "doomstat.h"
32 #include "w_checksum.h"
33 #include "w_wad.h"
34
35 #include "deh_main.h"
36
37 #include "d_loop.h"
38
39 ticcmd_t *netcmds;
40
41 // Called when a player leaves the game
42
PlayerQuitGame(player_t * player)43 static void PlayerQuitGame(player_t *player)
44 {
45 static char exitmsg[80];
46 unsigned int player_num;
47
48 player_num = player - players;
49
50 // Do this the same way as Vanilla Doom does, to allow dehacked
51 // replacements of this message
52
53 M_StringCopy(exitmsg, DEH_String("Player 1 left the game"),
54 sizeof(exitmsg));
55
56 exitmsg[7] += player_num;
57
58 playeringame[player_num] = false;
59 players[consoleplayer].message = exitmsg;
60 // [crispy] don't interpolate players who left the game
61 player->mo->interp = false;
62
63 // TODO: check if it is sensible to do this:
64
65 if (demorecording)
66 {
67 G_CheckDemoStatus ();
68 }
69 }
70
RunTic(ticcmd_t * cmds,boolean * ingame)71 static void RunTic(ticcmd_t *cmds, boolean *ingame)
72 {
73 extern boolean advancedemo;
74 unsigned int i;
75
76 // Check for player quits.
77
78 for (i = 0; i < MAXPLAYERS; ++i)
79 {
80 if (!demoplayback && playeringame[i] && !ingame[i])
81 {
82 PlayerQuitGame(&players[i]);
83 }
84 }
85
86 netcmds = cmds;
87
88 // check that there are players in the game. if not, we cannot
89 // run a tic.
90
91 if (advancedemo)
92 D_DoAdvanceDemo ();
93
94 G_Ticker ();
95 }
96
97 static loop_interface_t doom_loop_interface = {
98 D_ProcessEvents,
99 G_BuildTiccmd,
100 RunTic,
101 M_Ticker
102 };
103
104
105 // Load game settings from the specified structure and
106 // set global variables.
107
LoadGameSettings(net_gamesettings_t * settings)108 static void LoadGameSettings(net_gamesettings_t *settings)
109 {
110 unsigned int i;
111
112 deathmatch = settings->deathmatch;
113 startepisode = settings->episode;
114 startmap = settings->map;
115 startskill = settings->skill;
116 startloadgame = settings->loadgame;
117 lowres_turn = settings->lowres_turn;
118 nomonsters = settings->nomonsters;
119 fastparm = settings->fast_monsters;
120 respawnparm = settings->respawn_monsters;
121 timelimit = settings->timelimit;
122 consoleplayer = settings->consoleplayer;
123
124 if (lowres_turn)
125 {
126 printf("NOTE: Turning resolution is reduced; this is probably "
127 "because there is a client recording a Vanilla demo.\n");
128 }
129
130 for (i = 0; i < MAXPLAYERS; ++i)
131 {
132 playeringame[i] = i < settings->num_players;
133 }
134 }
135
136 // Save the game settings from global variables to the specified
137 // game settings structure.
138
SaveGameSettings(net_gamesettings_t * settings)139 static void SaveGameSettings(net_gamesettings_t *settings)
140 {
141 // Fill in game settings structure with appropriate parameters
142 // for the new game
143
144 settings->deathmatch = deathmatch;
145 settings->episode = startepisode;
146 settings->map = startmap;
147 settings->skill = startskill;
148 settings->loadgame = startloadgame;
149 settings->gameversion = gameversion;
150 settings->nomonsters = nomonsters;
151 settings->fast_monsters = fastparm;
152 settings->respawn_monsters = respawnparm;
153 settings->timelimit = timelimit;
154
155 settings->lowres_turn = (M_ParmExists("-record")
156 && !M_ParmExists("-longtics"))
157 || M_ParmExists("-shorttics");
158 }
159
InitConnectData(net_connect_data_t * connect_data)160 static void InitConnectData(net_connect_data_t *connect_data)
161 {
162 boolean shorttics;
163
164 connect_data->max_players = MAXPLAYERS;
165 connect_data->drone = false;
166
167 //!
168 // @category net
169 //
170 // Run as the left screen in three screen mode.
171 //
172
173 if (M_CheckParm("-left") > 0)
174 {
175 viewangleoffset = ANG90;
176 connect_data->drone = true;
177 }
178
179 //!
180 // @category net
181 //
182 // Run as the right screen in three screen mode.
183 //
184
185 if (M_CheckParm("-right") > 0)
186 {
187 viewangleoffset = ANG270;
188 connect_data->drone = true;
189 }
190
191 //
192 // Connect data
193 //
194
195 // Game type fields:
196
197 connect_data->gamemode = gamemode;
198 connect_data->gamemission = gamemission;
199
200 //!
201 // @category demo
202 //
203 // Play with low turning resolution to emulate demo recording.
204 //
205
206 shorttics = M_ParmExists("-shorttics");
207
208 // Are we recording a demo? Possibly set lowres turn mode
209
210 connect_data->lowres_turn = (M_ParmExists("-record")
211 && !M_ParmExists("-longtics"))
212 || shorttics;
213
214 // Read checksums of our WAD directory and dehacked information
215
216 W_Checksum(connect_data->wad_sha1sum);
217 DEH_Checksum(connect_data->deh_sha1sum);
218
219 // Are we playing with the Freedoom IWAD?
220
221 connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
222 }
223
D_ConnectNetGame(void)224 void D_ConnectNetGame(void)
225 {
226 net_connect_data_t connect_data;
227
228 InitConnectData(&connect_data);
229 netgame = D_InitNetGame(&connect_data);
230
231 //!
232 // @category net
233 //
234 // Start the game playing as though in a netgame with a single
235 // player. This can also be used to play back single player netgame
236 // demos.
237 //
238
239 if (M_CheckParm("-solo-net") > 0)
240 {
241 netgame = true;
242 }
243 }
244
245 //
246 // D_CheckNetGame
247 // Works out player numbers among the net participants
248 //
D_CheckNetGame(void)249 void D_CheckNetGame (void)
250 {
251 net_gamesettings_t settings;
252
253 if (netgame)
254 {
255 autostart = true;
256 }
257
258 D_RegisterLoopCallbacks(&doom_loop_interface);
259
260 SaveGameSettings(&settings);
261 D_StartNetGame(&settings, NULL);
262 LoadGameSettings(&settings);
263
264 DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
265 startskill, deathmatch, startmap, startepisode);
266
267 DEH_printf("player %i of %i (%i nodes)\n",
268 consoleplayer+1, settings.num_players, settings.num_players);
269
270 // Show players here; the server might have specified a time limit
271
272 if (timelimit > 0 && deathmatch)
273 {
274 // Gross hack to work like Vanilla:
275
276 if (timelimit == 20 && M_CheckParm("-avg"))
277 {
278 DEH_printf("Austin Virtual Gaming: Levels will end "
279 "after 20 minutes\n");
280 }
281 else
282 {
283 DEH_printf("Levels will end after %d minute", timelimit);
284 if (timelimit > 1)
285 printf("s");
286 printf(".\n");
287 }
288 }
289 }
290
291