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