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