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