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 "i_system.h"
23 #include "i_timer.h"
24 #include "i_video.h"
25 #include "doomdef.h"
26 #include "m_argv.h"
27 #include "m_misc.h"
28 #include "w_checksum.h"
29 
30 #include "deh_main.h"
31 
32 #include "d_loop.h"
33 
34 ticcmd_t *netcmds;
35 
36 extern void D_DoAdvanceDemo(void);
37 extern void D_ProcessEvents(void);
38 extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic);
39 extern boolean G_CheckDemoStatus(void);
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     // Note:
51     // The Heretic source code does this, which doesn't actually work.
52     // As a result, the exit message is never seen.
53 
54     M_StringCopy(exitmsg, "PLAYER 1 LEFT THE GAME", sizeof(exitmsg));
55     exitmsg[7] += player_num;
56     players[consoleplayer].message = exitmsg;
57 
58     playeringame[player_num] = false;
59     players[consoleplayer].message = exitmsg;
60 
61     // [crispy] don't interpolate players who left the game
62     player->mo->interp = false;
63 
64     // TODO: check if it is sensible to do this:
65 
66     if (demorecording)
67     {
68         G_CheckDemoStatus ();
69     }
70 }
71 
RunTic(ticcmd_t * cmds,boolean * ingame)72 static void RunTic(ticcmd_t *cmds, boolean *ingame)
73 {
74     extern boolean advancedemo;
75     unsigned int i;
76 
77     // Check for player quits.
78 
79     for (i = 0; i < MAXPLAYERS; ++i)
80     {
81         if (!demoplayback && playeringame[i] && !ingame[i])
82         {
83             PlayerQuitGame(&players[i]);
84         }
85     }
86 
87     netcmds = cmds;
88 
89     // check that there are players in the game.  if not, we cannot
90     // run a tic.
91 
92     if (advancedemo)
93         D_DoAdvanceDemo ();
94 
95     G_Ticker ();
96 }
97 
98 static loop_interface_t doom_loop_interface = {
99     D_ProcessEvents,
100     G_BuildTiccmd,
101     RunTic,
102     MN_Ticker
103 };
104 
105 
106 // Load game settings from the specified structure and
107 // set global variables.
108 
LoadGameSettings(net_gamesettings_t * settings)109 static void LoadGameSettings(net_gamesettings_t *settings)
110 {
111     unsigned int i;
112 
113     deathmatch = settings->deathmatch;
114     ticdup = settings->ticdup;
115     startepisode = settings->episode;
116     startmap = settings->map;
117     startskill = settings->skill;
118     // TODO startloadgame = settings->loadgame;
119     lowres_turn = settings->lowres_turn;
120     nomonsters = settings->nomonsters;
121     respawnparm = settings->respawn_monsters;
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     // TODO settings->loadgame = startloadgame;
149     settings->gameversion = exe_heretic_1_3;
150     settings->nomonsters = nomonsters;
151     settings->respawn_monsters = respawnparm;
152     settings->timelimit = 0;
153 
154     settings->lowres_turn = M_ParmExists("-record")
155                          && !M_ParmExists("-longtics");
156 }
157 
InitConnectData(net_connect_data_t * connect_data)158 static void InitConnectData(net_connect_data_t *connect_data)
159 {
160     connect_data->drone = false;
161     connect_data->max_players = MAXPLAYERS;
162 
163     //
164     // Connect data
165     //
166 
167     // Game type fields:
168 
169     connect_data->gamemode = gamemode;
170     connect_data->gamemission = heretic;
171 
172     // Are we recording a demo? Possibly set lowres turn mode
173 
174     connect_data->lowres_turn = M_ParmExists("-record")
175                              && !M_ParmExists("-longtics");
176 
177     // Read checksums of our WAD directory and dehacked information
178 
179     W_Checksum(connect_data->wad_sha1sum);
180     DEH_Checksum(connect_data->deh_sha1sum);
181 
182     connect_data->is_freedoom = 0;
183 }
184 
D_ConnectNetGame(void)185 void D_ConnectNetGame(void)
186 {
187     net_connect_data_t connect_data;
188 
189     InitConnectData(&connect_data);
190     netgame = D_InitNetGame(&connect_data);
191 
192     //!
193     // @category net
194     //
195     // Start the game playing as though in a netgame with a single
196     // player.  This can also be used to play back single player netgame
197     // demos.
198     //
199 
200     if (M_CheckParm("-solo-net") > 0)
201     {
202         netgame = true;
203     }
204 }
205 
206 //
207 // D_CheckNetGame
208 // Works out player numbers among the net participants
209 //
210 
D_CheckNetGame(void)211 void D_CheckNetGame (void)
212 {
213     net_gamesettings_t settings;
214 
215     D_RegisterLoopCallbacks(&doom_loop_interface);
216 
217     if (netgame)
218     {
219         autostart = true;
220     }
221 
222     SaveGameSettings(&settings);
223     D_StartNetGame(&settings, NULL);
224     LoadGameSettings(&settings);
225 }
226 
227