1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2004 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:  none
30  *  The original Doom description was none, basically because this file
31  *  has everything. This ties up the game logic, linking the menu and
32  *  input code to the underlying game by creating & respawning players,
33  *  building game tics, calling the underlying thing logic.
34  *
35  *-----------------------------------------------------------------------------
36  */
37 
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #ifdef _MSC_VER
42 #define    F_OK    0    /* Check for file existence */
43 #define    W_OK    2    /* Check for write permission */
44 #define    R_OK    4    /* Check for read permission */
45 #include <io.h>
46 #include <compat/msvc.h>
47 #endif
48 
49 #include <boolean.h>
50 
51 #include "config.h"
52 
53 #include "doomstat.h"
54 #include "d_net.h"
55 #include "f_finale.h"
56 #include "m_argv.h"
57 #include "m_misc.h"
58 #include "m_menu.h"
59 #include "m_random.h"
60 #include "p_setup.h"
61 #include "p_saveg.h"
62 #include "p_tick.h"
63 #include "p_map.h"
64 #include "p_checksum.h"
65 #include "d_main.h"
66 #include "wi_stuff.h"
67 #include "hu_stuff.h"
68 #include "st_stuff.h"
69 #include "am_map.h"
70 #include "w_wad.h"
71 #include "r_main.h"
72 #include "r_draw.h"
73 #include "p_map.h"
74 #include "s_sound.h"
75 #include "dstrings.h"
76 #include "sounds.h"
77 #include "r_data.h"
78 #include "r_sky.h"
79 #include "d_deh.h"              // Ty 3/27/98 deh declarations
80 #include "p_inter.h"
81 #include "g_game.h"
82 #include "lprintf.h"
83 #include "i_main.h"
84 #include "i_system.h"
85 #include "r_demo.h"
86 #include "r_fps.h"
87 
88 #define SAVEGAMESIZE  0x20000
89 #define SAVESTRINGSIZE  24
90 
91 static size_t   savegamesize = 0; // killough
92 static dbool    netdemo;
93 static const uint8_t *demobuffer;   /* cph - only used for playback */
94 static int demolength; // check for overrun (missing DEMOMARKER)
95 #if 0
96 static FILE    *demofp; /* cph - record straight to file */
97 #endif
98 
99 static const uint8_t *demo_p;
100 static short    consistancy[MAXPLAYERS][BACKUPTICS];
101 
102 gameaction_t    gameaction;
103 gamestate_t     gamestate;
104 skill_t         gameskill;
105 dbool           respawnmonsters;
106 int             gameepisode;
107 int             gamemap;
108 mapentry_t*     gamemapinfo;
109 dbool           paused;
110 // CPhipps - moved *_loadgame vars here
111 static dbool   forced_loadgame = FALSE;
112 static dbool   command_loadgame = FALSE;
113 
114 dbool           usergame;      // ok to save / end game
115 dbool           deathmatch;    // only if started as net death
116 dbool           netgame;       // only TRUE if packets are broadcast
117 dbool           playeringame[MAXPLAYERS];
118 player_t        players[MAXPLAYERS];
119 int             consoleplayer; // player taking events and displaying
120 int             displayplayer; // view being displayed
121 int             gametic;
122 int             basetic;       /* killough 9/29/98: for demo sync */
123 int             totalkills, totallive, totalitems, totalsecret;    // for intermission
124 dbool           demoplayback;
125 int             demover;
126 wbstartstruct_t wminfo;               // parms for world map / intermission
127 dbool           haswolflevels = FALSE;// jff 4/18/98 wolf levels present
128 static uint8_t     *savebuffer;          // CPhipps - static
129 static dbool       savestaticbuffer = FALSE;
130 int             autorun = FALSE;      // always running?          // phares
131 int             totalleveltimes;      // CPhipps - total time for all completed levels
132 int		longtics;
133 
134 //
135 // controls (have defaults)
136 //
137 
138 int     key_right;
139 int     key_left;
140 int     key_up;
141 int     key_down;
142 int     key_menu_right;                                      // phares 3/7/98
143 int     key_menu_left;                                       //     |
144 int     key_menu_up;                                         //     V
145 int     key_menu_down;
146 int     key_menu_backspace;                                  //     ^
147 int     key_menu_escape;                                     //     |
148 int     key_menu_enter;                                      // phares 3/7/98
149 int     key_strafeleft;
150 int     key_straferight;
151 int     key_fire;
152 int     key_use;
153 int     key_strafe;
154 int     key_speed;
155 int     key_escape = KEYD_ESCAPE;                           // phares 4/13/98
156 int     key_savegame;                                               // phares
157 int     key_loadgame;                                               //    |
158 int     key_autorun;                                                //    V
159 int     key_reverse;
160 int     key_zoomin;
161 int     key_zoomout;
162 int     key_chat;
163 int     key_backspace;
164 int     key_enter;
165 int     key_map_right;
166 int     key_map_left;
167 int     key_map_up;
168 int     key_map_down;
169 int     key_map_zoomin;
170 int     key_map_zoomout;
171 int     key_map;
172 int     key_map_gobig;
173 int     key_map_follow;
174 int     key_map_mark;
175 int     key_map_clear;
176 int     key_map_grid;
177 int     key_map_overlay; // cph - map overlay
178 int     key_map_rotate;  // cph - map rotation
179 int     key_help = KEYD_F1;                                 // phares 4/13/98
180 int     key_soundvolume;
181 int     key_hud;
182 int     key_quicksave;
183 int     key_endgame;
184 int     key_messages;
185 int     key_quickload;
186 int     key_quit;
187 int     key_gamma;
188 int     key_spy;
189 int     key_pause;
190 int     key_setup;
191 int     destination_keys[MAXPLAYERS];
192 int     key_weapontoggle;
193 int     key_weaponcycleup;
194 int     key_weaponcycledown;
195 int     key_weapon1;
196 int     key_weapon2;
197 int     key_weapon3;
198 int     key_weapon4;
199 int     key_weapon5;
200 int     key_weapon6;
201 int     key_weapon7;                                                //    ^
202 int     key_weapon8;                                                //    |
203 int     key_weapon9;                                                // phares
204 
205 int     key_screenshot;             // killough 2/22/98: screenshot key
206 int     mousebfire;
207 int     mousebstrafe;
208 int     mousebforward;
209 int     mousebbackward;
210 int     mlooky;
211 
212 #define MAXPLMOVE   (forwardmove[1])
213 #define TURBOTHRESHOLD  0x32
214 #define SLOWTURNTICS  6
215 #define QUICKREVERSE (short)32768 // 180 degree reverse                    // phares
216 #define NUMKEYS   512
217 
218 fixed_t forwardmove[2] = {0x19, 0x32};
219 fixed_t sidemove[2]    = {0x18, 0x28};
220 fixed_t angleturn[3]   = {640, 1280, 320};  // + slow turn
221 
222 // CPhipps - made lots of key/button state vars static
223 dbool   gamekeydown[NUMKEYS];
224 int     turnheld;       // for accelerative turning
225 
226 static dbool   mousearray[4];
227 static dbool   *mousebuttons = &mousearray[1];    // allow [-1]
228 
229 // mouse values are used once
230 static int   mousex;
231 static int   mousey;
232 
233 // Game events info
234 static buttoncode_t special_event; // Event triggered by local player, to send
235 static uint8_t  savegameslot;         // Slot to load if gameaction == ga_loadgame
236 char         savedescription[SAVEDESCLEN];  // Description to save in savegame if gameaction == ga_savegame
237 
238 //jff 3/24/98 define defaultskill here
239 int defaultskill;               //note 1-based
240 
241 // killough 2/8/98: make corpse queue variable in size
242 int    bodyqueslot, bodyquesize;        // killough 2/8/98
243 mobj_t **bodyque = 0;                   // phares 8/10/98
244 
245 static void G_DoSaveGame (dbool   menu);
246 static const uint8_t* G_ReadDemoHeader(const uint8_t* demo_p, size_t size, dbool   failonerror);
247 static mapentry_t *G_LookupMapinfo(int episode, int map);
248 
249 //
250 // G_BuildTiccmd
251 // Builds a ticcmd from all of the available inputs
252 // or reads it from the demo buffer.
253 // If recording a demo, write it out
254 //
fudgef(signed char b)255 static INLINE signed char fudgef(signed char b)
256 {
257   static int c;
258   if (!b || !demo_compatibility || longtics) return b;
259   if (++c & 0x1f) return b;
260   b |= 1; if (b>2) b-=2;
261   return b;
262 }
263 
fudgea(signed short b)264 static INLINE signed short fudgea(signed short b)
265 {
266   if (!b || !demo_compatibility || !longtics) return b;
267   b |= 1; if (b>2) b-=2;
268   return b;
269 }
270 
271 
G_BuildTiccmd(ticcmd_t * cmd)272 void G_BuildTiccmd(ticcmd_t* cmd)
273 {
274   dbool   strafe;
275   int speed;
276   int tspeed;
277   int forward;
278   int side;
279   int newweapon   = WP_NOCHANGE;
280   dbool   bstrafe = FALSE;
281   /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */
282   memset(cmd,0,sizeof*cmd);
283   cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
284 
285   (void)bstrafe;
286 
287   strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe];
288   //e6y: the "RUN" key inverts the autorun state
289   speed = (gamekeydown[key_speed] ? !autorun : autorun); // phares
290 
291   forward = side = 0;
292 
293     // use two stage accelerative turning
294     // on the keyboard
295   if (gamekeydown[key_right] || gamekeydown[key_left])
296     turnheld += ticdup;
297   else
298     turnheld = 0;
299 
300   if (turnheld < SLOWTURNTICS)
301     tspeed = 2;             // slow turn
302   else
303     tspeed = speed;
304 
305   // turn 180 degrees in one keystroke?                           // phares
306                                                                   //    |
307   if (gamekeydown[key_reverse])                                   //    V
308     {
309       cmd->angleturn += QUICKREVERSE;                             //    ^
310       gamekeydown[key_reverse] = FALSE;                           //    |
311     }                                                             // phares
312 
313   // let movement keys cancel each other out
314 
315   if (strafe)
316     {
317       if (gamekeydown[key_right])
318         side += sidemove[speed];
319       if (gamekeydown[key_left])
320         side -= sidemove[speed];
321     }
322   else
323     {
324       if (gamekeydown[key_right])
325         cmd->angleturn -= angleturn[tspeed];
326       if (gamekeydown[key_left])
327         cmd->angleturn += angleturn[tspeed];
328     }
329 
330   if (gamekeydown[key_up])
331     forward += forwardmove[speed];
332   if (gamekeydown[key_down])
333     forward -= forwardmove[speed];
334   if (gamekeydown[key_straferight])
335     side += sidemove[speed];
336   if (gamekeydown[key_strafeleft])
337     side -= sidemove[speed];
338 
339     // buttons
340   cmd->chatchar = HU_dequeueChatChar();
341 
342   if (gamekeydown[key_fire] || mousebuttons[mousebfire])
343     cmd->buttons |= BT_ATTACK;
344 
345   if (gamekeydown[key_use] || mousebuttons[mousebforward])
346     {
347       cmd->buttons |= BT_USE;
348     }
349 
350   // Toggle between the top 2 favorite weapons.                   // phares
351   // If not currently aiming one of these, switch to              // phares
352   // the favorite. Only switch if you possess the weapon.         // phares
353 
354   // killough 3/22/98:
355   //
356   // Perform automatic weapons switch here rather than in p_pspr.c,
357   // except in demo_compatibility mode.
358   //
359   // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left
360 
361   if ((!demo_compatibility && players[consoleplayer].attackdown && // killough
362        !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle])
363   {
364 	  newweapon = P_SwitchWeapon(&players[consoleplayer]);           // phares
365   }
366   else if (gamekeydown[key_weaponcycleup] || gamekeydown[key_weaponcycledown])
367   {
368 	  static weapontype_t weapons_list[] = {WP_FIST, WP_CHAINSAW, WP_PISTOL, WP_SHOTGUN, WP_SUPERSHOTGUN, WP_CHAINGUN, WP_MISSILE, WP_PLASMA, WP_BFG};
369 	  int i;
370 	  weapontype_t origweapon = players[consoleplayer].readyweapon;
371 	  int oldweapon = 0;
372 
373 	  for(i = 0; i != 9; i ++)
374 	  {
375 		  if(weapons_list[i] == players[consoleplayer].readyweapon)
376 		  {
377 			  oldweapon = i;
378 			  break;
379 		  }
380 	  }
381 
382 	  for(i = 0; i != 9; i ++)
383 	  {
384 		  if(gamekeydown[key_weaponcycleup])
385 			  oldweapon ++;
386 		  else
387 			  oldweapon --;
388 		  if(oldweapon < 0)
389 			  oldweapon = 8;
390 		  if(oldweapon > 8)
391 			  oldweapon = 0;
392 
393 		  // I SHOULD just write a P_CheckAmmo that takes the weapon as an argument... This will die if multithreaded...
394 		  players[consoleplayer].readyweapon = weapons_list[oldweapon];
395 
396 		  if(players[consoleplayer].weaponowned[players[consoleplayer].readyweapon] && P_CheckAmmo(&players[consoleplayer]))
397 		  {
398 			  newweapon = players[consoleplayer].readyweapon;
399 			  break;
400 		  }
401 	  }
402 	  players[consoleplayer].readyweapon = origweapon;
403   }
404   else
405   {                                 // phares 02/26/98: Added gamemode checks
406 	  newweapon =
407 		  gamekeydown[key_weapon1] ? WP_FIST :    // killough 5/2/98: reformatted
408 		  gamekeydown[key_weapon2] ? WP_PISTOL :
409 		  gamekeydown[key_weapon3] ? WP_SHOTGUN :
410 		  gamekeydown[key_weapon4] ? WP_CHAINGUN :
411 		  gamekeydown[key_weapon5] ? WP_MISSILE :
412 		  gamekeydown[key_weapon6] && gamemode != shareware ? WP_PLASMA :
413 		  gamekeydown[key_weapon7] && gamemode != shareware ? WP_BFG :
414 		  gamekeydown[key_weapon8] ? WP_CHAINSAW :
415 		  (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? WP_SUPERSHOTGUN :
416 		  WP_NOCHANGE;
417 
418 	  // killough 3/22/98: For network and demo consistency with the
419 	  // new weapons preferences, we must do the weapons switches here
420 	  // instead of in p_user.c. But for old demos we must do it in
421 	  // p_user.c according to the old rules. Therefore demo_compatibility
422 	  // determines where the weapons switch is made.
423 
424 	  // killough 2/8/98:
425 	  // Allow user to switch to fist even if they have chainsaw.
426 	  // Switch to fist or chainsaw based on preferences.
427 	  // Switch to shotgun or SSG based on preferences.
428 
429 	  if (!demo_compatibility)
430 	  {
431 		  const player_t *player = &players[consoleplayer];
432 
433 		  // only select chainsaw from '1' if it's owned, it's
434 		  // not already in use, and the player prefers it or
435 		  // the fist is already in use, or the player does not
436 		  // have the berserker strength.
437 
438 		  if (newweapon==WP_FIST && player->weaponowned[WP_CHAINSAW] &&
439 				  player->readyweapon!=WP_CHAINSAW &&
440 				  (player->readyweapon==WP_FIST ||
441 				   !player->powers[pw_strength] ||
442 				   P_WeaponPreferred(WP_CHAINSAW, WP_FIST)))
443 			  newweapon = WP_CHAINSAW;
444 
445 		  // Select SSG from '3' only if it's owned and the player
446 		  // does not have a shotgun, or if the shotgun is already
447 		  // in use, or if the SSG is not already in use and the
448 		  // player prefers it.
449 
450 		  if (newweapon == WP_SHOTGUN && gamemode == commercial &&
451 				  player->weaponowned[WP_SUPERSHOTGUN] &&
452 				  (!player->weaponowned[WP_SHOTGUN] ||
453 				   player->readyweapon == WP_SHOTGUN ||
454 				   (player->readyweapon != WP_SUPERSHOTGUN &&
455 				    P_WeaponPreferred(WP_SUPERSHOTGUN, WP_SHOTGUN))))
456 			  newweapon = WP_SUPERSHOTGUN;
457 	  }
458 	  // killough 2/8/98, 3/22/98 -- end of weapon selection changes
459   }
460 
461   if (newweapon != WP_NOCHANGE)
462     {
463       cmd->buttons |= BT_CHANGE;
464       cmd->buttons |= newweapon<<BT_WEAPONSHIFT;
465     }
466 
467   // mouse
468   if (mousebuttons[mousebbackward])
469     forward -= forwardmove[speed];
470 
471   bstrafe = mousebuttons[mousebstrafe];
472   if (strafe)
473     side += mousex / 4;       /* mead  Don't want to strafe as fast as turns.*/
474   else
475     cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */
476 
477   // if mouselook enabled, set pitch without affecting the tic cmds
478   if (movement_mouselook) {
479      if (movement_mouseinvert)
480         mlooky -= mousey;
481      else
482         mlooky += mousey;
483   }
484 
485   mousex = mousey = 0;
486 
487   if (forward > MAXPLMOVE)
488     forward = MAXPLMOVE;
489   else if (forward < -MAXPLMOVE)
490     forward = -MAXPLMOVE;
491   if (side > MAXPLMOVE)
492     side = MAXPLMOVE;
493   else if (side < -MAXPLMOVE)
494     side = -MAXPLMOVE;
495 
496   cmd->forwardmove += fudgef((signed char)forward);
497   cmd->sidemove += side;
498   cmd->angleturn = fudgea(cmd->angleturn);
499 
500   // CPhipps - special events (game new/load/save/pause)
501   if (special_event & BT_SPECIAL) {
502     cmd->buttons = special_event;
503     special_event = 0;
504   }
505 }
506 
507 //
508 // G_CheckNumForLevel
509 //
510 // Returns the level lump number if it exists, -1 otherwise
511 //
G_CheckNumForLevel(int episode,int map)512 int G_CheckNumForLevel(int episode, int map)
513 {
514   char mapname[9];
515   if (gamemode == commercial)
516     sprintf(mapname, "MAP%.2d", map);
517   else
518     sprintf(mapname, "E%dM%d", episode, map);
519 
520   return W_CheckNumForName(mapname);
521 }
522 
523 //
524 // G_RestartLevel
525 //
526 
G_RestartLevel(void)527 void G_RestartLevel(void)
528 {
529   special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK);
530 }
531 
532 #include "z_bmalloc.h"
533 
534 /*
535 ==============
536 =
537 = G_DoLoadLevel
538 =
539 ==============
540 */
541 
G_DoLoadLevel(void)542 static void G_DoLoadLevel (void)
543 {
544   int i;
545 
546   lprintf(LO_INFO, "------------------------------\n"
547           "G_DoLoadLevel:  ===== Episode %d - Map %.2d =====\n",
548           gameepisode, gamemap);
549 
550   /* Set the sky map for the episode.
551    * First thing, we have a dummy sky texture name,
552    *  a flat. The data is in the WAD only because
553    *  we look for an actual index, instead of simply
554    *  setting one.
555    */
556   skyflatnum = R_FlatNumForName ( SKYFLATNAME );
557 
558   /* skytexture set through UMAPINFO */
559   if (gamemapinfo && gamemapinfo->skytexture[0])
560   {
561     skytexture = R_TextureNumForName(gamemapinfo->skytexture);
562   }
563   /* DOOM determines the sky texture to be used
564    * depending on the current episode, and the game version.
565    */
566   else if (gamemode == commercial)
567      // || gamemode == pack_tnt   //jff 3/27/98 sorry guys pack_tnt,pack_plut
568      // || gamemode == pack_plut) //aren't gamemodes, this was matching retail
569   {
570     skytexture = R_TextureNumForName ("SKY3");
571     if (gamemap < 12)
572       skytexture = R_TextureNumForName ("SKY1");
573     else
574       if (gamemap < 21)
575         skytexture = R_TextureNumForName ("SKY2");
576   }
577   else /* and lets not forget about DOOM, Ultimate DOOM, SIGIL & extra Eps */
578   {
579     // Each episode has its own sky, numbered after it
580     char skyname[9];
581     sprintf(skyname, "SKY%d", gameepisode);
582     skytexture = R_CheckTextureNumForName(skyname);
583     if (skytexture == -1)
584       // default sky, in case of custom episodes with missing SKY
585       skytexture = R_TextureNumForName ("SKY1");
586   }
587 
588   /* cph 2006/07/31 - took out unused levelstarttic variable */
589 
590   if (!demo_compatibility && !mbf_features)   // killough 9/29/98
591      basetic = gametic;
592 
593   if (wipegamestate == GS_LEVEL && (gameaction == ga_newgame || gameaction == ga_completed))
594      wipegamestate = -1;             // force a wipe
595 
596   gamestate = GS_LEVEL;
597 
598   for (i=0 ; i<MAXPLAYERS ; i++)
599   {
600     if (playeringame[i] && players[i].playerstate == PST_DEAD)
601       players[i].playerstate = PST_REBORN;
602     memset (players[i].frags,0,sizeof(players[i].frags));
603   }
604 
605   // initialize the msecnode_t freelist.                     phares 3/25/98
606   // any nodes in the freelist are gone by now, cleared
607   // by Z_FreeTags() when the previous level ended or player
608   // died.
609 
610   {
611     DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
612     NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
613     //extern msecnode_t *headsecnode; // phares 3/25/98
614     //headsecnode = NULL;
615   }
616 
617   P_SetupLevel (gameepisode, gamemap, 0, gameskill);
618   if (!demoplayback) /* Don't switch views if playing a demo */
619     displayplayer = consoleplayer;    /* view the guy you are playing */
620   gameaction = ga_nothing;
621 
622   Z_CheckHeap ();
623 
624   /* clear cmd building stuff */
625   memset (gamekeydown, 0, sizeof(gamekeydown));
626   mousex = mousey = 0;
627   mlooky = 0;
628   special_event = 0; paused = FALSE;
629   memset (mousebuttons, 0, sizeof(*mousebuttons));
630 
631   // killough 5/13/98: in case netdemo has consoleplayer other than green
632   ST_Start();
633   HU_Start();
634 }
635 
636 
637 //
638 // G_Responder
639 // Get info needed to make ticcmd_ts for the players.
640 //
641 
G_Responder(event_t * ev)642 dbool   G_Responder (event_t* ev)
643 {
644   // allow spy mode changes even during the demo
645   // killough 2/22/98: even during DM demo
646   //
647   // killough 11/98: don't autorepeat spy mode switch
648 
649   if (ev->data1 == key_spy && netgame && (demoplayback || !deathmatch) &&
650       gamestate == GS_LEVEL)
651     {
652       if (ev->type == ev_keyup)
653   gamekeydown[key_spy] = FALSE;
654       if (ev->type == ev_keydown && !gamekeydown[key_spy])
655   {
656     gamekeydown[key_spy] = TRUE;
657     do                                          // spy mode
658       if (++displayplayer >= MAXPLAYERS)
659         displayplayer = 0;
660     while (!playeringame[displayplayer] && displayplayer!=consoleplayer);
661 
662     ST_Start();    // killough 3/7/98: switch status bar views too
663     HU_Start();
664     S_UpdateSounds(players[displayplayer].mo);
665 
666     R_ActivateSectorInterpolations();
667     R_SmoothPlaying_Reset(NULL);
668   }
669       return TRUE;
670     }
671 
672   // any other key pops up menu if in demos
673   //
674   // killough 8/2/98: enable automap in -timedemo demos
675   //
676   // killough 9/29/98: make any key pop up menu regardless of
677   // which kind of demo, and allow other events during playback
678 
679   if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN))
680     {
681       // killough 9/29/98: allow user to pause demos during playback
682       if (ev->type == ev_keydown && ev->data1 == key_pause)
683   {
684     if (paused ^= 2)
685       S_PauseSound();
686     else
687       S_ResumeSound();
688     return TRUE;
689   }
690 
691       // killough 10/98:
692       // Don't pop up menu, if paused in middle
693       // of demo playback, or if automap active.
694       // Don't suck up keys, which may be cheats
695 
696       return gamestate == GS_DEMOSCREEN &&
697   !(paused & 2) && !(automapmode & am_active) &&
698   ((ev->type == ev_keydown) ||
699    (ev->type == ev_mouse && ev->data1)) ?
700   M_StartControlPanel(), TRUE : FALSE;
701     }
702 
703   if (gamestate == GS_FINALE && F_Responder(ev))
704     return TRUE;  // finale ate the event
705 
706   switch (ev->type)
707     {
708     case ev_keydown:
709       if (ev->data1 == key_pause)           // phares
710         {
711           special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK);
712           return TRUE;
713         }
714       if (ev->data1 <NUMKEYS)
715         gamekeydown[ev->data1] = TRUE;
716       return TRUE;    // eat key down events
717 
718     case ev_keyup:
719       if (ev->data1 <NUMKEYS)
720         gamekeydown[ev->data1] = FALSE;
721       return FALSE;   // always let key up events filter down
722 
723     case ev_mouse:
724       mousebuttons[0] = ev->data1 & 1;
725       mousebuttons[1] = ev->data1 & 2;
726       mousebuttons[2] = ev->data1 & 4;
727       /*
728        * bmead@surfree.com
729        * Modified by Barry Mead after adding vastly more resolution
730        * to the Mouse Sensitivity Slider in the options menu 1-9-2000
731        * Removed the mouseSensitivity "*4" to allow more low end
732        * sensitivity resolution especially for lsdoom users.
733        */
734       mousex += (ev->data2*(mouseSensitivity_horiz))/10;  /* killough */
735       mousey += (ev->data3*(mouseSensitivity_vert))/10;  /*Mead rm *4 */
736       return TRUE;    // eat events
737     default:
738       break;
739     }
740   return FALSE;
741 }
742 
743 //
744 // G_Ticker
745 // Make ticcmd_ts for the players.
746 //
747 
G_Ticker(void)748 void G_Ticker (void)
749 {
750   int i;
751   static gamestate_t prevgamestate;
752 
753   // CPhipps - player colour changing
754   if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) {
755     // Changed my multiplayer colour - Inform the whole game
756 #ifdef HAVE_NET
757     int net_cl = LONG(mapcolor_me);
758     D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl);
759 #endif
760     G_ChangedPlayerColour(consoleplayer, mapcolor_me);
761   }
762   P_MapStart();
763   // do player reborns if needed
764   for (i=0 ; i<MAXPLAYERS ; i++)
765     if (playeringame[i] && players[i].playerstate == PST_REBORN)
766       G_DoReborn (i);
767   P_MapEnd();
768 
769   // do things to change the game state
770   while (gameaction != ga_nothing)
771     {
772       switch (gameaction)
773         {
774         case ga_loadlevel:
775     // force players to be initialized on level reload
776     for (i=0 ; i<MAXPLAYERS ; i++)
777       players[i].playerstate = PST_REBORN;
778           G_DoLoadLevel ();
779           break;
780         case ga_newgame:
781           G_DoNewGame ();
782           break;
783         case ga_loadgame:
784           G_DoLoadGame ();
785           break;
786         case ga_savegame:
787           G_DoSaveGame (FALSE);
788           break;
789         case ga_playdemo:
790           G_DoPlayDemo ();
791           break;
792         case ga_completed:
793           G_DoCompleted ();
794           break;
795         case ga_victory:
796           F_StartFinale ();
797           break;
798         case ga_worlddone:
799           G_DoWorldDone ();
800           break;
801         case ga_nothing:
802           break;
803         }
804     }
805 
806   if (paused & 2 || (!demoplayback && menuactive && !netgame))
807     basetic++;  // For revenant tracers and RNG -- we must maintain sync
808   else {
809     // get commands, check consistancy, and build new consistancy check
810     int buf = (gametic/ticdup)%BACKUPTICS;
811 
812     for (i=0 ; i<MAXPLAYERS ; i++) {
813       if (playeringame[i])
814         {
815           ticcmd_t *cmd = &players[i].cmd;
816 
817           memcpy(cmd, &netcmds[i][buf], sizeof *cmd);
818 
819           if (demoplayback)
820             G_ReadDemoTiccmd (cmd);
821 
822           // check for turbo cheats
823           // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
824 
825           if ((netgame || demoplayback) && cmd->forwardmove > TURBOTHRESHOLD &&
826               !(gametic&31) && ((gametic>>5)&3) == i )
827             {
828         extern char *player_names[];
829         /* cph - don't use sprintf, use doom_printf */
830               doom_printf ("%s is turbo!", player_names[i]);
831             }
832 
833           if (netgame && !netdemo && !(gametic%ticdup) )
834             {
835               if (gametic > BACKUPTICS
836                   && consistancy[i][buf] != cmd->consistancy)
837                 I_Error("G_Ticker: Consistency failure (%i should be %i)",
838             cmd->consistancy, consistancy[i][buf]);
839               if (players[i].mo)
840                 consistancy[i][buf] = players[i].mo->x;
841               else
842                 consistancy[i][buf] = 0; // killough 2/14/98
843             }
844         }
845     }
846 
847     // check for special buttons
848     for (i=0; i<MAXPLAYERS; i++) {
849       if (playeringame[i])
850         {
851           if (players[i].cmd.buttons & BT_SPECIAL)
852             {
853               switch (players[i].cmd.buttons & BT_SPECIALMASK)
854                 {
855                 case BTS_PAUSE:
856                   paused ^= 1;
857                   if (paused)
858                     S_PauseSound ();
859                   else
860                     S_ResumeSound ();
861                   break;
862 
863                 case BTS_SAVEGAME:
864                   if (!savedescription[0])
865                     strcpy(savedescription, "NET GAME");
866                   savegameslot =
867                     (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
868                   gameaction = ga_savegame;
869                   break;
870 
871       // CPhipps - remote loadgame request
872                 case BTS_LOADGAME:
873                   savegameslot =
874                     (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
875                   gameaction = ga_loadgame;
876       forced_loadgame = netgame; // Force if a netgame
877       command_loadgame = FALSE;
878                   break;
879 
880       // CPhipps - Restart the level
881     case BTS_RESTARTLEVEL:
882                   if (demoplayback || (compatibility_level < lxdoom_1_compatibility))
883                     break;     // CPhipps - Ignore in demos or old games
884       gameaction = ga_loadlevel;
885       break;
886                 }
887         players[i].cmd.buttons = 0;
888             }
889         }
890     }
891   }
892 
893   // cph - if the gamestate changed, we may need to clean up the old gamestate
894   if (gamestate != prevgamestate) {
895     switch (prevgamestate) {
896     case GS_LEVEL:
897       // This causes crashes at level end - Neil Stevens
898       // The crash is because the sounds aren't stopped before freeing them
899       // the following is a possible fix
900       // This fix does avoid the crash wowever, with this fix in, the exit
901       // switch sound is cut off
902       // S_Stop();
903       // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
904       break;
905     case GS_INTERMISSION:
906       WI_End();
907     default:
908       break;
909     }
910     prevgamestate = gamestate;
911   }
912 
913   // e6y
914   // do nothing if a pause has been pressed during playback
915   // pausing during intermission can cause desynchs without that
916   if (paused & 2 && gamestate != GS_LEVEL)
917     return;
918 
919   // do main actions
920   switch (gamestate)
921     {
922     case GS_LEVEL:
923       P_Ticker ();
924       ST_Ticker ();
925       AM_Ticker ();
926       HU_Ticker ();
927       break;
928 
929     case GS_INTERMISSION:
930       WI_Ticker ();
931       break;
932 
933     case GS_FINALE:
934       F_Ticker ();
935       break;
936 
937     case GS_DEMOSCREEN:
938       D_PageTicker ();
939       break;
940 
941     default:
942       break;
943     }
944 }
945 
946 //
947 // PLAYER STRUCTURE FUNCTIONS
948 // also see P_SpawnPlayer in P_Things
949 //
950 
951 /*
952 ====================
953 =
954 = G_PlayerFinishLevel
955 =
956 = Can when a player completes a level
957 ====================
958 */
959 
G_PlayerFinishLevel(int player)960 static void G_PlayerFinishLevel(int player)
961 {
962   player_t *p = &players[player];
963 
964   memset(p->powers, 0, sizeof p->powers);
965   memset(p->cards, 0, sizeof p->cards);
966 
967   p->mo = NULL;           // cph - this is allocated PU_LEVEL so it's gone
968   p->extralight = 0;      /* cancel gun flashes */
969   p->fixedcolormap = 0;   /* cancel ir gogles */
970   p->damagecount = 0;     /* no palette changes */
971   p->bonuscount = 0;
972 }
973 
974 // CPhipps - G_SetPlayerColour
975 // Player colours stuff
976 //
977 // G_SetPlayerColour
978 
979 #include "r_draw.h"
980 
G_ChangedPlayerColour(int pn,int cl)981 void G_ChangedPlayerColour(int pn, int cl)
982 {
983   int i;
984 
985   if (!netgame) return;
986 
987   mapcolor_plyr[pn] = cl;
988 
989   // Rebuild colour translation tables accordingly
990   R_InitTranslationTables();
991   // Change translations on existing player mobj's
992   for (i=0; i<MAXPLAYERS; i++) {
993     if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) {
994       players[i].mo->flags &= ~MF_TRANSLATION;
995       players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT;
996     }
997   }
998 }
999 
1000 /*
1001 ====================
1002 =
1003 = G_PlayerReborn
1004 =
1005 = Called after a player dies
1006 = almost everything is cleared and initialized
1007 ====================
1008 */
1009 
G_PlayerReborn(int player)1010 void G_PlayerReborn (int player)
1011 {
1012   player_t *p;
1013   int i;
1014   int frags[MAXPLAYERS];
1015   int killcount;
1016   int itemcount;
1017   int secretcount;
1018 
1019   memcpy (frags, players[player].frags, sizeof frags);
1020   killcount = players[player].killcount;
1021   itemcount = players[player].itemcount;
1022   secretcount = players[player].secretcount;
1023 
1024   p = &players[player];
1025 
1026   // killough 3/10/98,3/21/98: preserve cheats across idclev
1027   {
1028     int cheats = p->cheats;
1029     memset (p, 0, sizeof(*p));
1030     p->cheats = cheats;
1031   }
1032 
1033   memcpy(players[player].frags, frags, sizeof(players[player].frags));
1034   players[player].killcount = killcount;
1035   players[player].itemcount = itemcount;
1036   players[player].secretcount = secretcount;
1037 
1038   p->usedown = p->attackdown = true;  // don't do anything immediately
1039   p->playerstate = PST_LIVE;
1040   p->health = initial_health;  // Ty 03/12/98 - use dehacked values
1041   p->readyweapon = p->pendingweapon = WP_PISTOL;
1042   p->weaponowned[WP_FIST] = true;
1043   p->weaponowned[WP_PISTOL] = true;
1044   p->ammo[AM_CLIP] = initial_bullets; // Ty 03/12/98 - use dehacked values
1045 
1046   for (i=0 ; i<NUMAMMO ; i++)
1047     p->maxammo[i] = maxammo[i];
1048 }
1049 
1050 /*
1051 ====================
1052 =
1053 = G_CheckSpot
1054 =
1055 = Returns false if the player cannot be respawned at the given mapthing_t spot
1056 = because something is occupying it
1057 ====================
1058 */
1059 
G_CheckSpot(int playernum,mapthing_t * mthing)1060 static dbool   G_CheckSpot(int playernum, mapthing_t *mthing)
1061 {
1062   fixed_t     x,y;
1063   subsector_t *ss;
1064   int         i;
1065 
1066   if (!players[playernum].mo)
1067   {
1068      /* first spawn of level, before corpses */
1069      for (i=0 ; i<playernum ; i++)
1070         if (players[i].mo->x == mthing->x << FRACBITS
1071               && players[i].mo->y == mthing->y << FRACBITS)
1072            return FALSE;
1073      return TRUE;
1074   }
1075 
1076   x = mthing->x << FRACBITS;
1077   y = mthing->y << FRACBITS;
1078 
1079   // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
1080   // corpse to detect collisions with other players in DM starts
1081   //
1082   // Old code:
1083   // if (!P_CheckPosition (players[playernum].mo, x, y))
1084   //    return FALSE;
1085 
1086   players[playernum].mo->flags |=  MF_SOLID;
1087   i = P_CheckPosition(players[playernum].mo, x, y);
1088   players[playernum].mo->flags &= ~MF_SOLID;
1089   if (!i)
1090     return FALSE;
1091 
1092   // flush an old corpse if needed
1093   // killough 2/8/98: make corpse queue have an adjustable limit
1094   // killough 8/1/98: Fix bugs causing strange crashes
1095 
1096   if (bodyquesize > 0)
1097     {
1098       static int queuesize;
1099       if (queuesize < bodyquesize)
1100 	{
1101 	  bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque);
1102 	  memset(bodyque+queuesize, 0,
1103 		 (bodyquesize-queuesize)*sizeof*bodyque);
1104 	  queuesize = bodyquesize;
1105 	}
1106       if (bodyqueslot >= bodyquesize)
1107 	P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]);
1108       bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo;
1109     }
1110   else
1111     if (!bodyquesize)
1112       P_RemoveMobj(players[playernum].mo);
1113 
1114   /* spawn a teleport fog */
1115   ss = R_PointInSubsector (x,y);
1116   {
1117      // Teleport fog at respawn point
1118     fixed_t xa,ya;
1119     int an;
1120     mobj_t      *mo;
1121 
1122 /* BUG: an can end up negative, because mthing->angle is (signed) short.
1123  * We have to emulate original Doom's behaviour, deferencing past the start
1124  * of the array, into the previous array (finetangent) */
1125     an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT;
1126     xa = finecosine[an];
1127     ya = finesine[an];
1128 
1129     if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility)
1130       switch (an) {
1131       case -4096: xa = finetangent[2048];   // finecosine[-4096]
1132           	ya = finetangent[0];      // finesine[-4096]
1133           	break;
1134       case -3072: xa = finetangent[3072];   // finecosine[-3072]
1135           	ya = finetangent[1024];   // finesine[-3072]
1136           	break;
1137       case -2048: xa = finesine[0];   // finecosine[-2048]
1138           	ya = finetangent[2048];   // finesine[-2048]
1139           	break;
1140       case -1024:	xa = finesine[1024];     // finecosine[-1024]
1141           	ya = finetangent[3072];  // finesine[-1024]
1142           	break;
1143       case 1024:
1144       case 2048:
1145       case 3072:
1146       case 4096:
1147       case 0:	break; /* correct angles set above */
1148       default:	I_Error("G_CheckSpot: unexpected angle %d\n",an);
1149       }
1150 
1151     mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG);
1152 
1153     if (players[consoleplayer].viewz != 1)
1154       S_StartSound(mo, sfx_telept);  // don't start sound on first frame
1155   }
1156 
1157   return TRUE;
1158 }
1159 
1160 
1161 /*
1162 ====================
1163 =
1164 = G_DeathMatchSpawnPlayer
1165 =
1166 = Spawns a player at one of the random death match spots
1167 = called at level load and each death
1168 ====================
1169 */
1170 
G_DeathMatchSpawnPlayer(int playernum)1171 void G_DeathMatchSpawnPlayer (int playernum)
1172 {
1173    int i, j;
1174    int selections = deathmatch_p - deathmatchstarts;
1175 
1176    if (selections < MAXPLAYERS)
1177       I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required",
1178             selections, MAXPLAYERS);
1179 
1180    for (j=0 ; j<20 ; j++)
1181    {
1182       i = P_Random(pr_dmspawn) % selections;
1183       if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1184       {
1185          deathmatchstarts[i].type = playernum+1;
1186          P_SpawnPlayer (playernum, &deathmatchstarts[i]);
1187          return;
1188       }
1189    }
1190 
1191    /* no good spot, so the player will probably get stuck */
1192    P_SpawnPlayer (playernum, &playerstarts[playernum]);
1193 }
1194 
1195 /*
1196 ====================
1197 =
1198 = G_DoReborn
1199 =
1200 ====================
1201 */
1202 
G_DoReborn(int playernum)1203 void G_DoReborn (int playernum)
1204 {
1205    int i;
1206 
1207    if (!netgame)
1208    {
1209       gameaction = ga_loadlevel;			/* reload the level from scratch  */
1210       return;
1211    }
1212 
1213    /*	respawn this player while the other players keep going */
1214 
1215    /* dissasociate the corpse */
1216    players[playernum].mo->player = NULL;
1217 
1218    /* spawn at random spot if in death match */
1219    if (deathmatch)
1220    {
1221       G_DeathMatchSpawnPlayer (playernum);
1222       return;
1223    }
1224 
1225    if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1226    {
1227       P_SpawnPlayer (playernum, &playerstarts[playernum]);
1228       return;
1229    }
1230 
1231    /* try to spawn at one of the other players spots */
1232    for (i=0 ; i<MAXPLAYERS ; i++)
1233    {
1234       if (G_CheckSpot (playernum, &playerstarts[i]) )
1235       {
1236          P_SpawnPlayer (playernum, &playerstarts[i]);
1237          return;
1238       }
1239    }
1240 
1241    /* he's going to be inside something.  Too bad. */
1242    P_SpawnPlayer (playernum, &playerstarts[playernum]);
1243 }
1244 
1245 // DOOM Par Times
1246 int pars[4][10] = {
1247   {0},
1248   {0,30,75,120,90,165,180,180,30,165},
1249   {0,90,90,90,120,90,360,240,30,170},
1250   {0,90,45,90,150,90,90,165,30,135}
1251 };
1252 
1253 // DOOM II Par Times
1254 int cpars[32] = {
1255   30,90,120,120,90,150,120,120,270,90,  //  1-10
1256   210,150,150,150,210,150,420,150,210,150,  // 11-20
1257   240,150,180,150,150,300,330,420,300,180,  // 21-30
1258   120,30          // 31-32
1259 };
1260 
1261 dbool   secretexit;
1262 
1263 /*
1264 ====================
1265 =
1266 = G_ExitLevel
1267 =
1268 ====================
1269 */
1270 
G_ExitLevel(void)1271 void G_ExitLevel (void)
1272 {
1273   secretexit = FALSE;
1274   gameaction = ga_completed;
1275 }
1276 
1277 // Here's for the german edition.
1278 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1279 
G_SecretExitLevel(void)1280 void G_SecretExitLevel (void)
1281 {
1282   if (gamemode!=commercial || haswolflevels)
1283     secretexit = TRUE;
1284   else
1285     secretexit = FALSE;
1286   gameaction = ga_completed;
1287 }
1288 
1289 //
1290 // G_DoCompleted
1291 //
1292 
G_DoCompleted(void)1293 void G_DoCompleted (void)
1294 {
1295   int i;
1296 
1297   gameaction = ga_nothing;
1298 
1299   for (i=0; i<MAXPLAYERS; i++)
1300     if (playeringame[i])
1301       G_PlayerFinishLevel(i);        // take away cards and stuff
1302 
1303   if (automapmode & am_active)
1304     AM_Stop();
1305 
1306   wminfo.lastmapinfo = gamemapinfo;
1307   wminfo.nextmapinfo = NULL;
1308   if (gamemapinfo)
1309   {
1310     const char *next = "";
1311     if (gamemapinfo->endpic[0])
1312     {
1313       gameaction = ga_victory;
1314       return;
1315     }
1316     if (secretexit)
1317        next = gamemapinfo->nextsecret;
1318     if (next[0] == 0)
1319        next = gamemapinfo->nextmap;
1320     if (next[0])
1321     {
1322       G_ValidateMapName(next, &wminfo.nextep, &wminfo.next);
1323       wminfo.nextep--;
1324       wminfo.next--;
1325       wminfo.didsecret = players[consoleplayer].didsecret;
1326       wminfo.partime = gamemapinfo->partime;
1327       goto frommapinfo;	// skip past the default setup.
1328     }
1329   }
1330 
1331   if (gamemode != commercial) // kilough 2/7/98
1332     switch(gamemap)
1333     {
1334       // cph - Remove ExM8 special case, so it gets summary screen displayed
1335       case 9:
1336         for (i=0 ; i<MAXPLAYERS ; i++)
1337           players[i].didsecret = TRUE;
1338         break;
1339     }
1340 
1341   wminfo.didsecret = players[consoleplayer].didsecret;
1342   wminfo.nextep = wminfo.epsd = gameepisode -1;
1343   wminfo.last = gamemap -1;
1344 
1345   // wminfo.next is 0 biased, unlike gamemap
1346   if (gamemode == commercial)
1347     {
1348       if (secretexit)
1349         switch(gamemap)
1350           {
1351           case 15:
1352             wminfo.next = 30; break;
1353           case 31:
1354             wminfo.next = 31; break;
1355           case 2:
1356             if (bfgedition)
1357                wminfo.next = 32;
1358             break;
1359           }
1360       else
1361         switch(gamemap)
1362           {
1363           case 31:
1364           case 32:
1365             wminfo.next = 15; break;
1366           case 33:
1367             wminfo.next = 2; break;
1368           default:
1369             wminfo.next = gamemap;
1370           }
1371     }
1372   else
1373     {
1374       if (secretexit)
1375         wminfo.next = 8;  // go to secret level
1376       else
1377         if (gamemap == 9)
1378           {
1379             // returning from secret level
1380             switch (gameepisode)
1381               {
1382               case 1:
1383                 wminfo.next = 3;
1384                 break;
1385               case 2:
1386                 wminfo.next = 5;
1387                 break;
1388               case 3:
1389                 wminfo.next = 6;
1390                 break;
1391               case 4:
1392                 wminfo.next = 2;
1393                 break;
1394               case 5:
1395                 wminfo.next = 6;
1396                 break;
1397               }
1398           }
1399         else
1400           wminfo.next = gamemap;          // go to next level
1401     }
1402 
1403   if ( gamemode == commercial )
1404     wminfo.partime = TICRATE*cpars[gamemap-1];
1405   else
1406     wminfo.partime = TICRATE*pars[gameepisode][gamemap];
1407 
1408 frommapinfo:
1409   wminfo.nextmapinfo = G_LookupMapinfo(wminfo.nextep+1, wminfo.next+1);
1410   wminfo.maxkills = totalkills;
1411   wminfo.maxitems = totalitems;
1412   wminfo.maxsecret = totalsecret;
1413   wminfo.maxfrags = 0;
1414   wminfo.pnum = consoleplayer;
1415 
1416   for (i=0 ; i<MAXPLAYERS ; i++)
1417     {
1418       wminfo.plyr[i].in = playeringame[i];
1419       wminfo.plyr[i].skills = players[i].killcount;
1420       wminfo.plyr[i].sitems = players[i].itemcount;
1421       wminfo.plyr[i].ssecret = players[i].secretcount;
1422       wminfo.plyr[i].stime = leveltime;
1423       memcpy (wminfo.plyr[i].frags, players[i].frags,
1424               sizeof(wminfo.plyr[i].frags));
1425     }
1426 
1427   /* cph - modified so that only whole seconds are added to the totalleveltimes
1428    *  value; so our total is compatible with the "naive" total of just adding
1429    *  the times in seconds shown for each level. Also means our total time
1430    *  will agree with Compet-n.
1431    */
1432   wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35));
1433 
1434   gamestate = GS_INTERMISSION;
1435   automapmode &= ~am_active;
1436 
1437   WI_Start (&wminfo);
1438 }
1439 
1440 //
1441 // G_WorldDone
1442 //
1443 
G_WorldDone(void)1444 void G_WorldDone (void)
1445 {
1446   gameaction = ga_worlddone;
1447 
1448   if (secretexit)
1449     players[consoleplayer].didsecret = TRUE;
1450 
1451   if (gamemapinfo)
1452   {
1453     if (gamemapinfo->intertextsecret && secretexit)
1454     {
1455       if (gamemapinfo->intertextsecret[0] != '-') // '-' means that any default intermission was cleared.
1456         F_StartFinale();
1457       return;
1458     }
1459     else if (gamemapinfo->intertext && !secretexit)
1460     {
1461       if (gamemapinfo->intertext[0] != '-') // '-' means that any default intermission was cleared.
1462         F_StartFinale();
1463       return;
1464     }
1465     else if (gamemapinfo->endpic && gamemapinfo->endpic[0] && gamemapinfo->nointermission)
1466     {
1467       // game ends without a status screen.
1468       gameaction = ga_victory;
1469       return;
1470     }
1471     // if nothing applied, use the defaults.
1472   }
1473 
1474   if (gamemode == commercial)
1475     {
1476       switch (gamemap)
1477         {
1478         case 15:
1479         case 31:
1480           if (!secretexit)
1481             break;
1482           // fall through
1483         case 6:
1484         case 11:
1485         case 20:
1486         case 30:
1487           F_StartFinale ();
1488           break;
1489         }
1490     }
1491   else if (gamemap == 8)
1492     gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff
1493 }
1494 
G_DoWorldDone(void)1495 void G_DoWorldDone (void)
1496 {
1497   idmusnum = -1;             //jff 3/17/98 allow new level's music to be loaded
1498   gamestate = GS_LEVEL;
1499   gameepisode = wminfo.nextep + 1;
1500   gamemap = wminfo.next + 1;
1501   gamemapinfo = G_LookupMapinfo(gameepisode, gamemap);
1502   G_DoLoadLevel();
1503   gameaction = ga_nothing;
1504   AM_clearMarks();           //jff 4/12/98 clear any marks on the automap
1505 }
1506 
1507 // killough 2/28/98: A ridiculously large number
1508 // of players, the most you'll ever need in a demo
1509 // or savegame. This is used to prevent problems, in
1510 // case more players in a game are supported later.
1511 
1512 #define MIN_MAXPLAYERS 32
1513 
1514 extern dbool   setsizeneeded;
1515 
1516 //CPhipps - savename variable redundant
1517 
1518 /* killough 12/98:
1519  * This function returns a signature for the current wad.
1520  * It is used to distinguish between wads, for the purposes
1521  * of savegame compatibility warnings, and options lookups.
1522  */
1523 
G_UpdateSignature(uint64_t s,const char * name)1524 static uint64_t G_UpdateSignature(uint64_t s, const char *name)
1525 {
1526    int i, lump = W_CheckNumForName(name);
1527    if (lump != -1 && (i = lump+10) < numlumps)
1528       do
1529       {
1530          int size = W_LumpLength(i);
1531          const uint8_t *p = W_CacheLumpNum(i);
1532          while (size--)
1533             s <<= 1, s += *p++;
1534          W_UnlockLumpNum(i);
1535       }
1536       while (--i > lump);
1537    return s;
1538 }
1539 
G_Signature(void)1540 static uint64_t G_Signature(void)
1541 {
1542   static uint64_t s = 0;
1543   static dbool   computed = FALSE;
1544   char name[9];
1545   int episode, map;
1546 
1547   if (!computed) {
1548    computed = TRUE;
1549    if (gamemode == commercial)
1550     for (map = haswolflevels ? 32 : 30; map; map--)
1551       sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name);
1552    else
1553     for (episode = gamemode==retail ? 4 :
1554      gamemode==shareware ? 1 : 3; episode; episode--)
1555       for (map = 9; map; map--)
1556   sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name);
1557   }
1558   return s;
1559 }
1560 
1561 //
1562 // killough 5/15/98: add forced loadgames, which allow user to override checks
1563 //
1564 
G_ForcedLoadGame(void)1565 void G_ForcedLoadGame(void)
1566 {
1567   // CPhipps - net loadgames are always forced, so we only reach here
1568   //  in single player
1569   gameaction = ga_loadgame;
1570   forced_loadgame = TRUE;
1571 }
1572 
1573 // killough 3/16/98: add slot info
1574 // killough 5/15/98: add command-line
G_LoadGame(int slot,dbool command)1575 void G_LoadGame(int slot, dbool   command)
1576 {
1577   if (!demoplayback && !command) {
1578     // CPhipps - handle savegame filename in G_DoLoadGame
1579     //         - Delay load so it can be communicated in net game
1580     //         - store info in special_event
1581     special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) |
1582       ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1583     forced_loadgame = netgame; // CPhipps - always force load netgames
1584   } else {
1585     // Do the old thing, immediate load
1586     gameaction = ga_loadgame;
1587     forced_loadgame = FALSE;
1588     savegameslot = slot;
1589     demoplayback = FALSE;
1590     // Don't stay in netgame state if loading single player save
1591     // while watching multiplayer demo
1592     netgame = FALSE;
1593   }
1594   command_loadgame = command;
1595   R_SmoothPlaying_Reset(NULL); // e6y
1596 }
1597 
1598 // killough 5/15/98:
1599 // Consistency Error when attempting to load savegame.
1600 
G_LoadGameErr(const char * msg)1601 static void G_LoadGameErr(const char *msg)
1602 {
1603   Z_Free(savebuffer);                // Free the savegame buffer
1604   M_ForcedLoadGame(msg);             // Print message asking for 'Y' to force
1605   if (command_loadgame)              // If this was a command-line -loadgame
1606     {
1607       D_StartTitle();                // Start the title screen
1608       gamestate = GS_DEMOSCREEN;     // And set the game state accordingly
1609     }
1610 }
1611 
1612 // CPhipps - size of version header
1613 #define VERSIONSIZE   16
1614 
1615 const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] =
1616 { "doom v1.2", "doom v1.666", "doom/doom2 v1.9", "ultimate doom", "final doom",
1617   "dosdoom compatibility", "tasdoom compatibility", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+",
1618   "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6",
1619   "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom"  };
1620 
1621 // comp_options_by_version removed - see G_Compatibility
1622 
1623 static uint8_t map_old_comp_levels[] =
1624 { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
1625 
1626 static const struct {
1627   int comp_level;
1628   const char* ver_printf;
1629   int version;
1630 } version_headers[] = {
1631   /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since
1632    *  the file format is unchanged. */
1633   { prboom_3_compatibility, "PrBoom %d", 210},
1634   { prboom_5_compatibility, "PrBoom %d", 211},
1635   { prboom_6_compatibility, "PrBoom %d", 212}
1636 };
1637 
1638 static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]);
1639 
1640 //
1641 // Load the game from the internal savebuffer
1642 //
G_DoLoadGameFromSaveBuffer(int length)1643 static int G_DoLoadGameFromSaveBuffer(int length)
1644 {
1645   int isok;
1646   int  i;
1647   int savegame_compatibility = -1;
1648 
1649   gameaction = ga_nothing;
1650 
1651   save_p = savebuffer + SAVESTRINGSIZE;
1652 
1653   // CPhipps - read the description field, compare with supported ones
1654   for (i=0; (size_t)i<num_version_headers; i++) {
1655     char vcheck[VERSIONSIZE];
1656     // killough 2/22/98: "proprietary" version string :-)
1657     sprintf (vcheck, version_headers[i].ver_printf, version_headers[i].version);
1658 
1659     if (!strncmp((const char*)save_p, vcheck, VERSIONSIZE)) {
1660       savegame_compatibility = version_headers[i].comp_level;
1661       i = num_version_headers;
1662     }
1663   }
1664   if (savegame_compatibility == -1) {
1665     if (forced_loadgame) {
1666       savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1;
1667     } else {
1668       return -2;
1669     }
1670   }
1671 
1672   save_p += VERSIONSIZE;
1673 
1674   // CPhipps - always check savegames even when forced,
1675   //  only print a warning if forced
1676   {  // killough 3/16/98: check lump name checksum (independent of order)
1677     uint64_t checksum = 0;
1678 
1679     checksum = G_Signature();
1680 
1681     if (memcmp(&checksum, save_p, sizeof checksum)) {
1682       if (!forced_loadgame) {
1683         return -3;
1684       } else
1685   lprintf(LO_WARN, "G_DoLoadGame: Incompatible savegame\n");
1686     }
1687     save_p += sizeof checksum;
1688    }
1689 
1690   save_p += strlen((const char*)save_p)+1;
1691 
1692   compatibility_level = (savegame_compatibility >= prboom_4_compatibility) ? *save_p : savegame_compatibility;
1693   if (savegame_compatibility < prboom_6_compatibility)
1694     compatibility_level = map_old_comp_levels[compatibility_level];
1695   save_p++;
1696 
1697   gameskill = *save_p++;
1698   gameepisode = *save_p++;
1699   gamemap = *save_p++;
1700   gamemapinfo = G_LookupMapinfo(gameepisode, gamemap);
1701 
1702   for (i=0 ; i<MAXPLAYERS ; i++)
1703     playeringame[i] = *save_p++;
1704   save_p += MIN_MAXPLAYERS-MAXPLAYERS;         // killough 2/28/98
1705 
1706   idmusnum = *save_p++;           // jff 3/17/98 restore idmus music
1707   if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte
1708 
1709   /* killough 3/1/98: Read game options
1710    * killough 11/98: move down to here
1711    */
1712   // Avoid assignment of const to non-const: add the difference
1713   // between the updated and original pointer onto the original
1714   save_p += (G_ReadOptions(save_p) - save_p);
1715 
1716   // load a base level
1717   G_InitNew (gameskill, gameepisode, gamemap);
1718 
1719   /* get the times - killough 11/98: save entire word */
1720   memcpy(&leveltime, save_p, sizeof leveltime);
1721   save_p += sizeof leveltime;
1722 
1723   /* cph - total episode time */
1724   if (compatibility_level >= prboom_2_compatibility) {
1725     memcpy(&totalleveltimes, save_p, sizeof totalleveltimes);
1726     save_p += sizeof totalleveltimes;
1727   }
1728   else totalleveltimes = 0;
1729 
1730   // killough 11/98: load revenant tracer state
1731   basetic = gametic - *save_p++;
1732 
1733   // dearchive all the modifications
1734   P_MapStart();
1735   P_UnArchivePlayers ();
1736   P_UnArchiveWorld ();
1737   P_UnArchiveThinkers ();
1738   P_UnArchiveSpecials ();
1739   P_UnArchiveRNG ();    // killough 1/18/98: load RNG information
1740   P_UnArchiveMap ();    // killough 1/22/98: load automap information
1741   P_MapEnd();
1742   R_SmoothPlaying_Reset(NULL); // e6y
1743 
1744   isok = *save_p == 0xe6;
1745   if (!isok)
1746     I_Error ("G_DoLoadGame: Bad savegame");
1747 
1748   if (setsizeneeded)
1749     R_ExecuteSetViewSize ();
1750 
1751   return isok ? 0 : -1;
1752 }
1753 
G_DoLoadGame(void)1754 void G_DoLoadGame(void)
1755 {
1756   int err;
1757   int  length;
1758   // CPhipps - do savegame filename stuff here
1759   char name[PATH_MAX+1];     // killough 3/22/98
1760 
1761   G_SaveGameName(name,sizeof(name),savegameslot, demoplayback);
1762 
1763   length = M_ReadFile(name, &savebuffer);
1764   if (length<=0)
1765     I_Error("Couldn't read file %s: %s", name, "(Unknown Error)");
1766 
1767   err = G_DoLoadGameFromSaveBuffer(length);
1768   if (err == -2) {
1769     G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
1770   }
1771 
1772   if (err == -3) {
1773     char *msg;
1774     uint64_t checksum = 0;
1775 
1776     checksum = G_Signature();
1777     msg      = malloc(strlen((const char*)save_p + sizeof checksum) + 128);
1778     strcpy(msg,"Incompatible Savegame!!!\n");
1779     if (save_p[sizeof checksum])
1780       strcat(strcat(msg,"Wads expected:\n\n"), (const char*)save_p + sizeof checksum);
1781     strcat(msg, "\nAre you sure?");
1782     G_LoadGameErr(msg);
1783     free(msg);
1784   }
1785 
1786   // done
1787   Z_Free (savebuffer);
1788 }
1789 
G_DoLoadGameFromBuffer(void * data,size_t length)1790 bool G_DoLoadGameFromBuffer(void *data, size_t length)
1791 {
1792   int err;
1793   savebuffer = data;
1794 
1795   err = G_DoLoadGameFromSaveBuffer(length);
1796 
1797   // done
1798   savebuffer = NULL;
1799 
1800   return err == 0;
1801 }
1802 
1803 //
1804 // G_SaveGame
1805 // Called by the menu task.
1806 // Description is a 24 byte text string
1807 //
1808 
G_SaveGame(int slot,char * description)1809 void G_SaveGame(int slot, char *description)
1810 {
1811   strcpy(savedescription, description);
1812   if (demoplayback) {
1813     /* cph - We're doing a user-initiated save game while a demo is
1814      * running so, go outside normal mechanisms
1815      */
1816     savegameslot = slot;
1817     G_DoSaveGame(TRUE);
1818   }
1819   // CPhipps - store info in special_event
1820   special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) |
1821     ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1822 #ifdef HAVE_NET
1823   D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription);
1824 #endif
1825 }
1826 
1827 // Check for overrun and realloc if necessary -- Lee Killough 1/22/98
1828 void (CheckSaveGame)(size_t size, const char* file, int line)
1829 {
1830   size_t pos = save_p - savebuffer;
1831 
1832   size += 1024;  // breathing room
1833   if (pos+size > savegamesize) {
1834     savegamesize += (size+1023) & ~1023;
1835     if (savestaticbuffer) {
1836       savebuffer = malloc(savegamesize);
1837       savestaticbuffer = FALSE;
1838     }
1839     else
1840       savebuffer = realloc(savebuffer, savegamesize);
1841     save_p = savebuffer + pos;
1842   }
1843 }
1844 
1845 /* killough 3/22/98: form savegame name in one location
1846  * (previously code was scattered around in multiple places)
1847  * cph - Avoid possible buffer overflow problems by passing
1848  * size to this function and using snprintf */
1849 
G_SaveGameName(char * name,size_t size,int slot,dbool demoplayback)1850 void G_SaveGameName(char *name, size_t size, int slot, dbool   demoplayback)
1851 {
1852   const char* sgn = demoplayback ? "demosav" : savegamename;
1853 #ifdef _WIN32
1854   char slash = '\\';
1855 #else
1856   char slash = '/';
1857 #endif
1858   snprintf (name, size, "%s%c%s%d.dsg", basesavegame, slash, sgn, slot);
1859 }
1860 
1861 
1862 //
1863 // Save the game state into the internal savebuffer
1864 // It'll only reallocate the savebuffer if necessary
1865 //
G_DoSaveGameToSaveBuffer()1866 static int G_DoSaveGameToSaveBuffer() {
1867   char name2[VERSIONSIZE];
1868   char *description;
1869   int  length, i;
1870 
1871   description = savedescription;
1872 
1873   if(!savebuffer || savegamesize < SAVEGAMESIZE) {
1874     savegamesize = SAVEGAMESIZE;
1875     savebuffer = malloc(savegamesize);
1876   }
1877   save_p = savebuffer;
1878 
1879   CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint64_t));
1880   memcpy (save_p, description, SAVESTRINGSIZE);
1881   save_p += SAVESTRINGSIZE;
1882   memset (name2,0,sizeof(name2));
1883 
1884   // CPhipps - scan for the version header
1885   for (i=0; (size_t)i<num_version_headers; i++)
1886     if (version_headers[i].comp_level == best_compatibility) {
1887       // killough 2/22/98: "proprietary" version string :-)
1888       sprintf (name2,version_headers[i].ver_printf,version_headers[i].version);
1889       memcpy (save_p, name2, VERSIONSIZE);
1890       i = num_version_headers+1;
1891     }
1892 
1893   save_p += VERSIONSIZE;
1894 
1895   { /* killough 3/16/98, 12/98: store lump name checksum */
1896     uint64_t checksum = G_Signature();
1897     memcpy(save_p, &checksum, sizeof checksum);
1898     save_p += sizeof checksum;
1899   }
1900 
1901   // killough 3/16/98: store pwad filenames in savegame
1902   {
1903     // CPhipps - changed for new wadfiles handling
1904     size_t i;
1905     for (i = 0; i<numwadfiles; i++)
1906       {
1907         const char *const w = wadfiles[i].name;
1908         CheckSaveGame(strlen(w)+2);
1909         strcpy((char*)save_p, w);
1910         save_p += strlen((const char*)save_p);
1911         *save_p++ = '\n';
1912       }
1913     *save_p++ = 0;
1914   }
1915 
1916   CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+14);
1917 
1918   *save_p++ = compatibility_level;
1919 
1920   *save_p++ = gameskill;
1921   *save_p++ = gameepisode;
1922   *save_p++ = gamemap;
1923 
1924   for (i=0 ; i<MAXPLAYERS ; i++)
1925     *save_p++ = playeringame[i];
1926 
1927   for (;i<MIN_MAXPLAYERS;i++)         // killough 2/28/98
1928     *save_p++ = 0;
1929 
1930   *save_p++ = idmusnum;               // jff 3/17/98 save idmus state
1931 
1932   save_p = G_WriteOptions(save_p);    // killough 3/1/98: save game options
1933 
1934   /* cph - FIXME - endianness? */
1935   /* killough 11/98: save entire word */
1936   memcpy(save_p, &leveltime, sizeof leveltime);
1937   save_p += sizeof leveltime;
1938 
1939   /* cph - total episode time */
1940   if (compatibility_level >= prboom_2_compatibility) {
1941     memcpy(save_p, &totalleveltimes, sizeof totalleveltimes);
1942     save_p += sizeof totalleveltimes;
1943   }
1944   else totalleveltimes = 0;
1945 
1946   // killough 11/98: save revenant tracer state
1947   *save_p++ = (gametic-basetic) & 255;
1948 
1949   // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
1950   Z_CheckHeap();
1951   P_ArchivePlayers();
1952   Z_CheckHeap();
1953 
1954   // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the
1955   // indices can be used by P_ArchiveWorld when the sectors are saved.
1956   // This is so we can save the index of the mobj_t of the thinker that
1957   // caused a sound, referenced by sector_t->soundtarget.
1958   P_ThinkerToIndex();
1959 
1960   P_ArchiveWorld();
1961   Z_CheckHeap();
1962   P_ArchiveThinkers();
1963 
1964   // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply
1965   // for symmetry with the P_ThinkerToIndex call above.
1966 
1967   P_IndexToThinker();
1968 
1969   Z_CheckHeap();
1970   P_ArchiveSpecials();
1971   P_ArchiveRNG();    // killough 1/18/98: save RNG information
1972   Z_CheckHeap();
1973   P_ArchiveMap();    // killough 1/22/98: save automap information
1974 
1975   *save_p++ = 0xe6;   // consistancy marker
1976 
1977   length = save_p - savebuffer;
1978 
1979   Z_CheckHeap();
1980 
1981   return length;
1982 }
1983 
G_DoSaveGame(dbool menu)1984 static void G_DoSaveGame (dbool   menu)
1985 {
1986   int length;
1987   char name[PATH_MAX+1];
1988 
1989   gameaction = ga_nothing; // cph - cancel savegame at top of this function,
1990     // in case later problems cause a premature exit
1991 
1992   G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu);
1993 
1994   length = G_DoSaveGameToSaveBuffer();
1995 
1996   doom_printf( "%s", M_WriteFile(name, savebuffer, length)
1997          ? s_GGSAVED /* Ty - externalised */
1998          : "Game save failed!"); // CPhipps - not externalised
1999 
2000   free(savebuffer);  // killough
2001   savebuffer = save_p = NULL;
2002 
2003   savedescription[0] = 0;
2004 }
2005 
G_DoSaveGameToBuffer(void * buf,size_t size)2006 bool G_DoSaveGameToBuffer(void *buf, size_t size) {
2007   int length, ok;
2008   char description_saved[SAVEDESCLEN];
2009   // If no game is loaded we can't save
2010   if (thinkercap.next == NULL)
2011     return false;
2012 
2013   memcpy(description_saved, savedescription, SAVEDESCLEN);
2014   strcpy(savedescription, "BUFFER");
2015 
2016   // set savebuffer and its size to attempt to save directly into the destination buffer
2017   savebuffer = buf;
2018   savegamesize = size;
2019   savestaticbuffer = TRUE;
2020 
2021   length = G_DoSaveGameToSaveBuffer();
2022 
2023   ok     = ((size_t) length <= size);
2024 
2025   if (ok && size != (size_t)length) {
2026     // initialize the rest with zeroes
2027     memset((char*)buf+length, 0, size - length);
2028   } else if (savebuffer != NULL && !savestaticbuffer) {
2029     // a different savebuffer was allocated, free it
2030     free(savebuffer);
2031     I_Error("G_DoSaveGameToBuffer: too much data by %d bytes", (int) (length - size));
2032   }
2033   savestaticbuffer = FALSE;
2034   savebuffer = save_p = NULL;
2035   memcpy(savedescription, description_saved, SAVEDESCLEN);
2036 
2037   return ok;
2038 }
2039 
2040 static skill_t d_skill;
2041 static int     d_episode;
2042 static int     d_map;
2043 
G_DeferedInitNew(skill_t skill,int episode,int map)2044 void G_DeferedInitNew(skill_t skill, int episode, int map)
2045 {
2046   d_skill = skill;
2047   d_episode = episode;
2048   d_map = map;
2049   gameaction = ga_newgame;
2050 }
2051 
2052 /* cph -
2053  * G_Compatibility
2054  *
2055  * Initialises the comp[] array based on the compatibility_level
2056  * For reference, MBF did:
2057  * for (i=0; i < COMP_TOTAL; i++)
2058  *   comp[i] = compatibility;
2059  *
2060  * Instead, we have a lookup table showing at what version a fix was
2061  *  introduced, and made optional (replaces comp_options_by_version)
2062  */
2063 
G_Compatibility(void)2064 void G_Compatibility(void)
2065 {
2066   static const struct {
2067     complevel_t fix; // level at which fix/change was introduced
2068     complevel_t opt; // level at which fix/change was made optional
2069   } levels[] = {
2070     // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only
2071     { mbf_compatibility, mbf_compatibility },
2072     // comp_dropoff - MBF encourages things to drop off of overhangs
2073     { mbf_compatibility, mbf_compatibility },
2074     // comp_vile - original Doom archville bugs like ghosts
2075     { boom_compatibility, mbf_compatibility },
2076     // comp_pain - original Doom limits Pain Elementals from spawning too many skulls
2077     { boom_compatibility, mbf_compatibility },
2078     // comp_skull - original Doom let skulls be spit through walls by Pain Elementals
2079     { boom_compatibility, mbf_compatibility },
2080     // comp_blazing - original Doom duplicated blazing door sound
2081     { boom_compatibility, mbf_compatibility },
2082     // e6y: "Tagged doors don't trigger special lighting" handled wrong
2083     // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
2084     // comp_doorlight - MBF made door lighting changes more gradual
2085     { boom_compatibility, mbf_compatibility },
2086     // comp_model - improvements to the game physics
2087     { boom_compatibility, mbf_compatibility },
2088     // comp_god - fixes to God mode
2089     { boom_compatibility, mbf_compatibility },
2090     // comp_falloff - MBF encourages things to drop off of overhangs
2091     { mbf_compatibility, mbf_compatibility },
2092     // comp_floors - fixes for moving floors bugs
2093     { boom_compatibility_compatibility, mbf_compatibility },
2094     // comp_skymap
2095     { boom_compatibility, mbf_compatibility },
2096     // comp_pursuit - MBF AI change, limited pursuit?
2097     { mbf_compatibility, mbf_compatibility },
2098     // comp_doorstuck - monsters stuck in doors fix
2099     { boom_202_compatibility, mbf_compatibility },
2100     // comp_staylift - MBF AI change, monsters try to stay on lifts
2101     { mbf_compatibility, mbf_compatibility },
2102     // comp_zombie - prevent dead players triggering stuff
2103     { lxdoom_1_compatibility, mbf_compatibility },
2104     // comp_stairs - see p_floor.c
2105     { boom_202_compatibility, mbf_compatibility },
2106     // comp_infcheat - FIXME
2107     { mbf_compatibility, mbf_compatibility },
2108     // comp_zerotags - allow zero tags in wads */
2109     { boom_compatibility, mbf_compatibility },
2110     // comp_moveblock - enables keygrab and mancubi shots going thru walls
2111     { lxdoom_1_compatibility, prboom_2_compatibility },
2112     // comp_respawn - objects which aren't on the map at game start respawn at (0,0)
2113     { prboom_2_compatibility, prboom_2_compatibility },
2114     // comp_sound - see s_sound.c
2115     { boom_compatibility_compatibility, prboom_3_compatibility },
2116     // comp_666 - enables tag 666 in non-ExM8 levels
2117     { ultdoom_compatibility, prboom_4_compatibility },
2118     // comp_soul - enables lost souls bouncing (see P_ZMovement)
2119     { prboom_4_compatibility, prboom_4_compatibility },
2120     // comp_maskedanim - 2s mid textures don't animate
2121     { doom_1666_compatibility, prboom_4_compatibility },
2122   };
2123   unsigned i;
2124 
2125   if (sizeof(levels)/sizeof(*levels) != COMP_NUM)
2126     I_Error("G_Compatibility: consistency error");
2127 
2128   for (i = 0; i < sizeof(levels)/sizeof(*levels); i++)
2129     if (compatibility_level < levels[i].opt)
2130       comp[i] = (compatibility_level < levels[i].fix);
2131 
2132   if (!mbf_features) {
2133     monster_infighting = 1;
2134     monster_backing = 0;
2135     monster_avoid_hazards = 0;
2136     monster_friction = 0;
2137     help_friends = 0;
2138 
2139     monkeys = 0;
2140   }
2141 
2142   if (demo_compatibility) {
2143     allow_pushers = 0;
2144     variable_friction = 0;
2145     monsters_remember = 0;
2146     weapon_recoil = 0;
2147     player_bobbing = 1;
2148   }
2149 }
2150 
2151 // killough 3/1/98: function to reload all the default parameter
2152 // settings before a new game begins
2153 
G_ReloadDefaults(void)2154 void G_ReloadDefaults(void)
2155 {
2156   // killough 3/1/98: Initialize options based on config file
2157   // (allows functions above to load different values for demos
2158   // and savegames without messing up defaults).
2159 
2160   weapon_recoil = default_weapon_recoil;    // weapon recoil
2161 
2162   player_bobbing = default_player_bobbing;  // whether player bobs or not
2163 
2164   /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */
2165   variable_friction = default_variable_friction;
2166   allow_pushers     = default_allow_pushers;
2167 
2168 
2169   monsters_remember = default_monsters_remember;   // remember former enemies
2170 
2171   monster_infighting = default_monster_infighting; // killough 7/19/98
2172 
2173 
2174   distfriend = default_distfriend;                 // killough 8/8/98
2175 
2176   monster_backing = default_monster_backing;     // killough 9/8/98
2177 
2178   monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98
2179 
2180   monster_friction = default_monster_friction;     // killough 10/98
2181 
2182   help_friends = default_help_friends;             // killough 9/9/98
2183 
2184   monkeys = default_monkeys;
2185 
2186   // jff 1/24/98 reset play mode to command line spec'd version
2187   // killough 3/1/98: moved to here
2188   respawnparm = clrespawnparm;
2189   fastparm = clfastparm;
2190   nomonsters = clnomonsters;
2191 
2192   //jff 3/24/98 set startskill from defaultskill in config file, unless
2193   // it has already been set by a -skill parameter
2194   if (startskill==sk_none)
2195     startskill = (skill_t)(defaultskill-1);
2196 
2197   demoplayback = FALSE;
2198   netdemo = FALSE;
2199 
2200   // killough 2/21/98:
2201   memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1));
2202 
2203   consoleplayer = 0;
2204 
2205   compatibility_level = default_compatibility_level;
2206   {
2207     int i = M_CheckParm("-complevel");
2208     if (i && (1+i) < myargc) {
2209       int l = atoi(myargv[i+1]);;
2210       if (l >= -1) compatibility_level = l;
2211     }
2212   }
2213   if (compatibility_level == (unsigned) -1)
2214     compatibility_level = best_compatibility;
2215 
2216   if (mbf_features)
2217     memcpy(comp, default_comp, sizeof comp);
2218   G_Compatibility();
2219 
2220   // killough 3/31/98, 4/5/98: demo sync insurance
2221   demo_insurance = default_demo_insurance == 1;
2222 
2223   rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
2224 }
2225 
G_DoNewGame(void)2226 void G_DoNewGame (void)
2227 {
2228   G_ReloadDefaults();            // killough 3/1/98
2229   netgame = FALSE;               // killough 3/29/98
2230   deathmatch = FALSE;
2231   G_InitNew (d_skill, d_episode, d_map);
2232   gameaction = ga_nothing;
2233 
2234   //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
2235   ST_Start();
2236 }
2237 
2238 // killough 4/10/98: New function to fix bug which caused Doom
2239 // lockups when idclev was used in conjunction with -fast.
2240 
G_SetFastParms(int fast_pending)2241 void G_SetFastParms(int fast_pending)
2242 {
2243   static int fast = 0;            // remembers fast state
2244   int i;
2245   if (fast != fast_pending) {     /* only change if necessary */
2246     if ((fast = fast_pending))
2247       {
2248         for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2249           if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98
2250             states[i].tics >>= 1;  // don't change 1->0 since it causes cycles
2251         mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
2252         mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
2253         mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
2254       }
2255     else
2256       {
2257         for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2258           states[i].tics <<= 1;
2259         mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
2260         mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
2261         mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
2262       }
2263   }
2264 }
2265 
2266 // Since input is read on each frame, the speed of
2267 // turns needs to be scaled. This is called whenever
2268 // the framerate changes.
G_ScaleMovementToFramerate(void)2269 void G_ScaleMovementToFramerate (void)
2270 {
2271   angleturn[0] = (320  * TICRATE) / tic_vars.fps;
2272   angleturn[1] = (640 * TICRATE) / tic_vars.fps;
2273   angleturn[2] = (160  * TICRATE) / tic_vars.fps;
2274 }
2275 
2276 //
2277 //
2278 //
G_LookupMapinfo(int episode,int map)2279 mapentry_t *G_LookupMapinfo(int episode, int map)
2280 {
2281   char lumpname[9];
2282   unsigned i;
2283   if (gamemode == commercial) snprintf(lumpname, 9, "MAP%02d", map);
2284   else snprintf(lumpname, 9, "E%dM%d", episode, map);
2285   for (i = 0; i < U_mapinfo.mapcount; i++)
2286   {
2287     if (!stricmp(lumpname, U_mapinfo.maps[i].mapname))
2288     {
2289       return &U_mapinfo.maps[i];
2290     }
2291   }
2292   return NULL;
2293 }
2294 
2295 //
2296 //
2297 //
G_LookupMapinfoByName(const char * lumpname)2298 mapentry_t *G_LookupMapinfoByName(const char *lumpname)
2299 {
2300   unsigned i;
2301   for (i = 0; i < U_mapinfo.mapcount; i++)
2302   {
2303     if (!stricmp(lumpname, U_mapinfo.maps[i].mapname))
2304     {
2305       return &U_mapinfo.maps[i];
2306     }
2307   }
2308   return NULL;
2309 }
2310 
2311 
G_ValidateMapName(const char * mapname,int * pEpi,int * pMap)2312 int G_ValidateMapName(const char *mapname, int *pEpi, int *pMap)
2313 {
2314   // Check if the given map name can be expressed as a gameepisode/gamemap pair and be reconstructed from it.
2315   char lumpname[9], mapuname[9];
2316   int epi = -1, map = -1;
2317 
2318   if (strlen(mapname) > 8) return 0;
2319   strncpy(mapuname, mapname, 8);
2320   mapuname[8] = 0;
2321   M_Strupr(mapuname);
2322 
2323 
2324   if (sscanf(mapuname, "MAP%d", &map) == 1)
2325     snprintf(lumpname, 9, "MAP%02d", map);
2326   else if (sscanf(mapuname, "E%dM%d", &epi, &map) == 2)
2327     snprintf(lumpname, 9, "E%dM%d", epi, map);
2328   else return 0;
2329 
2330   if (pEpi) *pEpi = epi;
2331   if (pMap) *pMap = map;
2332   return !strcmp(mapuname, lumpname);
2333 }
2334 
2335 
2336 //
2337 // G_InitNew
2338 // Can be called by the startup code or the menu task,
2339 // consoleplayer, displayplayer, playeringame[] should be set.
2340 //
2341 
G_InitNew(skill_t skill,int episode,int map)2342 void G_InitNew(skill_t skill, int episode, int map)
2343 {
2344   int i;
2345 
2346   if (paused)
2347     {
2348       paused = FALSE;
2349       S_ResumeSound();
2350     }
2351 
2352   if (skill > sk_nightmare)
2353     skill = sk_nightmare;
2354 
2355   if (episode < 1)
2356     episode = 1;
2357 
2358   if (gamemode == retail)
2359     {
2360       if (episode > MAX_EPISODE_NUM)
2361         episode = MAX_EPISODE_NUM;
2362     }
2363   else
2364     if (gamemode == shareware)
2365       {
2366         if (episode > 1)
2367           episode = 1; // only start episode 1 on shareware
2368       }
2369     else
2370       if (episode > 3)
2371         episode = 3;
2372 
2373   if (map < 1)
2374     map = 1;
2375   if (map > 9 && gamemode != commercial)
2376     map = 9;
2377 
2378   G_SetFastParms(fastparm || skill == sk_nightmare);  // killough 4/10/98
2379 
2380   M_ClearRandom();
2381 
2382   respawnmonsters = skill == sk_nightmare || respawnparm;
2383 
2384   // force players to be initialized upon first level load
2385   for (i=0 ; i<MAXPLAYERS ; i++)
2386     players[i].playerstate = PST_REBORN;
2387 
2388   usergame = TRUE;                // will be set FALSE if a demo
2389   paused = FALSE;
2390   automapmode &= ~am_active;
2391   gameepisode = episode;
2392   gamemap = map;
2393   gameskill = skill;
2394   gamemapinfo = G_LookupMapinfo(gameepisode, gamemap);
2395 
2396   totalleveltimes = 0; // cph
2397 
2398   //jff 4/16/98 force marks on automap cleared every new level start
2399   AM_clearMarks();
2400 
2401   G_DoLoadLevel ();
2402 }
2403 
2404 //
2405 // DEMO RECORDING
2406 //
2407 
2408 #define DEMOMARKER    0x80
2409 
G_ReadDemoTiccmd(ticcmd_t * cmd)2410 void G_ReadDemoTiccmd (ticcmd_t* cmd)
2411 {
2412   unsigned char at = 0; // e6y: tasdoom stuff
2413 
2414   if (*demo_p == DEMOMARKER)
2415     G_CheckDemoStatus();      // end of demo data stream
2416   else if (demoplayback && demo_p + (longtics?5:4) > demobuffer + demolength)
2417   {
2418     lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n");
2419     G_CheckDemoStatus();
2420   }
2421   else
2422   {
2423     cmd->forwardmove = ((signed char)*demo_p++);
2424     cmd->sidemove = ((signed char)*demo_p++);
2425     if (!longtics) {
2426       cmd->angleturn = ((unsigned char)(at = *demo_p++))<<8;
2427     } else {
2428       unsigned int lowbyte = (unsigned char)*demo_p++;
2429       cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte;
2430     }
2431     cmd->buttons = (unsigned char)*demo_p++;
2432     // e6y: ability to play tasdoom demos directly
2433     if (compatibility_level == tasdoom_compatibility)
2434     {
2435       signed char k = cmd->forwardmove;
2436       cmd->forwardmove = cmd->sidemove;
2437       cmd->sidemove = (signed char)at;
2438       cmd->angleturn = ((unsigned char)cmd->buttons)<<8;
2439       cmd->buttons = (uint8_t)k;
2440     }
2441   }
2442 }
2443 
2444 // These functions are used to read and write game-specific options in demos
2445 // and savegames so that demo sync is preserved and savegame restoration is
2446 // complete. Not all options (for example "compatibility"), however, should
2447 // be loaded and saved here. It is extremely important to use the same
2448 // positions as before for the variables, so if one becomes obsolete, the
2449 // byte(s) should still be skipped over or padded with 0's.
2450 // Lee Killough 3/1/98
2451 
2452 extern int forceOldBsp;
2453 
G_WriteOptions(uint8_t * demo_p)2454 uint8_t *G_WriteOptions(uint8_t *demo_p)
2455 {
2456   uint8_t *target = demo_p + GAME_OPTION_SIZE;
2457 
2458   *demo_p++ = monsters_remember;  // part of monster AI
2459 
2460   *demo_p++ = variable_friction;  // ice & mud
2461 
2462   *demo_p++ = weapon_recoil;      // weapon recoil
2463 
2464   *demo_p++ = allow_pushers;      // MT_PUSH Things
2465 
2466   *demo_p++ = 0;
2467 
2468   *demo_p++ = player_bobbing;  // whether player bobs or not
2469 
2470   // killough 3/6/98: add parameters to savegame, move around some in demos
2471   *demo_p++ = respawnparm;
2472   *demo_p++ = fastparm;
2473   *demo_p++ = nomonsters;
2474 
2475   *demo_p++ = demo_insurance;        // killough 3/31/98
2476 
2477   // killough 3/26/98: Added rngseed. 3/31/98: moved here
2478   *demo_p++ = (uint8_t)((rngseed >> 24) & 0xff);
2479   *demo_p++ = (uint8_t)((rngseed >> 16) & 0xff);
2480   *demo_p++ = (uint8_t)((rngseed >>  8) & 0xff);
2481   *demo_p++ = (uint8_t)( rngseed        & 0xff);
2482 
2483   // Options new to v2.03 begin here
2484 
2485   *demo_p++ = monster_infighting;   // killough 7/19/98
2486 
2487   *demo_p++ = 0;
2488 
2489   *demo_p++ = 0;
2490   *demo_p++ = 0;
2491 
2492   *demo_p++ = (distfriend >> 8) & 0xff;  // killough 8/8/98
2493   *demo_p++ =  distfriend       & 0xff;  // killough 8/8/98
2494 
2495   *demo_p++ = monster_backing;         // killough 9/8/98
2496 
2497   *demo_p++ = monster_avoid_hazards;    // killough 9/9/98
2498 
2499   *demo_p++ = monster_friction;         // killough 10/98
2500 
2501   *demo_p++ = help_friends;             // killough 9/9/98
2502 
2503   *demo_p++ = 0;
2504 
2505   *demo_p++ = monkeys;
2506 
2507   {   // killough 10/98: a compatibility vector now
2508     int i;
2509     for (i=0; i < COMP_TOTAL; i++)
2510       *demo_p++ = comp[i] != 0;
2511   }
2512 
2513   *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20
2514 
2515   //----------------
2516   // Padding at end
2517   //----------------
2518   while (demo_p < target)
2519     *demo_p++ = 0;
2520 
2521   if (demo_p != target)
2522     I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small");
2523 
2524   return target;
2525 }
2526 
2527 /* Same, but read instead of write
2528  * cph - const byte*'s
2529  */
2530 
G_ReadOptions(const uint8_t * demo_p)2531 const uint8_t *G_ReadOptions(const uint8_t *demo_p)
2532 {
2533   const uint8_t *target = demo_p + GAME_OPTION_SIZE;
2534 
2535   monsters_remember = *demo_p++;
2536 
2537   variable_friction = *demo_p;  // ice & mud
2538   demo_p++;
2539 
2540   weapon_recoil = *demo_p;       // weapon recoil
2541   demo_p++;
2542 
2543   allow_pushers = *demo_p;      // MT_PUSH Things
2544   demo_p++;
2545 
2546   demo_p++;
2547 
2548   player_bobbing = *demo_p;     // whether player bobs or not
2549   demo_p++;
2550 
2551   // killough 3/6/98: add parameters to savegame, move from demo
2552   respawnparm = *demo_p++;
2553   fastparm = *demo_p++;
2554   nomonsters = *demo_p++;
2555 
2556   demo_insurance = *demo_p++;              // killough 3/31/98
2557 
2558   // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here
2559 
2560   rngseed  = *demo_p++ & 0xff;
2561   rngseed <<= 8;
2562   rngseed += *demo_p++ & 0xff;
2563   rngseed <<= 8;
2564   rngseed += *demo_p++ & 0xff;
2565   rngseed <<= 8;
2566   rngseed += *demo_p++ & 0xff;
2567 
2568   // Options new to v2.03
2569   if (mbf_features)
2570     {
2571       monster_infighting = *demo_p++;   // killough 7/19/98
2572 
2573       demo_p++;
2574 
2575       demo_p += 2;
2576 
2577       distfriend = *demo_p++ << 8;      // killough 8/8/98
2578       distfriend+= *demo_p++;
2579 
2580       monster_backing = *demo_p++;     // killough 9/8/98
2581 
2582       monster_avoid_hazards = *demo_p++; // killough 9/9/98
2583 
2584       monster_friction = *demo_p++;      // killough 10/98
2585 
2586       help_friends = *demo_p++;          // killough 9/9/98
2587 
2588       demo_p++;
2589 
2590       monkeys = *demo_p++;
2591 
2592       {   // killough 10/98: a compatibility vector now
2593   int i;
2594   for (i=0; i < COMP_TOTAL; i++)
2595     comp[i] = *demo_p++;
2596       }
2597 
2598       forceOldBsp = *demo_p++; // cph 2002/07/20
2599     }
2600   else  /* defaults for versions <= 2.02 */
2601     {
2602       /* G_Compatibility will set these */
2603     }
2604 
2605   G_Compatibility();
2606   return target;
2607 }
2608 
2609 //
2610 // G_PlayDemo
2611 //
2612 
2613 static const char *defdemoname;
2614 
G_DeferedPlayDemo(const char * name)2615 void G_DeferedPlayDemo (const char* name)
2616 {
2617   defdemoname = name;
2618   gameaction = ga_playdemo;
2619 }
2620 
2621 static int demolumpnum = -1;
2622 
G_GetOriginalDoomCompatLevel(int ver)2623 static int G_GetOriginalDoomCompatLevel(int ver)
2624 {
2625   {
2626     int lev;
2627     int i = M_CheckParm("-complevel");
2628     if (i && (i+1 < myargc))
2629     {
2630       lev = atoi(myargv[i+1]);
2631       if (lev>=0)
2632         return lev;
2633     }
2634   }
2635   if (ver < 107) return doom_1666_compatibility;
2636   if (gamemode == retail) return ultdoom_compatibility;
2637   if (gamemission >= pack_tnt) return finaldoom_compatibility;
2638   return doom2_19_compatibility;
2639 }
2640 
2641 //e6y: Check for overrun
CheckForOverrun(const uint8_t * start_p,const uint8_t * current_p,size_t maxsize,size_t size,dbool failonerror)2642 static dbool   CheckForOverrun(const uint8_t *start_p, const uint8_t *current_p, size_t maxsize, size_t size, dbool   failonerror)
2643 {
2644   size_t pos = current_p - start_p;
2645   if (pos + size > maxsize)
2646   {
2647     if (failonerror)
2648       I_Error("G_ReadDemoHeader: wrong demo header\n");
2649     else
2650       return TRUE;
2651   }
2652   return FALSE;
2653 }
2654 
G_ReadDemoHeader(const uint8_t * demo_p,size_t size,dbool failonerror)2655 static const uint8_t* G_ReadDemoHeader(const uint8_t *demo_p, size_t size, dbool   failonerror)
2656 {
2657    skill_t skill;
2658    int i, episode, map;
2659 
2660    // e6y
2661    // The local variable should be used instead of demobuffer,
2662    // because demobuffer can be uninitialized
2663    const uint8_t *header_p = demo_p;
2664 
2665    const uint8_t *option_p = NULL;      /* killough 11/98 */
2666 
2667    (void)option_p;
2668 
2669    basetic = gametic;  // killough 9/29/98
2670 
2671    // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
2672    // Old demos turn on demo_compatibility => compatibility; new demos load
2673    // compatibility flag, and other flags as well, as a part of the demo.
2674 
2675    //e6y: check for overrun
2676    if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2677       return NULL;
2678 
2679    demover = *demo_p++;
2680    longtics = 0;
2681 
2682    if (demover == 255) // UMAPINFO flag set
2683    {
2684      // Uses UMAPINFO. The real version will be in the second byte.
2685      // This prepended 255 is here to prevent non-UMAPINFO ports from recognizing the demo.
2686      demover = *demo_p++;
2687      if (!U_mapinfo.mapcount)
2688        I_Error("UMAPINFO not loaded but trying to play a demo recorded with it");
2689    }
2690    else if (U_mapinfo.mapcount)
2691      I_Error("UMAPINFO loaded but trying to play a demo recorded without it");
2692 
2693    // e6y
2694    // Handling of unrecognized demo formats
2695    // Versions up to 1.2 use a 7-byte header - first byte is a skill level.
2696    // Versions after 1.2 use a 13-byte header - first byte is a demoversion.
2697    // BOOM's demoversion starts from 200
2698    if (!((demover >=   0  && demover <=   4) ||
2699             (demover >= 104  && demover <= 111) ||
2700             (demover >= 200  && demover <= 214)))
2701    {
2702       I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover);
2703    }
2704 
2705    if (demover < 200)     // Autodetect old demos
2706    {
2707       if (demover >= 111) longtics = 1;
2708 
2709       // killough 3/2/98: force these variables to be 0 in demo_compatibility
2710 
2711       variable_friction = 0;
2712 
2713       weapon_recoil = 0;
2714 
2715       allow_pushers = 0;
2716 
2717       monster_infighting = 1;           // killough 7/19/98
2718 
2719       monster_backing = 0;              // killough 9/8/98
2720 
2721       monster_avoid_hazards = 0;        // killough 9/9/98
2722 
2723       monster_friction = 0;             // killough 10/98
2724       help_friends = 0;                 // killough 9/9/98
2725       monkeys = 0;
2726 
2727       // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm,
2728       // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions())
2729 
2730       if ((skill=demover) >= 100)         // For demos from versions >= 1.4
2731       {
2732          //e6y: check for overrun
2733          if (CheckForOverrun(header_p, demo_p, size, 8, failonerror))
2734             return NULL;
2735 
2736          compatibility_level = G_GetOriginalDoomCompatLevel(demover);
2737          skill = *demo_p++;
2738          episode = *demo_p++;
2739          map = *demo_p++;
2740          deathmatch = *demo_p++;
2741          respawnparm = *demo_p++;
2742          fastparm = *demo_p++;
2743          nomonsters = *demo_p++;
2744          consoleplayer = *demo_p++;
2745       }
2746       else
2747       {
2748          //e6y: check for overrun
2749          if (CheckForOverrun(header_p, demo_p, size, 2, failonerror))
2750             return NULL;
2751 
2752          compatibility_level = doom_12_compatibility;
2753          episode = *demo_p++;
2754          map = *demo_p++;
2755          deathmatch = respawnparm = fastparm =
2756             nomonsters = consoleplayer = 0;
2757       }
2758       G_Compatibility();
2759    }
2760    else    // new versions of demos
2761    {
2762       demo_p += 6;               // skip signature;
2763       switch (demover) {
2764          case 200: /* BOOM */
2765          case 201:
2766             //e6y: check for overrun
2767             if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2768                return NULL;
2769 
2770             if (!*demo_p++)
2771                compatibility_level = boom_201_compatibility;
2772             else
2773                compatibility_level = boom_compatibility_compatibility;
2774             break;
2775          case 202:
2776             //e6y: check for overrun
2777             if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
2778                return NULL;
2779 
2780             if (!*demo_p++)
2781                compatibility_level = boom_202_compatibility;
2782             else
2783                compatibility_level = boom_compatibility_compatibility;
2784             break;
2785          case 203:
2786             /* LxDoom or MBF - determine from signature
2787              * cph - load compatibility level */
2788             switch (*(header_p + 2)) {
2789                case 'B': /* LxDoom */
2790                   /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */
2791                   compatibility_level = lxdoom_1_compatibility;
2792                   break;
2793                case 'M':
2794                   compatibility_level = mbf_compatibility;
2795                   demo_p++;
2796                   break;
2797             }
2798             break;
2799          case 210:
2800             compatibility_level = prboom_2_compatibility;
2801             demo_p++;
2802             break;
2803          case 211:
2804             compatibility_level = prboom_3_compatibility;
2805             demo_p++;
2806             break;
2807          case 212:
2808             compatibility_level = prboom_4_compatibility;
2809             demo_p++;
2810             break;
2811          case 213:
2812             compatibility_level = prboom_5_compatibility;
2813             demo_p++;
2814             break;
2815          case 214:
2816             compatibility_level = prboom_6_compatibility;
2817             longtics = 1;
2818             demo_p++;
2819             break;
2820       }
2821       //e6y: check for overrun
2822       if (CheckForOverrun(header_p, demo_p, size, 5, failonerror))
2823          return NULL;
2824 
2825       skill = *demo_p++;
2826       episode = *demo_p++;
2827       map = *demo_p++;
2828       deathmatch = *demo_p++;
2829       consoleplayer = *demo_p++;
2830 
2831       /* killough 11/98: save option pointer for below */
2832       if (mbf_features)
2833          option_p = demo_p;
2834 
2835       //e6y: check for overrun
2836       if (CheckForOverrun(header_p, demo_p, size, GAME_OPTION_SIZE, failonerror))
2837          return NULL;
2838 
2839       demo_p = G_ReadOptions(demo_p);  // killough 3/1/98: Read game options
2840 
2841       if (demover == 200)              // killough 6/3/98: partially fix v2.00 demos
2842          demo_p += 256-GAME_OPTION_SIZE;
2843    }
2844 
2845    if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL)
2846       I_Error("G_ReadDemoHeader: compatibility level strings incomplete");
2847    lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n",
2848          comp_lev_str[compatibility_level]);
2849 
2850    if (demo_compatibility)  // only 4 players can exist in old demos
2851    {
2852       //e6y: check for overrun
2853       if (CheckForOverrun(header_p, demo_p, size, 4, failonerror))
2854          return NULL;
2855 
2856       for (i=0; i<4; i++)  // intentionally hard-coded 4 -- killough
2857          playeringame[i] = *demo_p++;
2858       for (;i < MAXPLAYERS; i++)
2859          playeringame[i] = 0;
2860    }
2861    else
2862    {
2863       //e6y: check for overrun
2864       if (CheckForOverrun(header_p, demo_p, size, MAXPLAYERS, failonerror))
2865          return NULL;
2866 
2867       for (i=0 ; i < MAXPLAYERS; i++)
2868          playeringame[i] = *demo_p++;
2869       demo_p += MIN_MAXPLAYERS - MAXPLAYERS;
2870    }
2871 
2872    if (playeringame[1])
2873    {
2874       netgame = TRUE;
2875       netdemo = TRUE;
2876    }
2877 
2878    if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */
2879       G_InitNew(skill, episode, map);
2880    }
2881 
2882    for (i=0; i<MAXPLAYERS;i++)         // killough 4/24/98
2883       players[i].cheats = 0;
2884 
2885    return demo_p;
2886 }
2887 
G_DoPlayDemo(void)2888 void G_DoPlayDemo(void)
2889 {
2890   char basename[9];
2891 
2892   ExtractFileBase(defdemoname,basename);           // killough
2893   basename[8] = 0;
2894 
2895   /* cph - store lump number for unlocking later */
2896   demolumpnum = W_GetNumForName(basename);
2897   demobuffer = W_CacheLumpNum(demolumpnum);
2898   demolength = W_LumpLength(demolumpnum);
2899 
2900   demo_p = G_ReadDemoHeader(demobuffer, demolength, TRUE);
2901 
2902   gameaction = ga_nothing;
2903   usergame = FALSE;
2904 
2905   demoplayback = TRUE;
2906   R_SmoothPlaying_Reset(NULL); // e6y
2907 }
2908 
2909 /* G_CheckDemoStatus
2910  *
2911  * Called after a death or level completion to allow demos to be cleaned up
2912  * Returns TRUE if a new demo loop action will take place
2913  */
G_CheckDemoStatus(void)2914 dbool   G_CheckDemoStatus (void)
2915 {
2916   P_ChecksumFinal();
2917 
2918   if (demoplayback)
2919   {
2920     if (demolumpnum != -1) {
2921       // cph - unlock the demo lump
2922       W_UnlockLumpNum(demolumpnum);
2923       demolumpnum = -1;
2924     }
2925     G_ReloadDefaults();    // killough 3/1/98
2926     netgame = FALSE;       // killough 3/29/98
2927     deathmatch = FALSE;
2928     D_AdvanceDemo ();
2929     return TRUE;
2930   }
2931   return FALSE;
2932 }
2933 
2934 // killough 1/22/98: this is a "Doom printf" for messages. I've gotten
2935 // tired of using players->message=... and so I've added this dprintf.
2936 //
2937 // killough 3/6/98: Made limit static to allow z_zone functions to call
2938 // this function, without calling realloc(), which seems to cause problems.
2939 
2940 #define MAX_MESSAGE_SIZE 1024
2941 
2942 // CPhipps - renamed to doom_printf to avoid name collision with glibc
doom_printf(const char * s,...)2943 void doom_printf(const char *s, ...)
2944 {
2945   static char msg[MAX_MESSAGE_SIZE];
2946   va_list v;
2947   va_start(v,s);
2948 #ifdef HAVE_VSNPRINTF
2949   vsnprintf(msg,sizeof(msg),s,v);        /* print message in buffer */
2950 #else
2951   vsprintf(msg,s,v);
2952 #endif
2953   va_end(v);
2954   players[consoleplayer].message = msg;  // set new message
2955 }
2956