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