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 #include <io.h>
43 #else
44 #include <unistd.h>
45 #endif
46 #include <fcntl.h>
47 
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 
52 #include "doomstat.h"
53 #include "d_net.h"
54 #include "f_finale.h"
55 #include "m_argv.h"
56 #include "m_misc.h"
57 #include "m_menu.h"
58 #include "m_random.h"
59 #include "p_setup.h"
60 #include "p_saveg.h"
61 #include "p_tick.h"
62 #include "p_map.h"
63 #include "p_checksum.h"
64 #include "d_main.h"
65 #include "wi_stuff.h"
66 #include "hu_stuff.h"
67 #include "st_stuff.h"
68 #include "am_map.h"
69 #include "w_wad.h"
70 #include "r_main.h"
71 #include "r_draw.h"
72 #include "p_map.h"
73 #include "s_sound.h"
74 #include "s_advsound.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 #include "e6y.h"//e6y
88 
89 #define SAVEGAMESIZE  0x20000
90 #define SAVESTRINGSIZE  24
91 
92 // e6y
93 // It is signature for new savegame format with continuous numbering.
94 // Now it is not necessary to add a new level of compatibility in case
95 // of need to savegame format change from one minor version to another.
96 // The old format is still supported.
97 #define NEWFORMATSIG "\xff\xff\xff\xff"
98 
99 static size_t   savegamesize = SAVEGAMESIZE; // killough
100 static dboolean  netdemo;
101 static const byte *demobuffer;   /* cph - only used for playback */
102 static int demolength; // check for overrun (missing DEMOMARKER)
103 static FILE    *demofp; /* cph - record straight to file */
104 //e6y static
105 const byte *demo_p;
106 const byte *demo_continue_p = NULL;
107 static short    consistancy[MAXPLAYERS][BACKUPTICS];
108 
109 gameaction_t    gameaction;
110 gamestate_t     gamestate;
111 skill_t         gameskill;
112 dboolean         respawnmonsters;
113 int             gameepisode;
114 int             gamemap;
115 dboolean         paused;
116 // CPhipps - moved *_loadgame vars here
117 static dboolean forced_loadgame = false;
118 static dboolean command_loadgame = false;
119 
120 dboolean         usergame;      // ok to save / end game
121 dboolean         timingdemo;    // if true, exit with report on completion
122 dboolean         fastdemo;      // if true, run at full speed -- killough
123 dboolean         nodrawers;     // for comparative timing purposes
124 dboolean         noblit;        // for comparative timing purposes
125 int             starttime;     // for comparative timing purposes
126 dboolean         deathmatch;    // only if started as net death
127 dboolean         netgame;       // only true if packets are broadcast
128 dboolean         playeringame[MAXPLAYERS];
129 player_t        players[MAXPLAYERS];
130 int             consoleplayer; // player taking events and displaying
131 int             displayplayer; // view being displayed
132 int             gametic;
133 int             basetic;       /* killough 9/29/98: for demo sync */
134 int             totalkills, totallive, totalitems, totalsecret;    // for intermission
135 int             show_alive;
136 dboolean         demorecording;
137 dboolean         demoplayback;
138 dboolean         democontinue = false;
139 char             democontinuename[PATH_MAX];
140 int             demover;
141 dboolean         singledemo;           // quit after playing a demo from cmdline
142 wbstartstruct_t wminfo;               // parms for world map / intermission
143 dboolean         haswolflevels = false;// jff 4/18/98 wolf levels present
144 static byte     *savebuffer;          // CPhipps - static
145 int             autorun = false;      // always running?          // phares
146 int             totalleveltimes;      // CPhipps - total time for all completed levels
147 int             longtics;
148 int             bytes_per_tic;
149 
150 // e6y
151 // There is a new command-line switch "-shorttics".
152 // This makes it possible to practice routes and tricks
153 // (e.g. glides, where this makes a significant difference)
154 // with the same mouse behaviour as when recording,
155 // but without having to be recording every time.
156 int shorttics;
157 
158 //
159 // controls (have defaults)
160 //
161 
162 int     key_right;
163 int     key_left;
164 int     key_up;
165 int     key_down;
166 int     key_mlook;
167 int     key_menu_right;                                      // phares 3/7/98
168 int     key_menu_left;                                       //     |
169 int     key_menu_up;                                         //     V
170 int     key_menu_down;
171 int     key_menu_backspace;                                  //     ^
172 int     key_menu_escape;                                     //     |
173 int     key_menu_enter;                                      // phares 3/7/98
174 int     key_strafeleft;
175 int     key_straferight;
176 int     key_fire;
177 int     key_use;
178 int     key_strafe;
179 int     key_speed;
180 int     key_escape = KEYD_ESCAPE;                           // phares 4/13/98
181 int     key_savegame;                                               // phares
182 int     key_loadgame;                                               //    |
183 int     key_autorun;                                                //    V
184 int     key_reverse;
185 int     key_zoomin;
186 int     key_zoomout;
187 int     key_chat;
188 int     key_backspace;
189 int     key_enter;
190 int     key_map_right;
191 int     key_map_left;
192 int     key_map_up;
193 int     key_map_down;
194 int     key_map_zoomin;
195 int     key_map_zoomout;
196 int     key_map;
197 int     key_map_gobig;
198 int     key_map_follow;
199 int     key_map_mark;
200 int     key_map_clear;
201 int     key_map_grid;
202 int     key_map_overlay; // cph - map overlay
203 int     key_map_rotate;  // cph - map rotation
204 int     key_map_textured;  // e6y - textured automap
205 int     key_help = KEYD_F1;                                 // phares 4/13/98
206 int     key_soundvolume;
207 int     key_hud;
208 int     key_quicksave;
209 int     key_endgame;
210 int     key_messages;
211 int     key_quickload;
212 int     key_quit;
213 int     key_gamma;
214 int     key_spy;
215 int     key_pause;
216 int     key_setup;
217 int     destination_keys[MAXPLAYERS];
218 int     key_weapontoggle;
219 int     key_weapon1;
220 int     key_weapon2;
221 int     key_weapon3;
222 int     key_weapon4;
223 int     key_weapon5;
224 int     key_weapon6;
225 int     key_weapon7;                                                //    ^
226 int     key_weapon8;                                                //    |
227 int     key_weapon9;                                                // phares
228 int     key_nextweapon;
229 int     key_prevweapon;
230 
231 int     key_screenshot;             // killough 2/22/98: screenshot key
232 int     mousebfire;
233 int     mousebstrafe;
234 int     mousebforward;
235 int     mousebbackward;
236 int     mousebuse;
237 int     joybfire;
238 int     joybstrafe;
239 int     joybuse;
240 int     joybspeed;
241 
242 #define MAXPLMOVE   (forwardmove[1])
243 #define TURBOTHRESHOLD  0x32
244 #define SLOWTURNTICS  6
245 #define QUICKREVERSE (short)32768 // 180 degree reverse                    // phares
246 #define NUMKEYS   512
247 
248 fixed_t forwardmove[2] = {0x19, 0x32};
249 fixed_t sidemove[2]    = {0x18, 0x28};
250 fixed_t angleturn[3]   = {640, 1280, 320};  // + slow turn
251 
252 // CPhipps - made lots of key/button state vars static
253 //e6y static
254 dboolean gamekeydown[NUMKEYS];
255 static int     turnheld;       // for accelerative turning
256 
257 // Set to -1 or +1 to switch to the previous or next weapon.
258 
259 static int next_weapon = 0;
260 
261 // Used for prev/next weapon keys.
262 
263 static const struct
264 {
265   weapontype_t weapon;
266   weapontype_t weapon_num;
267 } weapon_order_table[] = {
268   { wp_fist,         wp_fist },
269   { wp_chainsaw,     wp_fist },
270   { wp_pistol,       wp_pistol },
271   { wp_shotgun,      wp_shotgun },
272   { wp_supershotgun, wp_shotgun },
273   { wp_chaingun,     wp_chaingun },
274   { wp_missile,      wp_missile },
275   { wp_plasma,       wp_plasma },
276   { wp_bfg,          wp_bfg }
277 };
278 
279 static int mousearray[6];
280 static int *mousebuttons = &mousearray[1];    // allow [-1]
281 
282 // mouse values are used once
283 static int   mousex;
284 static int   mousey;
285 static int   dclicktime;
286 static int   dclickstate;
287 static int   dclicks;
288 static int   dclicktime2;
289 static int   dclickstate2;
290 static int   dclicks2;
291 
292 // joystick values are repeated
293 static int   joyxmove;
294 static int   joyymove;
295 static dboolean joyarray[5];
296 static dboolean *joybuttons = &joyarray[1];    // allow [-1]
297 
298 // Game events info
299 static buttoncode_t special_event; // Event triggered by local player, to send
300 static byte  savegameslot;         // Slot to load if gameaction == ga_loadgame
301 char         savedescription[SAVEDESCLEN];  // Description to save in savegame if gameaction == ga_savegame
302 
303 //jff 3/24/98 define defaultskill here
304 int defaultskill;               //note 1-based
305 
306 // killough 2/8/98: make corpse queue variable in size
307 int    bodyqueslot, bodyquesize;        // killough 2/8/98
308 mobj_t **bodyque = 0;                   // phares 8/10/98
309 
310 static void G_DoSaveGame (dboolean menu);
311 
312 //e6y: save/restore all data which could be changed by G_ReadDemoHeader
313 static void G_SaveRestoreGameOptions(int save);
314 
315 //
316 // G_BuildTiccmd
317 // Builds a ticcmd from all of the available inputs
318 // or reads it from the demo buffer.
319 // If recording a demo, write it out
320 //
fudgef(signed char b)321 static inline signed char fudgef(signed char b)
322 {
323 /*e6y
324   static int c;
325   if (!b || !demo_compatibility || longtics) return b;
326   if (++c & 0x1f) return b;
327   b |= 1; if (b>2) b-=2;*/
328   return b;
329 }
330 
fudgea(signed short b)331 static inline signed short fudgea(signed short b)
332 {
333 /*e6y
334   if (!b || !demo_compatibility || !longtics) return b;
335   b |= 1; if (b>2) b-=2;*/
336   if (shorttics && !demorecording && !demoplayback)
337   {
338     // e6y
339     // There is a new command-line switch "-shorttics".
340     // This makes it possible to practice routes and tricks
341     // (e.g. glides, where this makes a significant difference)
342     // with the same mouse behaviour as when recording,
343     // but without having to be recording every time.
344     return (((b + 128) >> 8) << 8);
345   }
346   else
347   {
348     return b;
349   }
350 }
351 
WeaponSelectable(weapontype_t weapon)352 static dboolean WeaponSelectable(weapontype_t weapon)
353 {
354   if (gamemode == shareware)
355   {
356     if (weapon == wp_plasma || weapon == wp_bfg)
357       return false;
358   }
359 
360   // Can't select the super shotgun in Doom 1.
361   if (weapon == wp_supershotgun && gamemission == doom)
362   {
363     return false;
364   }
365 
366   // Can't select a weapon if we don't own it.
367   if (!players[consoleplayer].weaponowned[weapon])
368   {
369     return false;
370   }
371 
372   return true;
373 }
374 
G_NextWeapon(int direction)375 static int G_NextWeapon(int direction)
376 {
377   weapontype_t weapon;
378   int i, arrlen;
379 
380   // Find index in the table.
381   if (players[consoleplayer].pendingweapon == wp_nochange)
382   {
383     weapon = players[consoleplayer].readyweapon;
384   }
385   else
386   {
387     weapon = players[consoleplayer].pendingweapon;
388   }
389 
390   arrlen = sizeof(weapon_order_table) / sizeof(*weapon_order_table);
391   for (i = 0; i < arrlen; i++)
392   {
393     if (weapon_order_table[i].weapon == weapon)
394     {
395       break;
396     }
397   }
398 
399   // Switch weapon.
400   do
401   {
402     i += direction;
403     i = (i + arrlen) % arrlen;
404   }
405   while (!WeaponSelectable(weapon_order_table[i].weapon));
406 
407   return weapon_order_table[i].weapon_num;
408 }
409 
G_BuildTiccmd(ticcmd_t * cmd)410 void G_BuildTiccmd(ticcmd_t* cmd)
411 {
412   int strafe;
413   int bstrafe;
414   int speed;
415   int tspeed;
416   int forward;
417   int side;
418   int newweapon;                                          // phares
419   /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */
420   memset(cmd,0,sizeof*cmd);
421   cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
422 
423   strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
424     || joybuttons[joybstrafe];
425   //e6y: the "RUN" key inverts the autorun state
426   speed = (gamekeydown[key_speed] || joybuttons[joybspeed] ? !autorun : autorun); // phares
427 
428   forward = side = 0;
429 
430   G_SkipDemoCheck(); //e6y
431 
432   if (democontinue)
433   {
434     mousex = mousey = 0;
435     return;
436   }
437 
438     // use two stage accelerative turning
439     // on the keyboard and joystick
440   if (joyxmove < 0 || joyxmove > 0 ||
441       gamekeydown[key_right] || gamekeydown[key_left])
442     turnheld += ticdup;
443   else
444     turnheld = 0;
445 
446   if (turnheld < SLOWTURNTICS)
447     tspeed = 2;             // slow turn
448   else
449     tspeed = speed;
450 
451   // turn 180 degrees in one keystroke?                           // phares
452                                                                   //    |
453   if (gamekeydown[key_reverse])                                   //    V
454     {
455       cmd->angleturn += QUICKREVERSE;                             //    ^
456       gamekeydown[key_reverse] = false;                           //    |
457     }                                                             // phares
458 
459   // let movement keys cancel each other out
460 
461   if (strafe)
462     {
463       if (gamekeydown[key_right])
464         side += sidemove[speed];
465       if (gamekeydown[key_left])
466         side -= sidemove[speed];
467       if (joyxmove > 0)
468         side += sidemove[speed];
469       if (joyxmove < 0)
470         side -= sidemove[speed];
471     }
472   else
473     {
474       if (gamekeydown[key_right])
475         cmd->angleturn -= angleturn[tspeed];
476       if (gamekeydown[key_left])
477         cmd->angleturn += angleturn[tspeed];
478       if (joyxmove > 0)
479         cmd->angleturn -= angleturn[tspeed];
480       if (joyxmove < 0)
481         cmd->angleturn += angleturn[tspeed];
482     }
483 
484   if (gamekeydown[key_up])
485     forward += forwardmove[speed];
486   if (gamekeydown[key_down])
487     forward -= forwardmove[speed];
488   if (joyymove < 0)
489     forward += forwardmove[speed];
490   if (joyymove > 0)
491     forward -= forwardmove[speed];
492   if (gamekeydown[key_straferight])
493     side += sidemove[speed];
494   if (gamekeydown[key_strafeleft])
495     side -= sidemove[speed];
496 
497     // buttons
498   cmd->chatchar = HU_dequeueChatChar();
499 
500   if (gamekeydown[key_fire] || mousebuttons[mousebfire] ||
501       joybuttons[joybfire])
502     cmd->buttons |= BT_ATTACK;
503 
504   if (gamekeydown[key_use] || mousebuttons[mousebuse] ||
505       joybuttons[joybuse])
506     {
507       cmd->buttons |= BT_USE;
508       // clear double clicks if hit use button
509       dclicks = 0;
510     }
511 
512   // Toggle between the top 2 favorite weapons.                   // phares
513   // If not currently aiming one of these, switch to              // phares
514   // the favorite. Only switch if you possess the weapon.         // phares
515 
516   // killough 3/22/98:
517   //
518   // Perform automatic weapons switch here rather than in p_pspr.c,
519   // except in demo_compatibility mode.
520   //
521   // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left
522 
523   if ((!demo_compatibility && players[consoleplayer].attackdown && // killough
524        !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle])
525     newweapon = P_SwitchWeapon(&players[consoleplayer]);           // phares
526   else
527     {                                 // phares 02/26/98: Added gamemode checks
528       if (next_weapon)
529       {
530         newweapon = G_NextWeapon(next_weapon);
531         next_weapon = 0;
532       }
533       else
534       {
535       newweapon =
536         gamekeydown[key_weapon1] ? wp_fist :    // killough 5/2/98: reformatted
537         gamekeydown[key_weapon2] ? wp_pistol :
538         gamekeydown[key_weapon3] ? wp_shotgun :
539         gamekeydown[key_weapon4] ? wp_chaingun :
540         gamekeydown[key_weapon5] ? wp_missile :
541         gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma :
542         gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg :
543         gamekeydown[key_weapon8] ? wp_chainsaw :
544         (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? wp_supershotgun :
545         wp_nochange;
546       }
547 
548       // killough 3/22/98: For network and demo consistency with the
549       // new weapons preferences, we must do the weapons switches here
550       // instead of in p_user.c. But for old demos we must do it in
551       // p_user.c according to the old rules. Therefore demo_compatibility
552       // determines where the weapons switch is made.
553 
554       // killough 2/8/98:
555       // Allow user to switch to fist even if they have chainsaw.
556       // Switch to fist or chainsaw based on preferences.
557       // Switch to shotgun or SSG based on preferences.
558 
559       if (!demo_compatibility)
560         {
561           const player_t *player = &players[consoleplayer];
562 
563           // only select chainsaw from '1' if it's owned, it's
564           // not already in use, and the player prefers it or
565           // the fist is already in use, or the player does not
566           // have the berserker strength.
567 
568           if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] &&
569               player->readyweapon!=wp_chainsaw &&
570               (player->readyweapon==wp_fist ||
571                !player->powers[pw_strength] ||
572                P_WeaponPreferred(wp_chainsaw, wp_fist)))
573             newweapon = wp_chainsaw;
574 
575           // Select SSG from '3' only if it's owned and the player
576           // does not have a shotgun, or if the shotgun is already
577           // in use, or if the SSG is not already in use and the
578           // player prefers it.
579 
580           if (newweapon == wp_shotgun && gamemode == commercial &&
581               player->weaponowned[wp_supershotgun] &&
582               (!player->weaponowned[wp_shotgun] ||
583                player->readyweapon == wp_shotgun ||
584                (player->readyweapon != wp_supershotgun &&
585                 P_WeaponPreferred(wp_supershotgun, wp_shotgun))))
586             newweapon = wp_supershotgun;
587         }
588       // killough 2/8/98, 3/22/98 -- end of weapon selection changes
589       //}
590     }
591 
592   if (newweapon != wp_nochange)
593     {
594       cmd->buttons |= BT_CHANGE;
595       cmd->buttons |= newweapon<<BT_WEAPONSHIFT;
596     }
597 
598   // mouse
599   if (mousebuttons[mousebforward])
600     forward += forwardmove[speed];
601   if (mousebuttons[mousebbackward])
602     forward -= forwardmove[speed];
603 
604   if (mouse_doubleclick_as_use) {//e6y
605 
606   // forward double click
607   if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
608     {
609       dclickstate = mousebuttons[mousebforward];
610       if (dclickstate)
611         dclicks++;
612       if (dclicks == 2)
613         {
614           cmd->buttons |= BT_USE;
615           dclicks = 0;
616         }
617       else
618         dclicktime = 0;
619     }
620   else
621     if ((dclicktime += ticdup) > 20)
622       {
623         dclicks = 0;
624         dclickstate = 0;
625       }
626 
627   // strafe double click
628 
629   bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
630   if (bstrafe != dclickstate2 && dclicktime2 > 1 )
631     {
632       dclickstate2 = bstrafe;
633       if (dclickstate2)
634         dclicks2++;
635       if (dclicks2 == 2)
636         {
637           cmd->buttons |= BT_USE;
638           dclicks2 = 0;
639         }
640       else
641         dclicktime2 = 0;
642     }
643   else
644     if ((dclicktime2 += ticdup) > 20)
645       {
646         dclicks2 = 0;
647         dclickstate2 = 0;
648       }
649 
650   }//e6y: end if (mouse_doubleclick_as_use)
651 
652   forward += mousey;
653   if (strafe)
654     side += mousex / 4;       /* mead  Don't want to strafe as fast as turns.*/
655   else
656     cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */
657 
658   if (!walkcamera.type || menuactive) //e6y
659     mousex = mousey = 0;
660 
661   if (forward > MAXPLMOVE)
662     forward = MAXPLMOVE;
663   else if (forward < -MAXPLMOVE)
664     forward = -MAXPLMOVE;
665   if (side > MAXPLMOVE)
666     side = MAXPLMOVE;
667   else if (side < -MAXPLMOVE)
668     side = -MAXPLMOVE;
669 
670   //e6y
671   if (movement_strafe50)
672   {
673     if (!speed)
674     {
675       if (side > sidemove_strafe50[0])
676         side = sidemove_strafe50[0];
677       else if (side < -sidemove_strafe50[0])
678         side = -sidemove_strafe50[0];
679     }
680     else if(!movement_strafe50onturns && !strafe && cmd->angleturn)
681     {
682       if (side > sidemove_normal[1])
683         side = sidemove_normal[1];
684       else if (side < -sidemove_normal[1])
685         side = -sidemove_normal[1];
686     }
687 
688   }
689 
690   cmd->forwardmove += fudgef((signed char)forward);
691   cmd->sidemove += side;
692   cmd->angleturn = fudgea(cmd->angleturn);
693 
694   // CPhipps - special events (game new/load/save/pause)
695   if (special_event & BT_SPECIAL) {
696     cmd->buttons = special_event;
697     special_event = 0;
698   }
699 }
700 
701 //
702 // G_RestartLevel
703 //
704 
G_RestartLevel(void)705 void G_RestartLevel(void)
706 {
707   special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK);
708 }
709 
710 //
711 // G_DoLoadLevel
712 //
713 
G_DoLoadLevel(void)714 static void G_DoLoadLevel (void)
715 {
716   int i;
717 
718   // Set the sky map.
719   // First thing, we have a dummy sky texture name,
720   //  a flat. The data is in the WAD only because
721   //  we look for an actual index, instead of simply
722   //  setting one.
723 
724   skyflatnum = R_FlatNumForName ( SKYFLATNAME );
725 
726   // DOOM determines the sky texture to be used
727   // depending on the current episode, and the game version.
728   if (gamemode == commercial)
729     // || gamemode == pack_tnt   //jff 3/27/98 sorry guys pack_tnt,pack_plut
730     // || gamemode == pack_plut) //aren't gamemodes, this was matching retail
731     {
732       skytexture = R_TextureNumForName ("SKY3");
733       if (gamemap < 12)
734         skytexture = R_TextureNumForName ("SKY1");
735       else
736         if (gamemap < 21)
737           skytexture = R_TextureNumForName ("SKY2");
738     }
739   else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh?
740     switch (gameepisode)
741       {
742       case 1:
743         skytexture = R_TextureNumForName ("SKY1");
744         break;
745       case 2:
746         skytexture = R_TextureNumForName ("SKY2");
747         break;
748       case 3:
749         skytexture = R_TextureNumForName ("SKY3");
750         break;
751       case 4: // Special Edition sky
752         skytexture = R_TextureNumForName ("SKY4");
753         break;
754       }//jff 3/27/98 end sky setting fix
755 
756 #ifdef GL_DOOM
757   R_SetBoxSkybox(skytexture);
758 #endif
759 
760   levelstarttic = gametic;        // for time calculation
761 
762   if (!demo_compatibility && !mbf_features)   // killough 9/29/98
763     basetic = gametic;
764 
765   if (wipegamestate == GS_LEVEL)
766     wipegamestate = -1;             // force a wipe
767 
768   gamestate = GS_LEVEL;
769 
770   for (i=0 ; i<MAXPLAYERS ; i++)
771     {
772       if (playeringame[i] && players[i].playerstate == PST_DEAD)
773         players[i].playerstate = PST_REBORN;
774       memset (players[i].frags,0,sizeof(players[i].frags));
775     }
776 
777   // initialize the msecnode_t freelist.                     phares 3/25/98
778   // any nodes in the freelist are gone by now, cleared
779   // by Z_FreeTags() when the previous level ended or player
780   // died.
781   P_FreeSecNodeList();
782 
783   P_SetupLevel (gameepisode, gamemap, 0, gameskill);
784   if (!demoplayback) // Don't switch views if playing a demo
785     displayplayer = consoleplayer;    // view the guy you are playing
786   gameaction = ga_nothing;
787   Z_CheckHeap ();
788 
789   // clear cmd building stuff
790   memset (gamekeydown, 0, sizeof(gamekeydown));
791   joyxmove = joyymove = 0;
792   mousex = mousey = 0;
793   mlooky = 0;//e6y
794   special_event = 0; paused = false;
795   memset (&mousearray, 0, sizeof(mousearray));
796   memset (&joyarray, 0, sizeof(joyarray));
797 
798   // killough 5/13/98: in case netdemo has consoleplayer other than green
799   ST_Start();
800   HU_Start();
801 
802   // killough: make -timedemo work on multilevel demos
803   // Move to end of function to minimize noise -- killough 2/22/98:
804 
805   if (timingdemo)
806     {
807       static int first=1;
808       if (first)
809         {
810           starttime = I_GetTime_RealTime ();
811           first=0;
812         }
813     }
814 }
815 
816 
817 //
818 // G_Responder
819 // Get info needed to make ticcmd_ts for the players.
820 //
821 
G_Responder(event_t * ev)822 dboolean G_Responder (event_t* ev)
823 {
824   // allow spy mode changes even during the demo
825   // killough 2/22/98: even during DM demo
826   //
827   // killough 11/98: don't autorepeat spy mode switch
828 
829   if (ev->data1 == key_spy && netgame && (demoplayback || !deathmatch) &&
830       gamestate == GS_LEVEL)
831     {
832       if (ev->type == ev_keyup)
833   gamekeydown[key_spy] = false;
834       if (ev->type == ev_keydown && !gamekeydown[key_spy])
835   {
836     gamekeydown[key_spy] = true;
837     do                                          // spy mode
838       if (++displayplayer >= MAXPLAYERS)
839         displayplayer = 0;
840     while (!playeringame[displayplayer] && displayplayer!=consoleplayer);
841 
842     ST_Start();    // killough 3/7/98: switch status bar views too
843     HU_Start();
844     S_UpdateSounds(players[displayplayer].mo);
845     R_ActivateSectorInterpolations();
846     R_SmoothPlaying_Reset(NULL);
847   }
848       return true;
849     }
850 
851   // any other key pops up menu if in demos
852   //
853   // killough 8/2/98: enable automap in -timedemo demos
854   //
855   // killough 9/29/98: make any key pop up menu regardless of
856   // which kind of demo, and allow other events during playback
857 
858   if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN))
859     {
860       // killough 9/29/98: allow user to pause demos during playback
861       if (ev->type == ev_keydown && ev->data1 == key_pause)
862   {
863     if (paused ^= 2)
864       S_PauseSound();
865     else
866       S_ResumeSound();
867     return true;
868   }
869 
870       // killough 10/98:
871       // Don't pop up menu, if paused in middle
872       // of demo playback, or if automap active.
873       // Don't suck up keys, which may be cheats
874 
875 //e6y
876   /*
877       return gamestate == GS_DEMOSCREEN &&
878   !(paused & 2) && !(automapmode & am_active) &&
879   ((ev->type == ev_keydown) ||
880    (ev->type == ev_mouse && ev->data1) ||
881    (ev->type == ev_joystick && ev->data1)) ?
882   M_StartControlPanel(), true : false;
883     */
884     }
885 
886   if (gamestate == GS_FINALE && F_Responder(ev))
887     return true;  // finale ate the event
888 
889   // If the next/previous weapon keys are pressed, set the next_weapon
890   // variable to change weapons when the next ticcmd is generated.
891   if (ev->type == ev_keydown)
892   {
893     if (ev->data1 == key_prevweapon)
894     {
895       next_weapon = -1;
896     }
897     else if (ev->data1 == key_nextweapon)
898     {
899       next_weapon = 1;
900     }
901   }
902 
903   switch (ev->type)
904     {
905     case ev_keydown:
906       if (ev->data1 == key_pause)           // phares
907         {
908           special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK);
909           return true;
910         }
911       if (ev->data1 <NUMKEYS)
912         gamekeydown[ev->data1] = true;
913       return true;    // eat key down events
914 
915     case ev_keyup:
916       if (ev->data1 <NUMKEYS)
917         gamekeydown[ev->data1] = false;
918       return false;   // always let key up events filter down
919 
920     case ev_mouse:
921       mousebuttons[0] = ev->data1 & 1;
922       mousebuttons[1] = ev->data1 & 2;
923       mousebuttons[2] = ev->data1 & 4;
924       mousebuttons[3] = ev->data1 & 8;
925       mousebuttons[4] = ev->data1 & 16;
926       /*
927        * bmead@surfree.com
928        * Modified by Barry Mead after adding vastly more resolution
929        * to the Mouse Sensitivity Slider in the options menu 1-9-2000
930        * Removed the mouseSensitivity "*4" to allow more low end
931        * sensitivity resolution especially for lsdoom users.
932        */
933       //e6y mousex += (ev->data2*(mouseSensitivity_horiz))/10;  /* killough */
934       //e6y mousey += (ev->data3*(mouseSensitivity_vert))/10;  /*Mead rm *4 */
935 
936       //e6y
937       mousex += (AccelerateMouse(ev->data2)*(mouseSensitivity_horiz))/10;  /* killough */
938       if(GetMouseLook())
939         if (movement_mouseinvert)
940           mlooky += (AccelerateMouse(ev->data3)*(mouseSensitivity_mlook))/10;
941         else
942           mlooky -= (AccelerateMouse(ev->data3)*(mouseSensitivity_mlook))/10;
943       else
944         mousey += (AccelerateMouse(ev->data3)*(mouseSensitivity_vert))/40;
945 
946       return true;    // eat events
947 
948     case ev_joystick:
949       joybuttons[0] = ev->data1 & 1;
950       joybuttons[1] = ev->data1 & 2;
951       joybuttons[2] = ev->data1 & 4;
952       joybuttons[3] = ev->data1 & 8;
953       joyxmove = ev->data2;
954       joyymove = ev->data3;
955       return true;    // eat events
956 
957     default:
958       break;
959     }
960   return false;
961 }
962 
963 //
964 // G_Ticker
965 // Make ticcmd_ts for the players.
966 //
967 
G_Ticker(void)968 void G_Ticker (void)
969 {
970   int i;
971   static gamestate_t prevgamestate;
972 
973   // CPhipps - player colour changing
974   if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) {
975     // Changed my multiplayer colour - Inform the whole game
976     int net_cl = LittleLong(mapcolor_me);
977 #ifdef HAVE_NET
978     D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl);
979 #endif
980     G_ChangedPlayerColour(consoleplayer, mapcolor_me);
981   }
982   P_MapStart();
983   // do player reborns if needed
984   for (i=0 ; i<MAXPLAYERS ; i++)
985     if (playeringame[i] && players[i].playerstate == PST_REBORN)
986       G_DoReborn (i);
987   P_MapEnd();
988 
989   // do things to change the game state
990   while (gameaction != ga_nothing)
991     {
992       switch (gameaction)
993         {
994         case ga_loadlevel:
995     // force players to be initialized on level reload
996     for (i=0 ; i<MAXPLAYERS ; i++)
997       players[i].playerstate = PST_REBORN;
998           G_DoLoadLevel ();
999           break;
1000         case ga_newgame:
1001           G_DoNewGame ();
1002           break;
1003         case ga_loadgame:
1004           G_DoLoadGame ();
1005           break;
1006         case ga_savegame:
1007           G_DoSaveGame (false);
1008           break;
1009         case ga_playdemo:
1010           G_DoPlayDemo ();
1011           break;
1012         case ga_completed:
1013           G_DoCompleted ();
1014           break;
1015         case ga_victory:
1016           F_StartFinale ();
1017           break;
1018         case ga_worlddone:
1019           G_DoWorldDone ();
1020           break;
1021         case ga_nothing:
1022           break;
1023         }
1024     }
1025 
1026   if (paused & 2 || (!demoplayback && menuactive && !netgame))
1027     basetic++;  // For revenant tracers and RNG -- we must maintain sync
1028   else {
1029     // get commands, check consistancy, and build new consistancy check
1030     int buf = (gametic/ticdup)%BACKUPTICS;
1031 
1032     for (i=0 ; i<MAXPLAYERS ; i++) {
1033       if (playeringame[i])
1034         {
1035           ticcmd_t *cmd = &players[i].cmd;
1036 
1037           memcpy(cmd, &netcmds[i][buf], sizeof *cmd);
1038 
1039           //e6y
1040           if (democontinue)
1041             G_ReadDemoContinueTiccmd (cmd);
1042 
1043           if (demoplayback)
1044             G_ReadDemoTiccmd (cmd);
1045           if (demorecording)
1046             G_WriteDemoTiccmd (cmd);
1047 
1048           // check for turbo cheats
1049           // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
1050 
1051           if ((netgame || demoplayback) && cmd->forwardmove > TURBOTHRESHOLD &&
1052               !(gametic&31) && ((gametic>>5)&3) == i )
1053             {
1054         extern char *player_names[];
1055         /* cph - don't use sprintf, use doom_printf */
1056               doom_printf ("%s is turbo!", player_names[i]);
1057             }
1058 
1059           if (netgame && !netdemo && !(gametic%ticdup) )
1060             {
1061               if (gametic > BACKUPTICS
1062                   && consistancy[i][buf] != cmd->consistancy)
1063                 I_Error("G_Ticker: Consistency failure (%i should be %i)",
1064             cmd->consistancy, consistancy[i][buf]);
1065               if (players[i].mo)
1066                 consistancy[i][buf] = players[i].mo->x;
1067               else
1068                 consistancy[i][buf] = 0; // killough 2/14/98
1069             }
1070         }
1071     }
1072 
1073     // check for special buttons
1074     for (i=0; i<MAXPLAYERS; i++) {
1075       if (playeringame[i])
1076         {
1077           if (players[i].cmd.buttons & BT_SPECIAL)
1078             {
1079               switch (players[i].cmd.buttons & BT_SPECIALMASK)
1080                 {
1081                 case BTS_PAUSE:
1082                   paused ^= 1;
1083                   if (paused)
1084                     S_PauseSound ();
1085                   else
1086                     S_ResumeSound ();
1087                   break;
1088 
1089                 case BTS_SAVEGAME:
1090                   if (!savedescription[0])
1091                     strcpy(savedescription, "NET GAME");
1092                   savegameslot =
1093                     (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
1094                   gameaction = ga_savegame;
1095                   break;
1096 
1097       // CPhipps - remote loadgame request
1098                 case BTS_LOADGAME:
1099                   savegameslot =
1100                     (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
1101                   gameaction = ga_loadgame;
1102       forced_loadgame = netgame; // Force if a netgame
1103       command_loadgame = false;
1104                   break;
1105 
1106       // CPhipps - Restart the level
1107     case BTS_RESTARTLEVEL:
1108                   if (demoplayback || (compatibility_level < lxdoom_1_compatibility))
1109                     break;     // CPhipps - Ignore in demos or old games
1110       gameaction = ga_loadlevel;
1111       break;
1112                 }
1113         players[i].cmd.buttons = 0;
1114             }
1115         }
1116     }
1117   }
1118 
1119   // cph - if the gamestate changed, we may need to clean up the old gamestate
1120   if (gamestate != prevgamestate) {
1121     switch (prevgamestate) {
1122     case GS_LEVEL:
1123       // This causes crashes at level end - Neil Stevens
1124       // The crash is because the sounds aren't stopped before freeing them
1125       // the following is a possible fix
1126       // This fix does avoid the crash wowever, with this fix in, the exit
1127       // switch sound is cut off
1128       // S_Stop();
1129       // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
1130       break;
1131     case GS_INTERMISSION:
1132       WI_End();
1133     default:
1134       break;
1135     }
1136     prevgamestate = gamestate;
1137   }
1138 
1139   // e6y
1140   // do nothing if a pause has been pressed during playback
1141   // pausing during intermission can cause desynchs without that
1142   if (paused & 2 && gamestate != GS_LEVEL)
1143     return;
1144 
1145   // do main actions
1146   switch (gamestate)
1147     {
1148     case GS_LEVEL:
1149       P_Ticker ();
1150       P_WalkTicker();//e6y
1151       mlooky = 0;//e6y
1152       if (!movement_smooth)
1153         AM_Ticker();
1154       else
1155         AM_savePrevLocAndScale();
1156       ST_Ticker ();
1157       HU_Ticker ();
1158       break;
1159 
1160     case GS_INTERMISSION:
1161        WI_Ticker ();
1162       break;
1163 
1164     case GS_FINALE:
1165       F_Ticker ();
1166       break;
1167 
1168     case GS_DEMOSCREEN:
1169       D_PageTicker ();
1170       break;
1171     }
1172 }
1173 
1174 //
1175 // PLAYER STRUCTURE FUNCTIONS
1176 // also see P_SpawnPlayer in P_Things
1177 //
1178 
1179 //
1180 // G_PlayerFinishLevel
1181 // Can when a player completes a level.
1182 //
1183 
G_PlayerFinishLevel(int player)1184 static void G_PlayerFinishLevel(int player)
1185 {
1186   player_t *p = &players[player];
1187   memset(p->powers, 0, sizeof p->powers);
1188   memset(p->cards, 0, sizeof p->cards);
1189   p->mo = NULL;           // cph - this is allocated PU_LEVEL so it's gone
1190   p->extralight = 0;      // cancel gun flashes
1191   p->fixedcolormap = 0;   // cancel ir gogles
1192   p->damagecount = 0;     // no palette changes
1193   p->bonuscount = 0;
1194 }
1195 
1196 // CPhipps - G_SetPlayerColour
1197 // Player colours stuff
1198 //
1199 // G_SetPlayerColour
1200 
1201 #include "r_draw.h"
1202 
G_ChangedPlayerColour(int pn,int cl)1203 void G_ChangedPlayerColour(int pn, int cl)
1204 {
1205   int i;
1206 
1207   if (!netgame) return;
1208 
1209   mapcolor_plyr[pn] = cl;
1210 
1211   // Rebuild colour translation tables accordingly
1212   R_InitTranslationTables();
1213   // Change translations on existing player mobj's
1214   for (i=0; i<MAXPLAYERS; i++) {
1215     if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) {
1216       players[i].mo->flags &= ~MF_TRANSLATION;
1217       players[i].mo->flags |= ((uint_64_t)playernumtotrans[i]) << MF_TRANSSHIFT;
1218     }
1219   }
1220 }
1221 
1222 //
1223 // G_PlayerReborn
1224 // Called after a player dies
1225 // almost everything is cleared and initialized
1226 //
1227 
G_PlayerReborn(int player)1228 void G_PlayerReborn (int player)
1229 {
1230   player_t *p;
1231   int i;
1232   int frags[MAXPLAYERS];
1233   int killcount;
1234   int itemcount;
1235   int secretcount;
1236   int resurectedkillcount; //e6y
1237 
1238   memcpy (frags, players[player].frags, sizeof frags);
1239   killcount = players[player].killcount;
1240   itemcount = players[player].itemcount;
1241   secretcount = players[player].secretcount;
1242   resurectedkillcount = players[player].resurectedkillcount; //e6y
1243 
1244   p = &players[player];
1245 
1246   // killough 3/10/98,3/21/98: preserve cheats across idclev
1247   {
1248     int cheats = p->cheats;
1249     memset (p, 0, sizeof(*p));
1250     p->cheats = cheats;
1251   }
1252 
1253   memcpy(players[player].frags, frags, sizeof(players[player].frags));
1254   players[player].killcount = killcount;
1255   players[player].itemcount = itemcount;
1256   players[player].secretcount = secretcount;
1257   players[player].resurectedkillcount = resurectedkillcount; //e6y
1258 
1259   p->usedown = p->attackdown = true;  // don't do anything immediately
1260   p->playerstate = PST_LIVE;
1261   p->health = initial_health;  // Ty 03/12/98 - use dehacked values
1262   p->readyweapon = p->pendingweapon = wp_pistol;
1263   p->weaponowned[wp_fist] = true;
1264   p->weaponowned[wp_pistol] = true;
1265   p->ammo[am_clip] = initial_bullets; // Ty 03/12/98 - use dehacked values
1266 
1267   for (i=0 ; i<NUMAMMO ; i++)
1268     p->maxammo[i] = maxammo[i];
1269 }
1270 
1271 //
1272 // G_CheckSpot
1273 // Returns false if the player cannot be respawned
1274 // at the given mapthing_t spot
1275 // because something is occupying it
1276 //
1277 
G_CheckSpot(int playernum,mapthing_t * mthing)1278 static dboolean G_CheckSpot(int playernum, mapthing_t *mthing)
1279 {
1280   fixed_t     x,y;
1281   subsector_t *ss;
1282   int         i;
1283 
1284   if (!players[playernum].mo)
1285     {
1286       // first spawn of level, before corpses
1287       for (i=0 ; i<playernum ; i++)
1288         if (players[i].mo->x == mthing->x << FRACBITS
1289             && players[i].mo->y == mthing->y << FRACBITS)
1290           return false;
1291       return true;
1292     }
1293 
1294   x = mthing->x << FRACBITS;
1295   y = mthing->y << FRACBITS;
1296 
1297   // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
1298   // corpse to detect collisions with other players in DM starts
1299   //
1300   // Old code:
1301   // if (!P_CheckPosition (players[playernum].mo, x, y))
1302   //    return false;
1303 
1304   players[playernum].mo->flags |=  MF_SOLID;
1305   i = P_CheckPosition(players[playernum].mo, x, y);
1306   players[playernum].mo->flags &= ~MF_SOLID;
1307   if (!i)
1308     return false;
1309 
1310   // flush an old corpse if needed
1311   // killough 2/8/98: make corpse queue have an adjustable limit
1312   // killough 8/1/98: Fix bugs causing strange crashes
1313 
1314   if (bodyquesize > 0)
1315     {
1316       static int queuesize;
1317       if (queuesize < bodyquesize)
1318 	{
1319 	  bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque);
1320 	  memset(bodyque+queuesize, 0,
1321 		 (bodyquesize-queuesize)*sizeof*bodyque);
1322 	  queuesize = bodyquesize;
1323 	}
1324       if (bodyqueslot >= bodyquesize)
1325 	P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]);
1326       bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo;
1327     }
1328   else
1329     if (!bodyquesize)
1330       P_RemoveMobj(players[playernum].mo);
1331 
1332   // spawn a teleport fog
1333   ss = R_PointInSubsector (x,y);
1334   { // Teleport fog at respawn point
1335     fixed_t xa,ya;
1336     int an;
1337     mobj_t      *mo;
1338 
1339 /* BUG: an can end up negative, because mthing->angle is (signed) short.
1340  * We have to emulate original Doom's behaviour, deferencing past the start
1341  * of the array, into the previous array (finetangent) */
1342     an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT;
1343     xa = finecosine[an];
1344     ya = finesine[an];
1345 
1346     if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility)
1347       switch (an) {
1348       case -4096: xa = finetangent[2048];   // finecosine[-4096]
1349           	ya = finetangent[0];      // finesine[-4096]
1350           	break;
1351       case -3072: xa = finetangent[3072];   // finecosine[-3072]
1352           	ya = finetangent[1024];   // finesine[-3072]
1353           	break;
1354       case -2048: xa = finesine[0];   // finecosine[-2048]
1355           	ya = finetangent[2048];   // finesine[-2048]
1356           	break;
1357       case -1024:	xa = finesine[1024];     // finecosine[-1024]
1358           	ya = finetangent[3072];  // finesine[-1024]
1359           	break;
1360       case 1024:
1361       case 2048:
1362       case 3072:
1363       case 4096:
1364       case 0:	break; /* correct angles set above */
1365       default:	I_Error("G_CheckSpot: unexpected angle %d\n",an);
1366       }
1367 
1368     mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG);
1369 
1370     if (players[consoleplayer].viewz != 1)
1371       S_StartSound(mo, sfx_telept);  // don't start sound on first frame
1372   }
1373 
1374   return true;
1375 }
1376 
1377 
1378 // G_DeathMatchSpawnPlayer
1379 // Spawns a player at one of the random death match spots
1380 // called at level load and each death
1381 //
G_DeathMatchSpawnPlayer(int playernum)1382 void G_DeathMatchSpawnPlayer (int playernum)
1383 {
1384   int j, selections = deathmatch_p - deathmatchstarts;
1385 
1386   if (selections < MAXPLAYERS)
1387     I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required",
1388     selections, MAXPLAYERS);
1389 
1390   for (j=0 ; j<20 ; j++)
1391     {
1392       int i = P_Random(pr_dmspawn) % selections;
1393       if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1394         {
1395           deathmatchstarts[i].type = playernum+1;
1396           P_SpawnPlayer (playernum, &deathmatchstarts[i]);
1397           return;
1398         }
1399     }
1400 
1401   // no good spot, so the player will probably get stuck
1402   P_SpawnPlayer (playernum, &playerstarts[playernum]);
1403 }
1404 
1405 //
1406 // G_DoReborn
1407 //
1408 
G_DoReborn(int playernum)1409 void G_DoReborn (int playernum)
1410 {
1411   if (!netgame)
1412     gameaction = ga_loadlevel;      // reload the level from scratch
1413   else
1414     {                               // respawn at the start
1415       int i;
1416 
1417       // first dissasociate the corpse
1418       players[playernum].mo->player = NULL;
1419 
1420       // spawn at random spot if in death match
1421       if (deathmatch)
1422         {
1423           G_DeathMatchSpawnPlayer (playernum);
1424           return;
1425         }
1426 
1427       if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1428         {
1429           P_SpawnPlayer (playernum, &playerstarts[playernum]);
1430           return;
1431         }
1432 
1433       // try to spawn at one of the other players spots
1434       for (i=0 ; i<MAXPLAYERS ; i++)
1435         {
1436           if (G_CheckSpot (playernum, &playerstarts[i]) )
1437             {
1438               P_SpawnPlayer (playernum, &playerstarts[i]);
1439               return;
1440             }
1441           // he's going to be inside something.  Too bad.
1442         }
1443       P_SpawnPlayer (playernum, &playerstarts[playernum]);
1444     }
1445 }
1446 
1447 // DOOM Par Times
1448 int pars[4][10] = {
1449   {0},
1450   {0,30,75,120,90,165,180,180,30,165},
1451   {0,90,90,90,120,90,360,240,30,170},
1452   {0,90,45,90,150,90,90,165,30,135}
1453 };
1454 
1455 // DOOM II Par Times
1456 int cpars[32] = {
1457   30,90,120,120,90,150,120,120,270,90,  //  1-10
1458   210,150,150,150,210,150,420,150,210,150,  // 11-20
1459   240,150,180,150,150,300,330,420,300,180,  // 21-30
1460   120,30          // 31-32
1461 };
1462 
1463 static dboolean secretexit;
1464 
G_ExitLevel(void)1465 void G_ExitLevel (void)
1466 {
1467   secretexit = false;
1468   gameaction = ga_completed;
1469 }
1470 
1471 // Here's for the german edition.
1472 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1473 
G_SecretExitLevel(void)1474 void G_SecretExitLevel (void)
1475 {
1476   if (gamemode!=commercial || haswolflevels)
1477     secretexit = true;
1478   else
1479     secretexit = false;
1480   gameaction = ga_completed;
1481 }
1482 
1483 //
1484 // G_DoCompleted
1485 //
1486 
G_DoCompleted(void)1487 void G_DoCompleted (void)
1488 {
1489   int i;
1490 
1491   gameaction = ga_nothing;
1492 
1493   for (i=0; i<MAXPLAYERS; i++)
1494     if (playeringame[i])
1495       G_PlayerFinishLevel(i);        // take away cards and stuff
1496 
1497   if (automapmode & am_active)
1498     AM_Stop();
1499 
1500   if (gamemode != commercial) // kilough 2/7/98
1501     switch(gamemap)
1502       {
1503   // cph - Remove ExM8 special case, so it gets summary screen displayed
1504       case 9:
1505         for (i=0 ; i<MAXPLAYERS ; i++)
1506           players[i].didsecret = true;
1507         break;
1508       }
1509 
1510   wminfo.didsecret = players[consoleplayer].didsecret;
1511   wminfo.epsd = gameepisode -1;
1512   wminfo.last = gamemap -1;
1513 
1514   // wminfo.next is 0 biased, unlike gamemap
1515   if (gamemode == commercial)
1516     {
1517       if (secretexit)
1518         switch(gamemap)
1519           {
1520           case 15:
1521             wminfo.next = 30; break;
1522           case 31:
1523             wminfo.next = 31; break;
1524           }
1525       else
1526         switch(gamemap)
1527           {
1528           case 31:
1529           case 32:
1530             wminfo.next = 15; break;
1531           default:
1532             wminfo.next = gamemap;
1533           }
1534     }
1535   else
1536     {
1537       if (secretexit)
1538         wminfo.next = 8;  // go to secret level
1539       else
1540         if (gamemap == 9)
1541           {
1542             // returning from secret level
1543             switch (gameepisode)
1544               {
1545               case 1:
1546                 wminfo.next = 3;
1547                 break;
1548               case 2:
1549                 wminfo.next = 5;
1550                 break;
1551               case 3:
1552                 wminfo.next = 6;
1553                 break;
1554               case 4:
1555                 wminfo.next = 2;
1556                 break;
1557               }
1558           }
1559         else
1560           wminfo.next = gamemap;          // go to next level
1561     }
1562 
1563   wminfo.maxkills = totalkills;
1564   wminfo.maxitems = totalitems;
1565   wminfo.maxsecret = totalsecret;
1566   wminfo.maxfrags = 0;
1567 
1568   if ( gamemode == commercial )
1569     wminfo.partime = TICRATE*cpars[gamemap-1];
1570   else
1571     wminfo.partime = TICRATE*pars[gameepisode][gamemap];
1572 
1573   wminfo.pnum = consoleplayer;
1574 
1575   for (i=0 ; i<MAXPLAYERS ; i++)
1576     {
1577       wminfo.plyr[i].in = playeringame[i];
1578       wminfo.plyr[i].skills = players[i].killcount;
1579       wminfo.plyr[i].sitems = players[i].itemcount;
1580       wminfo.plyr[i].ssecret = players[i].secretcount;
1581       wminfo.plyr[i].stime = leveltime;
1582       memcpy (wminfo.plyr[i].frags, players[i].frags,
1583               sizeof(wminfo.plyr[i].frags));
1584     }
1585 
1586   /* cph - modified so that only whole seconds are added to the totalleveltimes
1587    *  value; so our total is compatible with the "naive" total of just adding
1588    *  the times in seconds shown for each level. Also means our total time
1589    *  will agree with Compet-n.
1590    */
1591   wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35));
1592 
1593   gamestate = GS_INTERMISSION;
1594   automapmode &= ~am_active;
1595 
1596   // lmpwatch.pl engine-side demo testing support
1597   // print "FINISHED: <mapname>" when the player exits the current map
1598   if (nodrawers && (demoplayback || timingdemo)) {
1599     if (gamemode == commercial)
1600       lprintf(LO_INFO, "FINISHED: MAP%02d\n", gamemap);
1601     else
1602       lprintf(LO_INFO, "FINISHED: E%dM%d\n", gameepisode, gamemap);
1603   }
1604 
1605   e6y_G_DoCompleted();//e6y
1606 
1607   WI_Start (&wminfo);
1608 }
1609 
1610 //
1611 // G_WorldDone
1612 //
1613 
G_WorldDone(void)1614 void G_WorldDone (void)
1615 {
1616   gameaction = ga_worlddone;
1617 
1618   if (secretexit)
1619     players[consoleplayer].didsecret = true;
1620 
1621   if (gamemode == commercial)
1622     {
1623       switch (gamemap)
1624         {
1625         case 15:
1626         case 31:
1627           if (!secretexit)
1628             break;
1629         case 6:
1630         case 11:
1631         case 20:
1632         case 30:
1633           F_StartFinale ();
1634           break;
1635         }
1636     }
1637   else if (gamemap == 8)
1638     gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff
1639 }
1640 
G_DoWorldDone(void)1641 void G_DoWorldDone (void)
1642 {
1643   idmusnum = -1;             //jff 3/17/98 allow new level's music to be loaded
1644   gamestate = GS_LEVEL;
1645   gamemap = wminfo.next+1;
1646   G_DoLoadLevel();
1647   gameaction = ga_nothing;
1648   AM_clearMarks();           //jff 4/12/98 clear any marks on the automap
1649   e6y_G_DoWorldDone();//e6y
1650 }
1651 
1652 // killough 2/28/98: A ridiculously large number
1653 // of players, the most you'll ever need in a demo
1654 // or savegame. This is used to prevent problems, in
1655 // case more players in a game are supported later.
1656 
1657 #define MIN_MAXPLAYERS 32
1658 
1659 extern dboolean setsizeneeded;
1660 
1661 //CPhipps - savename variable redundant
1662 
1663 /* killough 12/98:
1664  * This function returns a signature for the current wad.
1665  * It is used to distinguish between wads, for the purposes
1666  * of savegame compatibility warnings, and options lookups.
1667  */
1668 
G_UpdateSignature(uint_64_t s,const char * name)1669 static uint_64_t G_UpdateSignature(uint_64_t s, const char *name)
1670 {
1671   int i, lump = W_CheckNumForName(name);
1672   if (lump != -1 && (i = lump+10) < numlumps)
1673     do
1674       {
1675   int size = W_LumpLength(i);
1676   const byte *p = W_CacheLumpNum(i);
1677   while (size--)
1678     s <<= 1, s += *p++;
1679   W_UnlockLumpNum(i);
1680       }
1681     while (--i > lump);
1682   return s;
1683 }
1684 
G_Signature(void)1685 static uint_64_t G_Signature(void)
1686 {
1687   static uint_64_t s = 0;
1688   static dboolean computed = false;
1689   char name[9];
1690   int episode, map;
1691 
1692   if (!computed) {
1693    computed = true;
1694    if (gamemode == commercial)
1695     for (map = haswolflevels ? 32 : 30; map; map--)
1696       sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name);
1697    else
1698     for (episode = gamemode==retail ? 4 :
1699      gamemode==shareware ? 1 : 3; episode; episode--)
1700       for (map = 9; map; map--)
1701   sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name);
1702   }
1703   return s;
1704 }
1705 
1706 //
1707 // killough 5/15/98: add forced loadgames, which allow user to override checks
1708 //
1709 
G_ForcedLoadGame(void)1710 void G_ForcedLoadGame(void)
1711 {
1712   // CPhipps - net loadgames are always forced, so we only reach here
1713   //  in single player
1714   gameaction = ga_loadgame;
1715   forced_loadgame = true;
1716 }
1717 
1718 // killough 3/16/98: add slot info
1719 // killough 5/15/98: add command-line
G_LoadGame(int slot,dboolean command)1720 void G_LoadGame(int slot, dboolean command)
1721 {
1722   if (!demoplayback && !command) {
1723     // CPhipps - handle savegame filename in G_DoLoadGame
1724     //         - Delay load so it can be communicated in net game
1725     //         - store info in special_event
1726     special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) |
1727       ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1728     forced_loadgame = netgame; // CPhipps - always force load netgames
1729   } else {
1730     // Do the old thing, immediate load
1731     gameaction = ga_loadgame;
1732     forced_loadgame = false;
1733     savegameslot = slot;
1734     demoplayback = false;
1735     // Don't stay in netgame state if loading single player save
1736     // while watching multiplayer demo
1737     netgame = false;
1738   }
1739   command_loadgame = command;
1740   R_SmoothPlaying_Reset(NULL); // e6y
1741 }
1742 
1743 // killough 5/15/98:
1744 // Consistency Error when attempting to load savegame.
1745 
G_LoadGameErr(const char * msg)1746 static void G_LoadGameErr(const char *msg)
1747 {
1748   Z_Free(savebuffer);                // Free the savegame buffer
1749   M_ForcedLoadGame(msg);             // Print message asking for 'Y' to force
1750   if (command_loadgame)              // If this was a command-line -loadgame
1751     {
1752       D_StartTitle();                // Start the title screen
1753       gamestate = GS_DEMOSCREEN;     // And set the game state accordingly
1754     }
1755 }
1756 
1757 // CPhipps - size of version header
1758 #define VERSIONSIZE   16
1759 
1760 const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] =
1761 { "Doom v1.2", "Doom v1.666", "Doom/Doom2 v1.9", "Ultimate Doom/Doom95", "Final Doom",
1762   "early DosDoom", "TASDoom", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+",
1763   "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6",
1764   "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom"  };
1765 
1766 // comp_options_by_version removed - see G_Compatibility
1767 
1768 static byte map_old_comp_levels[] =
1769 { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
1770 
1771 static const struct {
1772   int comp_level;
1773   const char* ver_printf;
1774   int version;
1775 } version_headers[] = {
1776   /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since
1777    *  the file format is unchanged. */
1778   { prboom_3_compatibility, "PrBoom %d", 210},
1779   { prboom_5_compatibility, "PrBoom %d", 211},
1780   { prboom_6_compatibility, "PrBoom %d", 212}
1781   //e6y
1782   ,{ doom_12_compatibility,  "PrBoom %d", 100}
1783   ,{ doom_1666_compatibility,"PrBoom %d", 101}
1784   ,{ doom2_19_compatibility, "PrBoom %d", 102}
1785   ,{ ultdoom_compatibility,  "PrBoom %d", 103}
1786   ,{ finaldoom_compatibility,"PrBoom %d", 104}
1787   ,{ dosdoom_compatibility,  "PrBoom %d", 105}
1788   ,{ tasdoom_compatibility,  "PrBoom %d", 106}
1789   ,{ boom_compatibility_compatibility, "PrBoom %d", 107}
1790   ,{ boom_201_compatibility, "PrBoom %d", 108}
1791   ,{ boom_202_compatibility, "PrBoom %d", 109}
1792   ,{ lxdoom_1_compatibility, "PrBoom %d", 110}
1793   ,{ mbf_compatibility, "PrBoom %d", 111}
1794   ,{ prboom_2_compatibility, "PrBoom %d", 113}
1795 };
1796 
1797 static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]);
1798 
1799 //e6y
GetPackageVersion(void)1800 unsigned int GetPackageVersion(void)
1801 {
1802   static unsigned int PACKAGEVERSION = 0;
1803 
1804   //e6y: "2.4.8.2" -> 0x02040802
1805   if (PACKAGEVERSION == 0)
1806   {
1807     int b[4], i, k = 1;
1808     memset(b, 0, sizeof(b));
1809     sscanf(VERSION, "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]);
1810     for (i = 3; i >= 0; i--, k *= 256)
1811     {
1812 #ifdef RANGECHECK
1813       if (b[i] >= 256)
1814         I_Error("Wrong version number of package: %s", VERSION);
1815 #endif
1816       PACKAGEVERSION += b[i] * k;
1817     }
1818   }
1819   return PACKAGEVERSION;
1820 }
1821 
1822 //==========================================================================
1823 //
1824 // RecalculateDrawnSubsectors
1825 //
1826 // In case the subsector data is unusable this function tries to reconstruct
1827 // if from the linedefs' ML_MAPPED info.
1828 //
1829 //==========================================================================
1830 
RecalculateDrawnSubsectors(void)1831 void RecalculateDrawnSubsectors(void)
1832 {
1833 #ifdef GL_DOOM
1834   int i, j;
1835 
1836   for (i = 0; i < numsubsectors; i++)
1837   {
1838     subsector_t *sub = &subsectors[i];
1839     seg_t *seg = &segs[sub->firstline];
1840     for (j = 0; j < sub->numlines; j++, seg++)
1841     {
1842       if (seg->linedef->flags & ML_MAPPED)
1843       {
1844         map_subsectors[i] = 1;
1845       }
1846     }
1847   }
1848 
1849   gld_ResetTexturedAutomap();
1850 #endif
1851 }
1852 
G_DoLoadGame(void)1853 void G_DoLoadGame(void)
1854 {
1855   int  length, i;
1856   // CPhipps - do savegame filename stuff here
1857   char name[PATH_MAX+1];     // killough 3/22/98
1858   int savegame_compatibility = -1;
1859   //e6y: numeric version number of package should be zero before initializing from savegame
1860   unsigned int packageversion = 0;
1861 
1862   G_SaveGameName(name,sizeof(name),savegameslot, demoplayback);
1863 
1864   gameaction = ga_nothing;
1865 
1866   length = M_ReadFile(name, &savebuffer);
1867   if (length<=0)
1868     I_Error("Couldn't read file %s: %s", name, "(Unknown Error)");
1869   save_p = savebuffer + SAVESTRINGSIZE;
1870 
1871   // CPhipps - read the description field, compare with supported ones
1872   for (i=0; (size_t)i<num_version_headers; i++) {
1873     char vcheck[VERSIONSIZE];
1874     // killough 2/22/98: "proprietary" version string :-)
1875     sprintf (vcheck, version_headers[i].ver_printf, version_headers[i].version);
1876 
1877     if (!strncmp((char*)save_p, vcheck, VERSIONSIZE)) {
1878       savegame_compatibility = version_headers[i].comp_level;
1879       break;
1880     }
1881   }
1882   if (savegame_compatibility == -1) {
1883     if (forced_loadgame) {
1884       savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1;
1885     } else {
1886       G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
1887       return;
1888     }
1889   }
1890 
1891   save_p += VERSIONSIZE;
1892 
1893   // CPhipps - always check savegames even when forced,
1894   //  only print a warning if forced
1895   {  // killough 3/16/98: check lump name checksum (independent of order)
1896     uint_64_t checksum = 0;
1897 
1898     checksum = G_Signature();
1899 
1900     if (memcmp(&checksum, save_p, sizeof checksum)) {
1901       if (!forced_loadgame) {
1902         char *msg = malloc(strlen((char*)save_p + sizeof checksum) + 128);
1903         strcpy(msg,"Incompatible Savegame!!!\n");
1904         if (save_p[sizeof checksum])
1905           strcat(strcat(msg,"Wads expected:\n\n"), (char*)save_p + sizeof checksum);
1906         strcat(msg, "\nAre you sure?");
1907         G_LoadGameErr(msg);
1908         free(msg);
1909         return;
1910       } else
1911   lprintf(LO_WARN, "G_DoLoadGame: Incompatible savegame\n");
1912     }
1913     save_p += sizeof checksum;
1914    }
1915 
1916   save_p += strlen((char*)save_p)+1;
1917 
1918   //e6y: check on new savegame format
1919   if (!memcmp(NEWFORMATSIG, save_p, strlen(NEWFORMATSIG)))
1920   {
1921     save_p += strlen(NEWFORMATSIG);
1922     memcpy(&packageversion, save_p, sizeof packageversion);
1923     save_p += sizeof packageversion;
1924   }
1925   //e6y: let's show the warning if savegame is from the previous version of prboom
1926   if (packageversion != GetPackageVersion())
1927   {
1928     if (!forced_loadgame)
1929     {
1930       G_LoadGameErr("Incompatible Savegame version!!!\n\nAre you sure?");
1931       return;
1932     } else
1933       lprintf(LO_WARN, "G_DoLoadGame: Incompatible savegame version\n");
1934   }
1935 
1936   compatibility_level = (savegame_compatibility >= prboom_4_compatibility) ? *save_p : savegame_compatibility;
1937   if (savegame_compatibility < prboom_6_compatibility)
1938     compatibility_level = map_old_comp_levels[compatibility_level];
1939   save_p++;
1940 
1941   gameskill = *save_p++;
1942   gameepisode = *save_p++;
1943   gamemap = *save_p++;
1944 
1945   for (i=0 ; i<MAXPLAYERS ; i++)
1946     playeringame[i] = *save_p++;
1947   save_p += MIN_MAXPLAYERS-MAXPLAYERS;         // killough 2/28/98
1948 
1949   idmusnum = *save_p++;           // jff 3/17/98 restore idmus music
1950   if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte
1951 
1952   /* killough 3/1/98: Read game options
1953    * killough 11/98: move down to here
1954    */
1955   // Avoid assignment of const to non-const: add the difference
1956   // between the updated and original pointer onto the original
1957   save_p += (G_ReadOptions(save_p) - save_p);
1958 
1959   // load a base level
1960   G_InitNew (gameskill, gameepisode, gamemap);
1961 
1962   /* get the times - killough 11/98: save entire word */
1963   memcpy(&leveltime, save_p, sizeof leveltime);
1964   save_p += sizeof leveltime;
1965 
1966   /* cph - total episode time */
1967   //e6y: total level times are always saved since 2.4.8.1
1968   memcpy(&totalleveltimes, save_p, sizeof totalleveltimes);
1969   save_p += sizeof totalleveltimes;
1970 
1971   // killough 11/98: load revenant tracer state
1972   basetic = gametic - *save_p++;
1973 
1974   // dearchive all the modifications
1975   P_MapStart();
1976   P_UnArchivePlayers ();
1977   P_UnArchiveWorld ();
1978   P_UnArchiveThinkers ();
1979   P_UnArchiveSpecials ();
1980   P_UnArchiveRNG ();    // killough 1/18/98: load RNG information
1981   P_UnArchiveMap ();    // killough 1/22/98: load automap information
1982   P_MapEnd();
1983   R_ActivateSectorInterpolations();//e6y
1984   R_SmoothPlaying_Reset(NULL); // e6y
1985 
1986   if (musinfo.current_item != -1)
1987   {
1988     S_ChangeMusInfoMusic(musinfo.current_item, true);
1989   }
1990 
1991   RecalculateDrawnSubsectors();
1992 
1993   if (*save_p != 0xe6)
1994     I_Error ("G_DoLoadGame: Bad savegame");
1995 
1996   // done
1997   Z_Free (savebuffer);
1998 
1999   if (setsizeneeded)
2000     R_ExecuteSetViewSize ();
2001 
2002   // draw the pattern into the back screen
2003   R_FillBackScreen ();
2004 
2005   /* killough 12/98: support -recordfrom and -loadgame -playdemo */
2006   if (!command_loadgame)
2007     singledemo = false;  /* Clear singledemo flag if loading from menu */
2008   else
2009     if (singledemo) {
2010       gameaction = ga_loadgame; /* Mark that we're loading a game before demo */
2011       G_DoPlayDemo();           /* This will detect it and won't reinit level */
2012     } else /* Command line + record means it's a recordfrom */
2013       if (demorecording)
2014         G_BeginRecording();
2015 }
2016 
2017 //
2018 // G_SaveGame
2019 // Called by the menu task.
2020 // Description is a 24 byte text string
2021 //
2022 
G_SaveGame(int slot,char * description)2023 void G_SaveGame(int slot, char *description)
2024 {
2025   strcpy(savedescription, description);
2026   if (demoplayback) {
2027     /* cph - We're doing a user-initiated save game while a demo is
2028      * running so, go outside normal mechanisms
2029      */
2030     savegameslot = slot;
2031     G_DoSaveGame(true);
2032   }
2033   // CPhipps - store info in special_event
2034   special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) |
2035     ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
2036 #ifdef HAVE_NET
2037   D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription);
2038 #endif
2039 }
2040 
2041 // Check for overrun and realloc if necessary -- Lee Killough 1/22/98
2042 void (CheckSaveGame)(size_t size, const char* file, int line)
2043 {
2044   size_t pos = save_p - savebuffer;
2045 
2046 #ifdef RANGECHECK
2047   /* cph 2006/08/07 - after-the-fact sanity checking of CheckSaveGame calls */
2048   static size_t prev_check;
2049   static const char* prevf;
2050   static int prevl;
2051 
2052   if (pos > prev_check)
2053     I_Error("CheckSaveGame at %s:%d called for insufficient buffer (%u < %u)", prevf, prevl, prev_check, pos);
2054   prev_check = size + pos;
2055   prevf = file;
2056   prevl = line;
2057 #endif
2058 
2059   size += 1024;  // breathing room
2060   if (pos+size > savegamesize)
2061     save_p = (savebuffer = realloc(savebuffer,
2062            savegamesize += (size+1023) & ~1023)) + pos;
2063 }
2064 
2065 /* killough 3/22/98: form savegame name in one location
2066  * (previously code was scattered around in multiple places)
2067  * cph - Avoid possible buffer overflow problems by passing
2068  * size to this function and using snprintf */
2069 
G_SaveGameName(char * name,size_t size,int slot,dboolean demoplayback)2070 void G_SaveGameName(char *name, size_t size, int slot, dboolean demoplayback)
2071 {
2072   const char* sgn = demoplayback ? "demosav" : savegamename;
2073   SNPRINTF(name, size, "%s/%s%d.dsg", basesavegame, sgn, slot);
2074 }
2075 
G_DoSaveGame(dboolean menu)2076 static void G_DoSaveGame (dboolean menu)
2077 {
2078   char name[PATH_MAX+1];
2079   char name2[VERSIONSIZE];
2080   char *description;
2081   int  i;
2082   //e6y: numeric version number of package
2083   unsigned int packageversion = GetPackageVersion();
2084 
2085   gameaction = ga_nothing; // cph - cancel savegame at top of this function,
2086     // in case later problems cause a premature exit
2087 
2088   G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu);
2089 
2090   description = savedescription;
2091 
2092   save_p = savebuffer = malloc(savegamesize);
2093 
2094   CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint_64_t));
2095   memcpy (save_p, description, SAVESTRINGSIZE);
2096   save_p += SAVESTRINGSIZE;
2097   memset (name2,0,sizeof(name2));
2098 
2099   // CPhipps - scan for the version header
2100   for (i=0; (size_t)i<num_version_headers; i++)
2101     if (version_headers[i].comp_level == best_compatibility) {
2102       // killough 2/22/98: "proprietary" version string :-)
2103       sprintf (name2,version_headers[i].ver_printf,version_headers[i].version);
2104       memcpy (save_p, name2, VERSIONSIZE);
2105       i = num_version_headers+1;
2106     }
2107 
2108   save_p += VERSIONSIZE;
2109 
2110   { /* killough 3/16/98, 12/98: store lump name checksum */
2111     uint_64_t checksum = G_Signature();
2112     memcpy(save_p, &checksum, sizeof checksum);
2113     save_p += sizeof checksum;
2114   }
2115 
2116   // killough 3/16/98: store pwad filenames in savegame
2117   {
2118     // CPhipps - changed for new wadfiles handling
2119     size_t i;
2120     for (i = 0; i<numwadfiles; i++)
2121       {
2122         const char *const w = wadfiles[i].name;
2123         CheckSaveGame(strlen(w)+2);
2124         strcpy((char*)save_p, w);
2125         save_p += strlen((char*)save_p);
2126         *save_p++ = '\n';
2127       }
2128     *save_p++ = 0;
2129   }
2130 
2131   CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+14+strlen(NEWFORMATSIG)+sizeof packageversion);
2132 
2133   //e6y: saving of the version number of package
2134   strcpy((char*)save_p, NEWFORMATSIG);
2135   save_p += strlen(NEWFORMATSIG);
2136   memcpy(save_p, &packageversion, sizeof packageversion);
2137   save_p += sizeof packageversion;
2138 
2139   *save_p++ = compatibility_level;
2140 
2141   *save_p++ = gameskill;
2142   *save_p++ = gameepisode;
2143   *save_p++ = gamemap;
2144 
2145   for (i=0 ; i<MAXPLAYERS ; i++)
2146     *save_p++ = playeringame[i];
2147 
2148   for (;i<MIN_MAXPLAYERS;i++)         // killough 2/28/98
2149     *save_p++ = 0;
2150 
2151   *save_p++ = idmusnum;               // jff 3/17/98 save idmus state
2152 
2153   save_p = G_WriteOptions(save_p);    // killough 3/1/98: save game options
2154 
2155   /* cph - FIXME - endianness? */
2156   /* killough 11/98: save entire word */
2157   memcpy(save_p, &leveltime, sizeof leveltime);
2158   save_p += sizeof leveltime;
2159 
2160   /* cph - total episode time */
2161   //e6y: always saved since 2.4.8
2162   memcpy(save_p, &totalleveltimes, sizeof totalleveltimes);
2163   save_p += sizeof totalleveltimes;
2164 
2165   // killough 11/98: save revenant tracer state
2166   *save_p++ = (gametic-basetic) & 255;
2167 
2168   // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
2169   Z_CheckHeap();
2170   P_ArchivePlayers();
2171   Z_CheckHeap();
2172 
2173   // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the
2174   // indices can be used by P_ArchiveWorld when the sectors are saved.
2175   // This is so we can save the index of the mobj_t of the thinker that
2176   // caused a sound, referenced by sector_t->soundtarget.
2177   P_ThinkerToIndex();
2178 
2179   P_ArchiveWorld();
2180   Z_CheckHeap();
2181   P_ArchiveThinkers();
2182 
2183   // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply
2184   // for symmetry with the P_ThinkerToIndex call above.
2185 
2186   P_IndexToThinker();
2187 
2188   Z_CheckHeap();
2189   P_ArchiveSpecials();
2190   P_ArchiveRNG();    // killough 1/18/98: save RNG information
2191   Z_CheckHeap();
2192   P_ArchiveMap();    // killough 1/22/98: save automap information
2193 
2194   *save_p++ = 0xe6;   // consistancy marker
2195 
2196   Z_CheckHeap();
2197   doom_printf( "%s", M_WriteFile(name, savebuffer, save_p - savebuffer)
2198          ? s_GGSAVED /* Ty - externalised */
2199          : "Game save failed!"); // CPhipps - not externalised
2200 
2201   free(savebuffer);  // killough
2202   savebuffer = save_p = NULL;
2203 
2204   savedescription[0] = 0;
2205 }
2206 
2207 static skill_t d_skill;
2208 static int     d_episode;
2209 static int     d_map;
2210 
G_DeferedInitNew(skill_t skill,int episode,int map)2211 void G_DeferedInitNew(skill_t skill, int episode, int map)
2212 {
2213   d_skill = skill;
2214   d_episode = episode;
2215   d_map = map;
2216   gameaction = ga_newgame;
2217 }
2218 
2219 /* cph -
2220  * G_Compatibility
2221  *
2222  * Initialises the comp[] array based on the compatibility_level
2223  * For reference, MBF did:
2224  * for (i=0; i < COMP_TOTAL; i++)
2225  *   comp[i] = compatibility;
2226  *
2227  * Instead, we have a lookup table showing at what version a fix was
2228  *  introduced, and made optional (replaces comp_options_by_version)
2229  */
2230 
G_Compatibility(void)2231 void G_Compatibility(void)
2232 {
2233   static const struct {
2234     complevel_t fix; // level at which fix/change was introduced
2235     complevel_t opt; // level at which fix/change was made optional
2236   } levels[] = {
2237     // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only
2238     { mbf_compatibility, mbf_compatibility },
2239     // comp_dropoff - MBF encourages things to drop off of overhangs
2240     { mbf_compatibility, mbf_compatibility },
2241     // comp_vile - original Doom archville bugs like ghosts
2242     { boom_compatibility, mbf_compatibility },
2243     // comp_pain - original Doom limits Pain Elementals from spawning too many skulls
2244     { boom_compatibility, mbf_compatibility },
2245     // comp_skull - original Doom let skulls be spit through walls by Pain Elementals
2246     { boom_compatibility, mbf_compatibility },
2247     // comp_blazing - original Doom duplicated blazing door sound
2248     { boom_compatibility, mbf_compatibility },
2249     // e6y: "Tagged doors don't trigger special lighting" handled wrong
2250     // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943
2251     // comp_doorlight - MBF made door lighting changes more gradual
2252     { boom_compatibility, mbf_compatibility },
2253     // comp_model - improvements to the game physics
2254     { boom_compatibility, mbf_compatibility },
2255     // comp_god - fixes to God mode
2256     { boom_compatibility, mbf_compatibility },
2257     // comp_falloff - MBF encourages things to drop off of overhangs
2258     { mbf_compatibility, mbf_compatibility },
2259     // comp_floors - fixes for moving floors bugs
2260     { boom_compatibility_compatibility, mbf_compatibility },
2261     // comp_skymap
2262     { mbf_compatibility, mbf_compatibility },
2263     // comp_pursuit - MBF AI change, limited pursuit?
2264     { mbf_compatibility, mbf_compatibility },
2265     // comp_doorstuck - monsters stuck in doors fix
2266     { boom_202_compatibility, mbf_compatibility },
2267     // comp_staylift - MBF AI change, monsters try to stay on lifts
2268     { mbf_compatibility, mbf_compatibility },
2269     // comp_zombie - prevent dead players triggering stuff
2270     { lxdoom_1_compatibility, mbf_compatibility },
2271     // comp_stairs - see p_floor.c
2272     { boom_202_compatibility, mbf_compatibility },
2273     // comp_infcheat - FIXME
2274     { mbf_compatibility, mbf_compatibility },
2275     // comp_zerotags - allow zero tags in wads */
2276     { boom_compatibility, mbf_compatibility },
2277     // comp_moveblock - enables keygrab and mancubi shots going thru walls
2278     { lxdoom_1_compatibility, prboom_2_compatibility },
2279     // comp_respawn - objects which aren't on the map at game start respawn at (0,0)
2280     { prboom_2_compatibility, prboom_2_compatibility },
2281     // comp_sound - see s_sound.c
2282     { boom_compatibility_compatibility, prboom_3_compatibility },
2283     // comp_666 - emulate pre-Ultimate BossDeath behaviour
2284     { ultdoom_compatibility, prboom_4_compatibility },
2285     // comp_soul - enables lost souls bouncing (see P_ZMovement)
2286     { prboom_4_compatibility, prboom_4_compatibility },
2287     // comp_maskedanim - 2s mid textures don't animate
2288     { doom_1666_compatibility, prboom_4_compatibility },
2289     //e6y
2290     // comp_ouchface - Use Doom's buggy "Ouch" face code
2291     { prboom_1_compatibility, prboom_6_compatibility },
2292     // comp_maxhealth - Max Health in DEH applies only to potions
2293     { boom_compatibility_compatibility, prboom_6_compatibility },
2294     // comp_translucency - No predefined translucency for some things
2295     { boom_compatibility_compatibility, prboom_6_compatibility },
2296   };
2297   unsigned int i;
2298 
2299   if (sizeof(levels)/sizeof(*levels) != COMP_NUM)
2300     I_Error("G_Compatibility: consistency error");
2301 
2302   for (i = 0; i < sizeof(levels)/sizeof(*levels); i++)
2303     if (compatibility_level < levels[i].opt)
2304       comp[i] = (compatibility_level < levels[i].fix);
2305 
2306   e6y_G_Compatibility();//e6y
2307 
2308   if (!mbf_features) {
2309     monster_infighting = 1;
2310     monster_backing = 0;
2311     monster_avoid_hazards = 0;
2312     monster_friction = 0;
2313     help_friends = 0;
2314 
2315 #ifdef DOGS
2316     dogs = 0;
2317     dog_jumping = 0;
2318 #endif
2319 
2320     monkeys = 0;
2321   }
2322 }
2323 
2324 #ifdef DOGS
2325 /* killough 7/19/98: Marine's best friend :) */
G_GetHelpers(void)2326 static int G_GetHelpers(void)
2327 {
2328   int j = M_CheckParm ("-dog");
2329 
2330   if (!j)
2331     j = M_CheckParm ("-dogs");
2332   return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs;
2333 }
2334 #endif
2335 
2336 // killough 3/1/98: function to reload all the default parameter
2337 // settings before a new game begins
2338 
G_ReloadDefaults(void)2339 void G_ReloadDefaults(void)
2340 {
2341   // killough 3/1/98: Initialize options based on config file
2342   // (allows functions above to load different values for demos
2343   // and savegames without messing up defaults).
2344 
2345   weapon_recoil = default_weapon_recoil;    // weapon recoil
2346 
2347   player_bobbing = default_player_bobbing;  // whether player bobs or not
2348 
2349   /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */
2350   variable_friction = default_variable_friction;
2351   allow_pushers     = default_allow_pushers;
2352 
2353 
2354   monsters_remember = default_monsters_remember;   // remember former enemies
2355 
2356   monster_infighting = default_monster_infighting; // killough 7/19/98
2357 
2358 #ifdef DOGS
2359   dogs = netgame ? 0 : G_GetHelpers();             // killough 7/19/98
2360   dog_jumping = default_dog_jumping;
2361 #endif
2362 
2363   distfriend = default_distfriend;                 // killough 8/8/98
2364 
2365   monster_backing = default_monster_backing;     // killough 9/8/98
2366 
2367   monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98
2368 
2369   monster_friction = default_monster_friction;     // killough 10/98
2370 
2371   help_friends = default_help_friends;             // killough 9/9/98
2372 
2373   monkeys = default_monkeys;
2374 
2375   // jff 1/24/98 reset play mode to command line spec'd version
2376   // killough 3/1/98: moved to here
2377   respawnparm = clrespawnparm;
2378   fastparm = clfastparm;
2379   nomonsters = clnomonsters;
2380 
2381   //jff 3/24/98 set startskill from defaultskill in config file, unless
2382   // it has already been set by a -skill parameter
2383   if (startskill==sk_none)
2384     startskill = (skill_t)(defaultskill-1);
2385 
2386   demoplayback = false;
2387   singledemo = false;            // killough 9/29/98: don't stop after 1 demo
2388   netdemo = false;
2389 
2390   // killough 2/21/98:
2391   memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1));
2392 
2393   consoleplayer = 0;
2394 
2395   compatibility_level = default_compatibility_level;
2396   {
2397     int i = M_CheckParm("-complevel");
2398     if (i && (1+i) < myargc) {
2399       int l = atoi(myargv[i+1]);;
2400       if (l >= -1) compatibility_level = l;
2401     }
2402   }
2403   if (compatibility_level == -1)
2404     compatibility_level = best_compatibility;
2405 
2406   if (mbf_features)
2407     memcpy(comp, default_comp, sizeof comp);
2408   G_Compatibility();
2409 
2410   // killough 3/31/98, 4/5/98: demo sync insurance
2411   demo_insurance = default_demo_insurance == 1;
2412 
2413   rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
2414 }
2415 
G_DoNewGame(void)2416 void G_DoNewGame (void)
2417 {
2418   // e6y: allow new level's music to be loaded
2419   idmusnum = -1;
2420 
2421   G_ReloadDefaults();            // killough 3/1/98
2422   netgame = false;               // killough 3/29/98
2423   deathmatch = false;
2424   G_InitNew (d_skill, d_episode, d_map);
2425   gameaction = ga_nothing;
2426 
2427   //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
2428   ST_Start();
2429   walkcamera.type=0; //e6y
2430 }
2431 
2432 // killough 4/10/98: New function to fix bug which caused Doom
2433 // lockups when idclev was used in conjunction with -fast.
2434 
G_SetFastParms(int fast_pending)2435 void G_SetFastParms(int fast_pending)
2436 {
2437   static int fast = 0;            // remembers fast state
2438   int i;
2439   if (fast != fast_pending) {     /* only change if necessary */
2440     if ((fast = fast_pending))
2441       {
2442         for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2443           if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98
2444             states[i].tics >>= 1;  // don't change 1->0 since it causes cycles
2445         mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
2446         mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
2447         mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
2448       }
2449     else
2450       {
2451         for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2452           states[i].tics <<= 1;
2453         mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
2454         mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
2455         mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
2456       }
2457   }
2458 }
2459 
2460 //
2461 // G_InitNew
2462 // Can be called by the startup code or the menu task,
2463 // consoleplayer, displayplayer, playeringame[] should be set.
2464 //
2465 
G_InitNew(skill_t skill,int episode,int map)2466 void G_InitNew(skill_t skill, int episode, int map)
2467 {
2468   int i;
2469 
2470   // e6y
2471   // This variable is for correct checking for upper limit of episode.
2472   // Ultimate Doom, Final Doom and Doom95 have
2473   // "if (episode == 0) episode = 3/4" check instead of
2474   // "if (episode > 3/4) episode = 3/4"
2475   dboolean fake_episode_check =
2476     compatibility_level == ultdoom_compatibility ||
2477     compatibility_level == finaldoom_compatibility;
2478 
2479   if (paused)
2480     {
2481       paused = false;
2482       S_ResumeSound();
2483     }
2484 
2485   if (skill > sk_nightmare)
2486     skill = sk_nightmare;
2487 
2488   if (episode < 1)
2489     episode = 1;
2490 
2491   //e6y: We need to remove the fourth episode for pre-ultimate complevels.
2492   if (compatibility_level < ultdoom_compatibility && episode > 3)
2493   {
2494     episode = 3;
2495   }
2496 
2497   //e6y: DosDoom has only this check
2498   if (compatibility_level == dosdoom_compatibility)
2499   {
2500     if (gamemode == shareware)
2501       episode = 1; // only start episode 1 on shareware
2502   }
2503   else
2504   if (gamemode == retail)
2505     {
2506       // e6y: Ability to play any episode with Ultimate Doom,
2507       // Final Doom or Doom95 compatibility and -warp command line switch
2508       // E5M1 from 2002ado.wad is an example.
2509       // Now you can play it with "-warp 5 1 -complevel 3".
2510       // 'Vanilla' Ultimate Doom executable also allows it.
2511       if (fake_episode_check ? episode == 0 : episode > 4)
2512         episode = 4;
2513     }
2514   else
2515     if (gamemode == shareware)
2516       {
2517         if (episode > 1)
2518           episode = 1; // only start episode 1 on shareware
2519       }
2520     else
2521       // e6y: Ability to play any episode with Ultimate Doom,
2522       // Final Doom or Doom95 compatibility and -warp command line switch
2523       if (fake_episode_check ? episode == 0 : episode > 3)
2524         episode = 3;
2525 
2526   if (map < 1)
2527     map = 1;
2528   if (map > 9 && gamemode != commercial)
2529     map = 9;
2530 
2531   G_SetFastParms(fastparm || skill == sk_nightmare);  // killough 4/10/98
2532 
2533   M_ClearRandom();
2534 
2535   respawnmonsters = skill == sk_nightmare || respawnparm;
2536 
2537   // force players to be initialized upon first level load
2538   for (i=0 ; i<MAXPLAYERS ; i++)
2539     players[i].playerstate = PST_REBORN;
2540 
2541   usergame = true;                // will be set false if a demo
2542   paused = false;
2543   automapmode &= ~am_active;
2544   gameepisode = episode;
2545   gamemap = map;
2546   gameskill = skill;
2547 
2548   totalleveltimes = 0; // cph
2549 
2550   //jff 4/16/98 force marks on automap cleared every new level start
2551   AM_clearMarks();
2552 
2553   G_DoLoadLevel ();
2554 }
2555 
2556 //
2557 // DEMO RECORDING
2558 //
2559 
G_ReadOneTick(ticcmd_t * cmd,const byte ** data_p)2560 void G_ReadOneTick(ticcmd_t* cmd, const byte **data_p)
2561 {
2562   unsigned char at = 0; // e6y: for tasdoom demo format
2563 
2564   cmd->forwardmove = (signed char)(*(*data_p)++);
2565   cmd->sidemove = (signed char)(*(*data_p)++);
2566   if (!longtics)
2567   {
2568     cmd->angleturn = ((unsigned char)(at = *(*data_p)++))<<8;
2569   }
2570   else
2571   {
2572     unsigned int lowbyte = (unsigned char)(*(*data_p)++);
2573     cmd->angleturn = (((signed int)(*(*data_p)++))<<8) + lowbyte;
2574   }
2575   cmd->buttons = (unsigned char)(*(*data_p)++);
2576 
2577   // e6y: ability to play tasdoom demos directly
2578   if (compatibility_level == tasdoom_compatibility)
2579   {
2580     signed char tmp = cmd->forwardmove;
2581     cmd->forwardmove = cmd->sidemove;
2582     cmd->sidemove = (signed char)at;
2583     cmd->angleturn = ((unsigned char)cmd->buttons)<<8;
2584     cmd->buttons = (byte)tmp;
2585   }
2586 }
2587 
G_ReadDemoTiccmd(ticcmd_t * cmd)2588 void G_ReadDemoTiccmd (ticcmd_t* cmd)
2589 {
2590   demo_curr_tic++;
2591 
2592   if (*demo_p == DEMOMARKER)
2593   {
2594     G_CheckDemoStatus();      // end of demo data stream
2595   }
2596   else if (demoplayback && demo_p + bytes_per_tic > demobuffer + demolength)
2597   {
2598     lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n");
2599     G_CheckDemoStatus();
2600   }
2601   else
2602   {
2603     G_ReadOneTick(cmd, &demo_p);
2604   }
2605 }
2606 
2607 /* Demo limits removed -- killough
2608  * cph - record straight to file
2609  */
G_WriteDemoTiccmd(ticcmd_t * cmd)2610 void G_WriteDemoTiccmd (ticcmd_t* cmd)
2611 {
2612   char buf[5];
2613   char *p = buf;
2614 
2615   if (compatibility_level == tasdoom_compatibility)
2616   {
2617     *p++ = cmd->buttons;
2618     *p++ = cmd->forwardmove;
2619     *p++ = cmd->sidemove;
2620     *p++ = (cmd->angleturn+128)>>8;
2621   } else {
2622 
2623   *p++ = cmd->forwardmove;
2624   *p++ = cmd->sidemove;
2625   if (!longtics) {
2626     *p++ = (cmd->angleturn+128)>>8;
2627   } else {
2628     signed short a = cmd->angleturn;
2629     *p++ = a & 0xff;
2630     *p++ = (a >> 8) & 0xff;
2631   }
2632   *p++ = cmd->buttons;
2633 
2634   }//e6y
2635 
2636   if (fwrite(buf, p-buf, 1, demofp) != 1)
2637     I_Error("G_WriteDemoTiccmd: error writing demo");
2638 
2639   /* cph - alias demo_p to it so we can read it back */
2640   demo_p = buf;
2641   G_ReadDemoTiccmd (cmd);         // make SURE it is exactly the same
2642 }
2643 
2644 //
2645 // G_RecordDemo
2646 //
2647 
G_RecordDemo(const char * name)2648 void G_RecordDemo (const char* name)
2649 {
2650   char demoname[PATH_MAX];
2651   usergame = false;
2652   AddDefaultExtension(strcpy(demoname, name), ".lmp");  // 1/18/98 killough
2653   demorecording = true;
2654 
2655   /* cph - Record demos straight to file
2656   * If file already exists, try to continue existing demo
2657   */
2658 
2659   demofp = NULL;
2660   if (access(demoname, F_OK) || democontinue ||
2661      (demo_compatibility && demo_overwriteexisting))
2662   {
2663     if (strlen(demoname) > 4
2664         && !strcasecmp(demoname+strlen(demoname)-4, ".wad"))
2665       I_Error("G_RecordDemo: Cowardly refusing to record over "
2666               "what appears to be a WAD. (%s)", demoname);
2667 
2668     demofp = fopen(demoname, "wb");
2669   }
2670   else
2671   {
2672     if (demo_compatibility && !demo_overwriteexisting)
2673     {
2674       I_Error("G_RecordDemo: file %s already exists", name);
2675     }
2676 
2677     demofp = fopen(demoname, "rb+");
2678     if (demofp)
2679     {
2680       int slot = -1;
2681       const byte* pos;
2682       byte buf[200];
2683       size_t len;
2684 
2685       //e6y: save all data which can be changed by G_ReadDemoHeader
2686       G_SaveRestoreGameOptions(true);
2687 
2688       /* Read the demo header for options etc */
2689       len = fread(buf, 1, sizeof(buf), demofp);
2690       pos = G_ReadDemoHeader(buf, len);
2691       if (pos)
2692       {
2693         int rc;
2694         int bytes_per_tic = longtics ? 5 : 4;
2695 
2696         fseek(demofp, pos - buf, SEEK_SET);
2697 
2698         /* Now read the demo to find the last save slot */
2699         do
2700         {
2701           byte buf[5];
2702 
2703           rc = fread(buf, 1, bytes_per_tic, demofp);
2704           if (buf[0] == DEMOMARKER || rc < bytes_per_tic-1)
2705           {
2706             break;
2707           }
2708 
2709           if (buf[bytes_per_tic-1] & BT_SPECIAL)
2710           {
2711             if ((buf[bytes_per_tic-1] & BT_SPECIALMASK) == BTS_SAVEGAME)
2712             {
2713               slot = (buf[bytes_per_tic-1] & BTS_SAVEMASK)>>BTS_SAVESHIFT;
2714             }
2715           }
2716         }
2717         while (rc == bytes_per_tic);
2718 
2719         if (slot != -1)
2720         {
2721           /* Return to the last save position, and load the relevant savegame */
2722           fseek(demofp, -rc, SEEK_CUR);
2723           G_LoadGame(slot, false);
2724           autostart = false;
2725           return;
2726         }
2727       }
2728 
2729       //demo cannot be continued
2730       fclose(demofp);
2731       if (demo_overwriteexisting)
2732       {
2733         //restoration of all data which could be changed by G_ReadDemoHeader
2734         G_SaveRestoreGameOptions(false);
2735         demofp = fopen(demoname, "wb");
2736       }
2737       else
2738       {
2739         I_Error("G_RecordDemo: No save in demo, can't continue");
2740       }
2741     }
2742   }
2743 
2744   if (!demofp)
2745   {
2746     I_Error("G_RecordDemo: failed to open %s", name);
2747   }
2748 }
2749 
2750 // These functions are used to read and write game-specific options in demos
2751 // and savegames so that demo sync is preserved and savegame restoration is
2752 // complete. Not all options (for example "compatibility"), however, should
2753 // be loaded and saved here. It is extremely important to use the same
2754 // positions as before for the variables, so if one becomes obsolete, the
2755 // byte(s) should still be skipped over or padded with 0's.
2756 // Lee Killough 3/1/98
2757 
2758 extern int forceOldBsp;
2759 
G_WriteOptions(byte * demo_p)2760 byte *G_WriteOptions(byte *demo_p)
2761 {
2762   byte *target = demo_p + GAME_OPTION_SIZE;
2763 
2764   *demo_p++ = monsters_remember;  // part of monster AI
2765 
2766   *demo_p++ = variable_friction;  // ice & mud
2767 
2768   *demo_p++ = weapon_recoil;      // weapon recoil
2769 
2770   *demo_p++ = allow_pushers;      // MT_PUSH Things
2771 
2772   *demo_p++ = 0;
2773 
2774   *demo_p++ = player_bobbing;  // whether player bobs or not
2775 
2776   // killough 3/6/98: add parameters to savegame, move around some in demos
2777   *demo_p++ = respawnparm;
2778   *demo_p++ = fastparm;
2779   *demo_p++ = nomonsters;
2780 
2781   *demo_p++ = demo_insurance;        // killough 3/31/98
2782 
2783   // killough 3/26/98: Added rngseed. 3/31/98: moved here
2784   *demo_p++ = (byte)((rngseed >> 24) & 0xff);
2785   *demo_p++ = (byte)((rngseed >> 16) & 0xff);
2786   *demo_p++ = (byte)((rngseed >>  8) & 0xff);
2787   *demo_p++ = (byte)( rngseed        & 0xff);
2788 
2789   // Options new to v2.03 begin here
2790 
2791   *demo_p++ = monster_infighting;   // killough 7/19/98
2792 
2793 #ifdef DOGS
2794   *demo_p++ = dogs;                 // killough 7/19/98
2795 #else
2796   *demo_p++ = 0;
2797 #endif
2798 
2799   *demo_p++ = 0;
2800   *demo_p++ = 0;
2801 
2802   *demo_p++ = (distfriend >> 8) & 0xff;  // killough 8/8/98
2803   *demo_p++ =  distfriend       & 0xff;  // killough 8/8/98
2804 
2805   *demo_p++ = monster_backing;         // killough 9/8/98
2806 
2807   *demo_p++ = monster_avoid_hazards;    // killough 9/9/98
2808 
2809   *demo_p++ = monster_friction;         // killough 10/98
2810 
2811   *demo_p++ = help_friends;             // killough 9/9/98
2812 
2813 #ifdef DOGS
2814   *demo_p++ = dog_jumping;
2815 #else
2816   *demo_p++ = 0;
2817 #endif
2818 
2819   *demo_p++ = monkeys;
2820 
2821   {   // killough 10/98: a compatibility vector now
2822     int i;
2823     for (i=0; i < COMP_TOTAL; i++)
2824       *demo_p++ = comp[i] != 0;
2825   }
2826 
2827   *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20
2828 
2829   //----------------
2830   // Padding at end
2831   //----------------
2832   while (demo_p < target)
2833     *demo_p++ = 0;
2834 
2835   if (demo_p != target)
2836     I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small");
2837 
2838   return target;
2839 }
2840 
2841 /* Same, but read instead of write
2842  * cph - const byte*'s
2843  */
2844 
G_ReadOptions(const byte * demo_p)2845 const byte *G_ReadOptions(const byte *demo_p)
2846 {
2847   const byte *target = demo_p + GAME_OPTION_SIZE;
2848 
2849   monsters_remember = *demo_p++;
2850 
2851   variable_friction = *demo_p;  // ice & mud
2852   demo_p++;
2853 
2854   weapon_recoil = *demo_p;       // weapon recoil
2855   demo_p++;
2856 
2857   allow_pushers = *demo_p;      // MT_PUSH Things
2858   demo_p++;
2859 
2860   demo_p++;
2861 
2862   player_bobbing = *demo_p;     // whether player bobs or not
2863   demo_p++;
2864 
2865   // killough 3/6/98: add parameters to savegame, move from demo
2866   respawnparm = *demo_p++;
2867   fastparm = *demo_p++;
2868   nomonsters = *demo_p++;
2869 
2870   demo_insurance = *demo_p++;              // killough 3/31/98
2871 
2872   // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here
2873 
2874   rngseed  = *demo_p++ & 0xff;
2875   rngseed <<= 8;
2876   rngseed += *demo_p++ & 0xff;
2877   rngseed <<= 8;
2878   rngseed += *demo_p++ & 0xff;
2879   rngseed <<= 8;
2880   rngseed += *demo_p++ & 0xff;
2881 
2882   // Options new to v2.03
2883   if (mbf_features)
2884     {
2885       monster_infighting = *demo_p++;   // killough 7/19/98
2886 
2887 #ifdef DOGS
2888       dogs = *demo_p++;                 // killough 7/19/98
2889 #else
2890       demo_p++;
2891 #endif
2892 
2893       demo_p += 2;
2894 
2895       distfriend = *demo_p++ << 8;      // killough 8/8/98
2896       distfriend+= *demo_p++;
2897 
2898       monster_backing = *demo_p++;     // killough 9/8/98
2899 
2900       monster_avoid_hazards = *demo_p++; // killough 9/9/98
2901 
2902       monster_friction = *demo_p++;      // killough 10/98
2903 
2904       help_friends = *demo_p++;          // killough 9/9/98
2905 
2906 #ifdef DOGS
2907       dog_jumping = *demo_p++;           // killough 10/98
2908 #else
2909       demo_p++;
2910 #endif
2911 
2912       monkeys = *demo_p++;
2913 
2914       {   // killough 10/98: a compatibility vector now
2915   int i;
2916   for (i=0; i < COMP_TOTAL; i++)
2917     comp[i] = *demo_p++;
2918       }
2919 
2920       forceOldBsp = *demo_p++; // cph 2002/07/20
2921     }
2922   else  /* defaults for versions <= 2.02 */
2923     {
2924       /* G_Compatibility will set these */
2925     }
2926 
2927   G_Compatibility();
2928   return target;
2929 }
2930 
G_BeginRecording(void)2931 void G_BeginRecording (void)
2932 {
2933   int i;
2934   byte *demostart, *demo_p;
2935   demostart = demo_p = malloc(1000);
2936   longtics = 0;
2937 
2938   /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */
2939   if (mbf_features) {
2940     { /* Write version code into demo */
2941       unsigned char v = 0;
2942       switch(compatibility_level) {
2943         case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed
2944         case prboom_2_compatibility: v = 210; break;
2945         case prboom_3_compatibility: v = 211; break;
2946         case prboom_4_compatibility: v = 212; break;
2947         case prboom_5_compatibility: v = 213; break;
2948         case prboom_6_compatibility:
2949 				     v = 214;
2950 				     longtics = 1;
2951 				     break;
2952         default: I_Error("G_BeginRecording: PrBoom compatibility level unrecognised?");
2953       }
2954       *demo_p++ = v;
2955     }
2956 
2957     // signature
2958     *demo_p++ = 0x1d;
2959     *demo_p++ = 'M';
2960     *demo_p++ = 'B';
2961     *demo_p++ = 'F';
2962     *demo_p++ = 0xe6;
2963     *demo_p++ = '\0';
2964 
2965     /* killough 2/22/98: save compatibility flag in new demos
2966      * cph - FIXME? MBF demos will always be not in compat. mode */
2967     *demo_p++ = 0;
2968 
2969     *demo_p++ = gameskill;
2970     *demo_p++ = gameepisode;
2971     *demo_p++ = gamemap;
2972     *demo_p++ = deathmatch;
2973     *demo_p++ = consoleplayer;
2974 
2975     demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
2976 
2977     for (i=0 ; i<MAXPLAYERS ; i++)
2978       *demo_p++ = playeringame[i];
2979 
2980     // killough 2/28/98:
2981     // We always store at least MIN_MAXPLAYERS bytes in demo, to
2982     // support enhancements later w/o losing demo compatibility
2983 
2984     for (; i<MIN_MAXPLAYERS; i++)
2985       *demo_p++ = 0;
2986 
2987   // FIXME } else if (compatibility_level >= boom_compatibility_compatibility) { //e6y
2988   } else if (compatibility_level > boom_compatibility_compatibility) {
2989     byte v = 0, c = 0; /* Nominally, version and compatibility bits */
2990     switch (compatibility_level) {
2991     case boom_compatibility_compatibility: v = 202, c = 1; break;
2992     case boom_201_compatibility: v = 201; c = 0; break;
2993     case boom_202_compatibility: v = 202, c = 0; break;
2994     default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?");
2995     }
2996     *demo_p++ = v;
2997 
2998     // signature
2999     *demo_p++ = 0x1d;
3000     *demo_p++ = 'B';
3001     *demo_p++ = 'o';
3002     *demo_p++ = 'o';
3003     *demo_p++ = 'm';
3004     *demo_p++ = 0xe6;
3005 
3006     /* CPhipps - save compatibility level in demos */
3007     *demo_p++ = c;
3008 
3009     *demo_p++ = gameskill;
3010     *demo_p++ = gameepisode;
3011     *demo_p++ = gamemap;
3012     *demo_p++ = deathmatch;
3013     *demo_p++ = consoleplayer;
3014 
3015     demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
3016 
3017     for (i=0 ; i<MAXPLAYERS ; i++)
3018       *demo_p++ = playeringame[i];
3019 
3020     // killough 2/28/98:
3021     // We always store at least MIN_MAXPLAYERS bytes in demo, to
3022     // support enhancements later w/o losing demo compatibility
3023 
3024     for (; i<MIN_MAXPLAYERS; i++)
3025       *demo_p++ = 0;
3026   } else { // cph - write old v1.9 demos (might even sync)
3027     unsigned char v = 109;
3028     longtics = M_CheckParm("-longtics");
3029     if (longtics)
3030     {
3031       v = 111;
3032     }
3033     else
3034     {
3035       switch (compatibility_level)
3036       {
3037       case doom_1666_compatibility:
3038         v = 106;
3039         break;
3040       case tasdoom_compatibility:
3041         v = 110;
3042         break;
3043       }
3044     }
3045     *demo_p++ = v;
3046     *demo_p++ = gameskill;
3047     *demo_p++ = gameepisode;
3048     *demo_p++ = gamemap;
3049     *demo_p++ = deathmatch;
3050     *demo_p++ = respawnparm;
3051     *demo_p++ = fastparm;
3052     *demo_p++ = nomonsters;
3053     *demo_p++ = consoleplayer;
3054     for (i=0; i<4; i++)  // intentionally hard-coded 4 -- killough
3055       *demo_p++ = playeringame[i];
3056   }
3057 
3058   if (fwrite(demostart, 1, demo_p-demostart, demofp) != (size_t)(demo_p-demostart))
3059     I_Error("G_BeginRecording: Error writing demo header");
3060   free(demostart);
3061 }
3062 
3063 //
3064 // G_PlayDemo
3065 //
3066 
3067 static const char *defdemoname;
3068 
G_DeferedPlayDemo(const char * name)3069 void G_DeferedPlayDemo (const char* name)
3070 {
3071   defdemoname = name;
3072   gameaction = ga_playdemo;
3073 }
3074 
3075 static int demolumpnum = -1;
3076 
G_GetOriginalDoomCompatLevel(int ver)3077 static int G_GetOriginalDoomCompatLevel(int ver)
3078 {
3079   {
3080     int lev;
3081     int i = M_CheckParm("-complevel");
3082     if (i && (i+1 < myargc))
3083     {
3084       lev = atoi(myargv[i+1]);
3085       if (lev>=0)
3086         return lev;
3087     }
3088   }
3089   if (ver == 110) return tasdoom_compatibility;
3090   if (ver < 107) return doom_1666_compatibility;
3091   if (gamemode == retail) return ultdoom_compatibility;
3092   if (gamemission >= pack_tnt) return finaldoom_compatibility;
3093   return doom2_19_compatibility;
3094 }
3095 
3096 //e6y: Check for overrun
CheckForOverrun(const byte * start_p,const byte * current_p,size_t maxsize,size_t size,dboolean failonerror)3097 static dboolean CheckForOverrun(const byte *start_p, const byte *current_p, size_t maxsize, size_t size, dboolean failonerror)
3098 {
3099   size_t pos = current_p - start_p;
3100   if (pos + size > maxsize)
3101   {
3102     if (failonerror)
3103       I_Error("G_ReadDemoHeader: wrong demo header\n");
3104     else
3105       return true;
3106   }
3107   return false;
3108 }
3109 
3110 // e6y
3111 // save/restore all data which could be changed by G_ReadDemoHeader
G_SaveRestoreGameOptions(int save)3112 void G_SaveRestoreGameOptions(int save)
3113 {
3114   typedef struct gameoption_s
3115   {
3116     int type;
3117     int value_int;
3118     int *value_p;
3119   } gameoption_t;
3120 
3121   static gameoption_t gameoptions[] =
3122   {
3123     {1, 0, &demover},
3124     {1, 0, (int*)&compatibility_level},
3125     {1, 0, &basetic},
3126     {3, 0, (int*)&rngseed},
3127 
3128     {1, 0, (int*)&gameskill},
3129     {1, 0, &gameepisode},
3130     {1, 0, &gamemap},
3131 
3132     {2, 0, (int*)&deathmatch},
3133     {2, 0, (int*)&respawnparm},
3134     {2, 0, (int*)&fastparm},
3135     {2, 0, (int*)&nomonsters},
3136     {1, 0, &consoleplayer},
3137     {2, 0, (int*)&netgame},
3138     {2, 0, (int*)&netdemo},
3139 
3140     {1, 0, &longtics},
3141     {1, 0, &monsters_remember},
3142     {1, 0, &variable_friction},
3143     {1, 0, &weapon_recoil},
3144     {1, 0, &allow_pushers},
3145     {1, 0, &player_bobbing},
3146     {1, 0, &demo_insurance},
3147     {1, 0, &monster_infighting},
3148 #ifdef DOGS
3149     {1, 0, &dogs},
3150 #endif
3151     {1, 0, &distfriend},
3152     {1, 0, &monster_backing},
3153     {1, 0, &monster_avoid_hazards},
3154     {1, 0, &monster_friction},
3155     {1, 0, &help_friends},
3156 #ifdef DOGS
3157     {1, 0, &dog_jumping},
3158 #endif
3159     {1, 0, &monkeys},
3160 
3161     {2, 0, &forceOldBsp},
3162     {-1, -1, NULL}
3163   };
3164 
3165   static dboolean was_saved_once = false;
3166 
3167   static dboolean playeringame_o[MAXPLAYERS];
3168   static dboolean playerscheats_o[MAXPLAYERS];
3169   static int comp_o[COMP_TOTAL];
3170 
3171   int i = 0;
3172 
3173   if (save)
3174   {
3175     was_saved_once = true;
3176   }
3177   else
3178   {
3179     if (!was_saved_once)
3180     {
3181       I_Error("G_SaveRestoreGameOptions: Trying to restore unsaved data");
3182     }
3183   }
3184 
3185   while (gameoptions[i].value_p)
3186   {
3187     switch (gameoptions[i].type)
3188     {
3189     case 1: //int
3190     case 2: //dboolean
3191     case 3: //unsigned long
3192       if (save)
3193       {
3194         gameoptions[i].value_int = *gameoptions[i].value_p;
3195       }
3196       else
3197       {
3198         *gameoptions[i].value_p = gameoptions[i].value_int;
3199       }
3200       break;
3201     default: // unrecognised type
3202       I_Error("G_SaveRestoreGameOptions: Unrecognised type of option");
3203       break;
3204     }
3205 
3206     i++;
3207   }
3208 
3209   for (i = 0 ; i < MAXPLAYERS; i++)
3210   {
3211     if (save)
3212     {
3213       playeringame_o[i] = playeringame[i];
3214       playerscheats_o[i] = players[i].cheats;
3215     }
3216     else
3217     {
3218       playeringame[i] = playeringame_o[i];
3219       players[i].cheats = playerscheats_o[i];
3220     }
3221   }
3222 
3223   for (i = 0; i < COMP_TOTAL; i++)
3224   {
3225     if (save)
3226     {
3227       comp_o[i] = comp[i];
3228     }
3229     else
3230     {
3231       comp[i] = comp_o[i];
3232     }
3233   }
3234 }
3235 
G_ReadDemoHeader(const byte * demo_p,size_t size)3236 const byte* G_ReadDemoHeader(const byte *demo_p, size_t size)
3237 {
3238   return G_ReadDemoHeaderEx(demo_p, size, 0);
3239 }
3240 
G_ReadDemoHeaderEx(const byte * demo_p,size_t size,unsigned int params)3241 const byte* G_ReadDemoHeaderEx(const byte *demo_p, size_t size, unsigned int params)
3242 {
3243   skill_t skill;
3244   int i, episode, map;
3245 
3246   // e6y
3247   // The local variable should be used instead of demobuffer,
3248   // because demobuffer can be uninitialized
3249   const byte *header_p = demo_p;
3250 
3251   dboolean failonerror = (params&RDH_SAFE);
3252 
3253   basetic = gametic;  // killough 9/29/98
3254 
3255   // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
3256   // Old demos turn on demo_compatibility => compatibility; new demos load
3257   // compatibility flag, and other flags as well, as a part of the demo.
3258 
3259   //e6y: check for overrun
3260   if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
3261     return NULL;
3262 
3263   demover = *demo_p++;
3264   longtics = 0;
3265 
3266   // e6y
3267   // Handling of unrecognized demo formats
3268   // Versions up to 1.2 use a 7-byte header - first byte is a skill level.
3269   // Versions after 1.2 use a 13-byte header - first byte is a demoversion.
3270   // BOOM's demoversion starts from 200
3271   if (!((demover >=   0  && demover <=   4) ||
3272         (demover >= 104  && demover <= 111) ||
3273         (demover >= 200  && demover <= 214)))
3274   {
3275     I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover);
3276   }
3277 
3278   if (demover < 200)     // Autodetect old demos
3279     {
3280       if (demover >= 111) longtics = 1;
3281 
3282       // killough 3/2/98: force these variables to be 0 in demo_compatibility
3283 
3284       variable_friction = 0;
3285 
3286       weapon_recoil = 0;
3287 
3288       allow_pushers = 0;
3289 
3290       monster_infighting = 1;           // killough 7/19/98
3291 
3292 #ifdef DOGS
3293       dogs = 0;                         // killough 7/19/98
3294       dog_jumping = 0;                  // killough 10/98
3295 #endif
3296 
3297       monster_backing = 0;              // killough 9/8/98
3298 
3299       monster_avoid_hazards = 0;        // killough 9/9/98
3300 
3301       monster_friction = 0;             // killough 10/98
3302       help_friends = 0;                 // killough 9/9/98
3303       monkeys = 0;
3304 
3305       // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm,
3306       // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions())
3307 
3308       if ((skill=demover) >= 100)         // For demos from versions >= 1.4
3309         {
3310           //e6y: check for overrun
3311           if (CheckForOverrun(header_p, demo_p, size, 8, failonerror))
3312             return NULL;
3313 
3314           compatibility_level = G_GetOriginalDoomCompatLevel(demover);
3315           skill = *demo_p++;
3316           episode = *demo_p++;
3317           map = *demo_p++;
3318           deathmatch = *demo_p++;
3319           respawnparm = *demo_p++;
3320           fastparm = *demo_p++;
3321           nomonsters = *demo_p++;
3322           consoleplayer = *demo_p++;
3323         }
3324       else
3325         {
3326           //e6y: check for overrun
3327           if (CheckForOverrun(header_p, demo_p, size, 2, failonerror))
3328             return NULL;
3329 
3330           compatibility_level = doom_12_compatibility;
3331           episode = *demo_p++;
3332           map = *demo_p++;
3333           deathmatch = respawnparm = fastparm =
3334             nomonsters = consoleplayer = 0;
3335 
3336           // e6y
3337           // Ability to force -nomonsters and -respawn for playback of 1.2 demos.
3338           // Demos recorded with Doom.exe 1.2 did not contain any information
3339           // about whether these parameters had been used. In order to play them
3340           // back, you should add them to the command-line for playback.
3341           // There is no more desynch on mesh.lmp @ mesh.wad
3342           // prboom -iwad doom.wad -file mesh.wad -playdemo mesh.lmp -nomonsters
3343           // http://www.doomworld.com/idgames/index.php?id=13976
3344           respawnparm = M_CheckParm("-respawn");
3345           fastparm = M_CheckParm("-fast");
3346           nomonsters = M_CheckParm("-nomonsters");
3347 
3348           // e6y: detection of more unsupported demo formats
3349           if (*(header_p + size - 1) == DEMOMARKER)
3350           {
3351             // file size test;
3352             // DOOM_old and HERETIC don't use maps>9;
3353             // 2 at 4,6 means playerclass=mage -> not DOOM_old or HERETIC;
3354             if ((size >= 8 && (size - 8) % 4 != 0) ||
3355                 (map > 9) ||
3356                 (size >= 6 && (*(header_p + 4) == 2 || *(header_p + 6) == 2)))
3357             {
3358               I_Error("Unrecognised demo format.");
3359             }
3360           }
3361 
3362         }
3363       G_Compatibility();
3364     }
3365   else    // new versions of demos
3366     {
3367       demo_p += 6;               // skip signature;
3368       switch (demover) {
3369       case 200: /* BOOM */
3370       case 201:
3371         //e6y: check for overrun
3372         if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
3373           return NULL;
3374 
3375         if (!*demo_p++)
3376 	  compatibility_level = boom_201_compatibility;
3377         else
3378 	  compatibility_level = boom_compatibility_compatibility;
3379 	  break;
3380       case 202:
3381         //e6y: check for overrun
3382         if (CheckForOverrun(header_p, demo_p, size, 1, failonerror))
3383           return NULL;
3384 
3385         if (!*demo_p++)
3386 	  compatibility_level = boom_202_compatibility;
3387         else
3388 	  compatibility_level = boom_compatibility_compatibility;
3389 	  break;
3390       case 203:
3391 	/* LxDoom or MBF - determine from signature
3392 	 * cph - load compatibility level */
3393 	switch (*(header_p + 2)) {
3394 	case 'B': /* LxDoom */
3395 	  /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */
3396 	  compatibility_level = lxdoom_1_compatibility;
3397 	  break;
3398 	case 'M':
3399 	  compatibility_level = mbf_compatibility;
3400 	  demo_p++;
3401 	  break;
3402 	}
3403 	break;
3404       case 210:
3405 	compatibility_level = prboom_2_compatibility;
3406 	demo_p++;
3407 	break;
3408       case 211:
3409 	compatibility_level = prboom_3_compatibility;
3410 	demo_p++;
3411 	break;
3412       case 212:
3413 	compatibility_level = prboom_4_compatibility;
3414 	demo_p++;
3415 	break;
3416       case 213:
3417 	compatibility_level = prboom_5_compatibility;
3418 	demo_p++;
3419 	break;
3420       case 214:
3421 	compatibility_level = prboom_6_compatibility;
3422         longtics = 1;
3423 	demo_p++;
3424 	break;
3425       }
3426       //e6y: check for overrun
3427       if (CheckForOverrun(header_p, demo_p, size, 5, failonerror))
3428         return NULL;
3429 
3430       skill = *demo_p++;
3431       episode = *demo_p++;
3432       map = *demo_p++;
3433       deathmatch = *demo_p++;
3434       consoleplayer = *demo_p++;
3435 
3436       //e6y: check for overrun
3437       if (CheckForOverrun(header_p, demo_p, size, GAME_OPTION_SIZE, failonerror))
3438         return NULL;
3439 
3440       demo_p = G_ReadOptions(demo_p);  // killough 3/1/98: Read game options
3441 
3442       if (demover == 200)              // killough 6/3/98: partially fix v2.00 demos
3443         demo_p += 256-GAME_OPTION_SIZE;
3444     }
3445 
3446   if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL)
3447     I_Error("G_ReadDemoHeader: compatibility level strings incomplete");
3448   lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n",
3449     comp_lev_str[compatibility_level]);
3450 
3451   if (demo_compatibility || demover < 200) //e6y  // only 4 players can exist in old demos
3452     {
3453       //e6y: check for overrun
3454       if (CheckForOverrun(header_p, demo_p, size, 4, failonerror))
3455         return NULL;
3456 
3457       for (i=0; i<4; i++)  // intentionally hard-coded 4 -- killough
3458         playeringame[i] = *demo_p++;
3459       for (;i < MAXPLAYERS; i++)
3460         playeringame[i] = 0;
3461     }
3462   else
3463     {
3464       //e6y: check for overrun
3465       if (CheckForOverrun(header_p, demo_p, size, MAXPLAYERS, failonerror))
3466         return NULL;
3467 
3468       for (i=0 ; i < MAXPLAYERS; i++)
3469         playeringame[i] = *demo_p++;
3470       demo_p += MIN_MAXPLAYERS - MAXPLAYERS;
3471     }
3472 
3473   if (playeringame[1])
3474     {
3475       netgame = true;
3476       netdemo = true;
3477     }
3478 
3479   if (!(params&RDH_SKIP_HEADER))
3480   {
3481     if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */
3482       G_InitNew(skill, episode, map);
3483     }
3484   }
3485 
3486   for (i=0; i<MAXPLAYERS;i++)         // killough 4/24/98
3487     players[i].cheats = 0;
3488 
3489   // e6y
3490   // additional params
3491   {
3492     const byte *p = demo_p;
3493 
3494     bytes_per_tic = (longtics ? 5 : 4);
3495     demo_playerscount = 0;
3496     demo_tics_count = 0;
3497     demo_curr_tic = 0;
3498     strcpy(demo_len_st, "-");
3499 
3500     for (i = 0; i < MAXPLAYERS; i++)
3501     {
3502       if (playeringame[i])
3503       {
3504         demo_playerscount++;
3505       }
3506     }
3507 
3508     if (demo_playerscount > 0 && demolength > 0)
3509     {
3510       do
3511       {
3512         demo_tics_count++;
3513         p += bytes_per_tic;
3514       }
3515       while ((p < demobuffer + demolength) && (*p != DEMOMARKER));
3516 
3517       demo_tics_count /= demo_playerscount;
3518 
3519       sprintf(demo_len_st, "\x1b\x35/%d:%02d",
3520         demo_tics_count/TICRATE/60,
3521         (demo_tics_count%(60*TICRATE))/TICRATE);
3522     }
3523   }
3524 
3525   return demo_p;
3526 }
3527 
G_DoPlayDemo(void)3528 void G_DoPlayDemo(void)
3529 {
3530   if (LoadDemo(defdemoname, &demobuffer, &demolength, &demolumpnum))
3531   {
3532     demo_p = G_ReadDemoHeaderEx(demobuffer, demolength, RDH_SAFE);
3533 
3534     gameaction = ga_nothing;
3535     usergame = false;
3536 
3537     demoplayback = true;
3538     R_SmoothPlaying_Reset(NULL); // e6y
3539   }
3540   else
3541   {
3542     // e6y
3543     // Do not exit if corresponding demo lump is not found.
3544     // It makes sense for Plutonia and TNT IWADs, which have no DEMO4 lump,
3545     // but DEMO4 should be in a demo cycle as real Plutonia and TNT have.
3546     //
3547     // Plutonia/Tnt executables exit with "W_GetNumForName: DEMO4 not found"
3548     // message after playing of DEMO3, because DEMO4 is not present
3549     // in the corresponding IWADs.
3550     usergame = false;
3551     D_StartTitle();                // Start the title screen
3552     gamestate = GS_DEMOSCREEN;     // And set the game state accordingly
3553   }
3554 }
3555 
3556 /* G_CheckDemoStatus
3557  *
3558  * Called after a death or level completion to allow demos to be cleaned up
3559  * Returns true if a new demo loop action will take place
3560  */
G_CheckDemoStatus(void)3561 dboolean G_CheckDemoStatus (void)
3562 {
3563   //e6y
3564   if (doSkip && (demo_stoponend || demo_stoponnext))
3565     G_SkipDemoStop();
3566 
3567   P_ChecksumFinal();
3568 
3569   if (demorecording)
3570     {
3571       demorecording = false;
3572       fputc(DEMOMARKER, demofp);
3573 
3574       //e6y
3575       G_WriteDemoFooter(demofp);
3576 
3577       lprintf(LO_INFO, "G_CheckDemoStatus: Demo recorded\n");
3578       return false;  // killough
3579     }
3580 
3581   if (timingdemo)
3582     {
3583       int endtime = I_GetTime_RealTime ();
3584       // killough -- added fps information and made it work for longer demos:
3585       unsigned realtics = endtime-starttime;
3586 
3587       M_SaveDefaults();
3588 
3589       I_Error ("Timed %u gametics in %u realtics = %-.1f frames per second",
3590                (unsigned) gametic,realtics,
3591                (unsigned) gametic * (double) TICRATE / realtics);
3592     }
3593 
3594   if (demoplayback)
3595     {
3596       if (singledemo)
3597         exit(0);  // killough
3598 
3599       if (demolumpnum != -1) {
3600   // cph - unlock the demo lump
3601   W_UnlockLumpNum(demolumpnum);
3602   demolumpnum = -1;
3603       }
3604       G_ReloadDefaults();    // killough 3/1/98
3605       netgame = false;       // killough 3/29/98
3606       deathmatch = false;
3607       D_AdvanceDemo ();
3608       return true;
3609     }
3610   return false;
3611 }
3612 
3613 // killough 1/22/98: this is a "Doom printf" for messages. I've gotten
3614 // tired of using players->message=... and so I've added this dprintf.
3615 //
3616 // killough 3/6/98: Made limit static to allow z_zone functions to call
3617 // this function, without calling realloc(), which seems to cause problems.
3618 
3619 #define MAX_MESSAGE_SIZE 1024
3620 
3621 // CPhipps - renamed to doom_printf to avoid name collision with glibc
doom_printf(const char * s,...)3622 void doom_printf(const char *s, ...)
3623 {
3624   static char msg[MAX_MESSAGE_SIZE];
3625   va_list v;
3626   va_start(v,s);
3627 #ifdef HAVE_VSNPRINTF
3628   vsnprintf(msg,sizeof(msg),s,v);        /* print message in buffer */
3629 #else
3630   vsprintf(msg,s,v);
3631 #endif
3632   va_end(v);
3633   players[consoleplayer].message = msg;  // set new message
3634 }
3635 
3636 //e6y
P_WalkTicker()3637 void P_WalkTicker()
3638 {
3639   int strafe;
3640   int speed;
3641   int tspeed;
3642   int turnheld;
3643   int forward;
3644   int side;
3645   int angturn;
3646 
3647   if (!walkcamera.type || menuactive)
3648     return;
3649 
3650   strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
3651     || joybuttons[joybstrafe];
3652   speed = autorun || gamekeydown[key_speed] || joybuttons[joybspeed]; // phares
3653 
3654   forward = side = 0;
3655   angturn = 0;
3656   turnheld = 0;
3657 
3658     // use two stage accelerative turning
3659     // on the keyboard and joystick
3660   if (joyxmove < 0 || joyxmove > 0 ||
3661       gamekeydown[key_right] || gamekeydown[key_left])
3662     turnheld += ticdup;
3663   else
3664     turnheld = 0;
3665 
3666   if (turnheld < SLOWTURNTICS)
3667     tspeed = 0;             // slow turn
3668   else
3669     tspeed = speed;                                                             // phares
3670 
3671   // let movement keys cancel each other out
3672 
3673   if (strafe)
3674     {
3675       if (gamekeydown[key_right])
3676         side += sidemove[speed];
3677       if (gamekeydown[key_left])
3678         side -= sidemove[speed];
3679       if (joyxmove > 0)
3680         side += sidemove[speed];
3681       if (joyxmove < 0)
3682         side -= sidemove[speed];
3683     }
3684   else
3685     {
3686       if (gamekeydown[key_right])
3687         angturn -= angleturn[tspeed];
3688       if (gamekeydown[key_left])
3689         angturn += angleturn[tspeed];
3690       if (joyxmove > 0)
3691         angturn -= angleturn[tspeed];
3692       if (joyxmove < 0)
3693         angturn += angleturn[tspeed];
3694     }
3695 
3696   if (gamekeydown[key_up])
3697     forward += forwardmove[speed];
3698   if (gamekeydown[key_down])
3699     forward -= forwardmove[speed];
3700   if (joyymove < 0)
3701     forward += forwardmove[speed];
3702   if (joyymove > 0)
3703     forward -= forwardmove[speed];
3704   if (gamekeydown[key_straferight])
3705     side += sidemove[speed];
3706   if (gamekeydown[key_strafeleft])
3707     side -= sidemove[speed];
3708 
3709   //mouse
3710   if (mousebuttons[mousebforward])
3711     forward += forwardmove[speed];
3712 
3713   forward += mousey;
3714   if (strafe)
3715     side += mousex / 4;       /* mead  Don't want to strafe as fast as turns.*/
3716   else
3717     angturn -= mousex; /* mead now have enough dynamic range 2-10-00 */
3718 
3719   walkcamera.angle += ((angturn / 8) << ANGLETOFINESHIFT);
3720   if(GetMouseLook())
3721   {
3722     walkcamera.pitch += ((mlooky / 8) << ANGLETOFINESHIFT);
3723     CheckPitch((signed int *) &walkcamera.pitch);
3724   }
3725 
3726   if (gamekeydown[key_fire] || mousebuttons[mousebfire] ||
3727       joybuttons[joybfire])
3728   {
3729     walkcamera.x = players[0].mo->x;
3730     walkcamera.y = players[0].mo->y;
3731     walkcamera.angle = players[0].mo->angle;
3732     walkcamera.pitch = players[0].mo->pitch;
3733   }
3734 
3735   if (forward > MAXPLMOVE)
3736     forward = MAXPLMOVE;
3737   else if (forward < -MAXPLMOVE)
3738     forward = -MAXPLMOVE;
3739   if (side > MAXPLMOVE)
3740     side = MAXPLMOVE;
3741   else if (side < -MAXPLMOVE)
3742     side = -MAXPLMOVE;
3743 
3744   // moving forward
3745   walkcamera.x += FixedMul ((ORIG_FRICTION / 4) * forward,
3746           finecosine[walkcamera.angle >> ANGLETOFINESHIFT]);
3747   walkcamera.y += FixedMul ((ORIG_FRICTION / 4) * forward,
3748           finesine[walkcamera.angle >> ANGLETOFINESHIFT]);
3749 
3750   // strafing
3751   walkcamera.x += FixedMul ((ORIG_FRICTION / 6) * side,
3752           finecosine[(walkcamera.angle -
3753           ANG90) >> ANGLETOFINESHIFT]);
3754   walkcamera.y += FixedMul ((ORIG_FRICTION / 6) * side,
3755         finesine[(walkcamera.angle - ANG90) >> ANGLETOFINESHIFT]);
3756 
3757   {
3758     subsector_t *subsec = R_PointInSubsector (walkcamera.x, walkcamera.y);
3759     walkcamera.z = subsec->sector->floorheight + 41 * FRACUNIT;
3760   }
3761 
3762   mousex = mousey = 0;
3763 }
3764 
P_ResetWalkcam(void)3765 void P_ResetWalkcam(void)
3766 {
3767   walkcamera.PrevX = walkcamera.x;
3768   walkcamera.PrevY = walkcamera.y;
3769   walkcamera.PrevZ = walkcamera.z;
3770   walkcamera.PrevAngle = walkcamera.angle;
3771   walkcamera.PrevPitch = walkcamera.pitch;
3772 }
3773 
P_SyncWalkcam(dboolean sync_coords,dboolean sync_sight)3774 void P_SyncWalkcam(dboolean sync_coords, dboolean sync_sight)
3775 {
3776   if (!walkcamera.type)
3777     return;
3778 
3779   if (players[displayplayer].mo)
3780   {
3781     if (sync_sight)
3782     {
3783       walkcamera.angle = players[displayplayer].mo->angle;
3784       walkcamera.pitch = players[displayplayer].mo->pitch;
3785     }
3786 
3787     if(sync_coords)
3788     {
3789       walkcamera.x = players[displayplayer].mo->x;
3790       walkcamera.y = players[displayplayer].mo->y;
3791     }
3792   }
3793 }
3794 
G_ReadDemoContinueTiccmd(ticcmd_t * cmd)3795 void G_ReadDemoContinueTiccmd (ticcmd_t* cmd)
3796 {
3797   if (!demo_continue_p)
3798     return;
3799 
3800   if (gametic <= demo_tics_count &&
3801     demo_continue_p + bytes_per_tic <= demobuffer + demolength &&
3802     *demo_continue_p != DEMOMARKER)
3803   {
3804     G_ReadOneTick(cmd, &demo_continue_p);
3805   }
3806 
3807   if (gametic >= demo_tics_count ||
3808     demo_continue_p > demobuffer + demolength ||
3809     gamekeydown[key_demo_jointogame] || joybuttons[joybuse])
3810   {
3811     demo_continue_p = NULL;
3812     democontinue = false;
3813   }
3814 }
3815 
3816 //e6y
G_CheckDemoContinue(void)3817 void G_CheckDemoContinue(void)
3818 {
3819   if (democontinue)
3820   {
3821     if (LoadDemo(defdemoname, &demobuffer, &demolength, &demolumpnum))
3822     {
3823       demo_continue_p = G_ReadDemoHeaderEx(demobuffer, demolength, RDH_SAFE);
3824 
3825       singledemo = true;
3826       autostart = true;
3827       G_RecordDemo(democontinuename);
3828       G_BeginRecording();
3829       usergame = true;
3830     }
3831   }
3832 }
3833