1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 * The original Doom description was none, basically because this file
29 * has everything. This ties up the game logic, linking the menu and
30 * input code to the underlying game by creating & respawning players,
31 * building game tics, calling the underlying thing logic.
33 *-----------------------------------------------------------------------------
57 // Needs access to LFB.
68 // SKY handling - still the wrong place.
74 #include "rockmacros.h"
76 #define SAVEGAMESIZE 0x20000
77 #define SAVESTRINGSIZE 24
79 static size_t savegamesize
= SAVEGAMESIZE
; // killough
80 static boolean netdemo
;
81 static const byte
*demobuffer
; /* cph - only used for playback */
82 static int demofd
; /* cph - record straight to file */
83 static const byte
*demo_p
;
84 static short consistancy
[MAXPLAYERS
][BACKUPTICS
];
86 gameaction_t gameaction
;
87 gamestate_t gamestate
;
89 boolean respawnmonsters
;
93 // CPhipps - moved *_loadgame vars here
94 static boolean forced_loadgame
= false;
95 static boolean command_loadgame
= false;
97 boolean usergame
; // ok to save / end game
98 boolean timingdemo
; // if true, exit with report on completion
99 boolean fastdemo
; // if true, run at full speed -- killough
100 boolean nodrawers
; // for comparative timing purposes
101 boolean noblit
; // for comparative timing purposes
102 int starttime
; // for comparative timing purposes
103 boolean deathmatch
; // only if started as net death
104 boolean netgame
; // only true if packets are broadcast
105 boolean playeringame
[MAXPLAYERS
];
106 player_t players
[MAXPLAYERS
];
107 int consoleplayer
; // player taking events and displaying
108 int displayplayer
; // view being displayed
110 int levelstarttic
; // gametic at level start
111 extern int basetic
; /* killough 9/29/98: for demo sync */
112 int totalkills
, totallive
, totalitems
, totalsecret
; // for intermission
113 boolean demorecording
;
114 boolean demoplayback
;
115 boolean singledemo
; // quit after playing a demo from cmdline
116 wbstartstruct_t wminfo
; // parms for world map / intermission
117 boolean haswolflevels
= false;// jff 4/18/98 wolf levels present
118 static byte
*savebuffer
; // CPhipps - static
119 int autorun
= false; // always running? // phares
120 int totalleveltimes
; // CPhipps - total time for all completed levels
124 // controls (have defaults)
130 int key_menu_right
; // phares 3/7/98
131 int key_menu_left
; // |
132 int key_menu_up
; // V
134 int key_menu_backspace
; // ^
135 int key_menu_escape
; // |
136 int key_menu_enter
; // phares 3/7/98
143 int key_escape
= KEY_ESCAPE
; // phares 4/13/98
146 int key_savegame
; // phares
147 int key_loadgame
; // |
148 int key_autorun
; // V
170 int key_map_overlay
; // cph - map overlay
171 int key_map_rotate
; // cph - map rotation
172 int key_help
= KEY_F1
; // phares 4/13/98
184 int destination_keys
[MAXPLAYERS
];
185 int key_weapontoggle
;
192 int key_weapon7
; // ^
193 int key_weapon8
; // |
194 int key_weapon9
; // phares
196 int key_screenshot
; // killough 2/22/98: screenshot key
205 #define MAXPLMOVE (forwardmove[1])
206 #define TURBOTHRESHOLD 0x32
207 #define SLOWTURNTICS 6
208 #define QUICKREVERSE (short)32768 // 180 degree reverse // phares
211 fixed_t forwardmove
[2] = {0x19, 0x32};
212 fixed_t sidemove
[2] = {0x18, 0x28};
213 fixed_t angleturn
[3] = {640, 1280, 320}; // + slow turn
215 // CPhipps - made lots of key/button state vars static
216 static boolean gamekeydown
[NUMKEYS
];
217 static int turnheld
; // for accelerative turning
219 static boolean mousearray
[4];
220 static boolean
*mousebuttons
= &mousearray
[1]; // allow [-1]
222 // mouse values are used once
225 static unsigned int dclicktime
;
226 static unsigned int dclickstate
;
227 static unsigned int dclicks
;
228 static unsigned int dclicktime2
;
229 static unsigned int dclickstate2
;
230 static unsigned int dclicks2
;
232 // joystick values are repeated
235 static boolean joyarray
[5];
236 static boolean
*joybuttons
= &joyarray
[1]; // allow [-1]
239 static buttoncode_t special_event
; // Event triggered by local player, to send
240 static byte savegameslot
; // Slot to load if gameaction == ga_loadgame
241 char savedescription
[SAVEDESCLEN
]; // Description to save in savegame if gameaction == ga_savegame
243 //jff 3/24/98 declare startskill external, define defaultskill here
244 extern skill_t startskill
; //note 0-based
245 int defaultskill
; //note 1-based
247 // killough 2/8/98: make corpse queue variable in size
248 int bodyqueslot
, bodyquesize
; // killough 2/8/98
249 mobj_t
**bodyque
= 0; // phares 8/10/98
251 void* statcopy
; // for statistics driver
253 static void G_DoSaveGame (boolean menu
);
254 static const byte
* G_ReadDemoHeader(const byte
* demo_p
);
258 // Builds a ticcmd from all of the available inputs
259 // or reads it from the demo buffer.
260 // If recording a demo, write it out
262 static inline signed char fudgef(signed char b
)
265 if (!b
|| !demo_compatibility
|| longtics
) return b
;
266 if (++c
& 0x1f) return b
;
267 b
|= 1; if (b
>2) b
-=2;
271 static inline signed short fudgea(signed short b
)
273 if (!b
|| !demo_compatibility
|| !longtics
) return b
;
274 b
|= 1; if (b
>2) b
-=2;
278 void G_BuildTiccmd(ticcmd_t
* cmd
)
286 int newweapon
=0; // phares
287 /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */
288 memset(cmd
,0,sizeof*cmd
);
289 cmd
->consistancy
= consistancy
[consoleplayer
][maketic
%BACKUPTICS
];
291 strafe
= gamekeydown
[key_strafe
] || mousebuttons
[mousebstrafe
]
292 || joybuttons
[joybstrafe
];
293 speed
= autorun
|| gamekeydown
[key_speed
] || joybuttons
[joybspeed
]; // phares
297 // use two stage accelerative turning
298 // on the keyboard and joystick
299 if (joyxmove
< 0 || joyxmove
> 0 ||
300 gamekeydown
[key_right
] || gamekeydown
[key_left
])
305 if (turnheld
< SLOWTURNTICS
)
306 tspeed
= 2; // slow turn
310 // turn 180 degrees in one keystroke? // phares
312 if (gamekeydown
[key_reverse
]) // V
314 cmd
->angleturn
+= QUICKREVERSE
; // ^
315 gamekeydown
[key_reverse
] = false; // |
318 // let movement keys cancel each other out
322 if (gamekeydown
[key_right
])
323 side
+= sidemove
[speed
];
324 if (gamekeydown
[key_left
])
325 side
-= sidemove
[speed
];
327 side
+= sidemove
[speed
];
329 side
-= sidemove
[speed
];
333 if (gamekeydown
[key_right
])
334 cmd
->angleturn
-= angleturn
[tspeed
];
335 if (gamekeydown
[key_left
])
336 cmd
->angleturn
+= angleturn
[tspeed
];
338 cmd
->angleturn
-= angleturn
[tspeed
];
340 cmd
->angleturn
+= angleturn
[tspeed
];
343 if (gamekeydown
[key_up
])
344 forward
+= forwardmove
[speed
];
345 if (gamekeydown
[key_down
])
346 forward
-= forwardmove
[speed
];
348 forward
+= forwardmove
[speed
];
350 forward
-= forwardmove
[speed
];
351 if (gamekeydown
[key_straferight
])
352 side
+= sidemove
[speed
];
353 if (gamekeydown
[key_strafeleft
])
354 side
-= sidemove
[speed
];
357 cmd
->chatchar
= HU_dequeueChatChar();
359 if (gamekeydown
[key_fire
] || mousebuttons
[mousebfire
] ||
360 joybuttons
[joybfire
])
361 cmd
->buttons
|= BT_ATTACK
;
363 if (gamekeydown
[key_use
] || joybuttons
[joybuse
])
365 cmd
->buttons
|= BT_USE
;
366 // clear double clicks if hit use button
370 // Toggle between the top 2 favorite weapons. // phares
371 // If not currently aiming one of these, switch to // phares
372 // the favorite. Only switch if you possess the weapon. // phares
376 // Perform automatic weapons switch here rather than in p_pspr.c,
377 // except in demo_compatibility mode.
379 // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left
381 if ((!demo_compatibility
&& players
[consoleplayer
].attackdown
&& // killough
382 !P_CheckAmmo(&players
[consoleplayer
])) || gamekeydown
[key_weapontoggle
])
383 newweapon
= P_SwitchWeapon(&players
[consoleplayer
]); // phares
385 { // phares 02/26/98: Added gamemode checks
386 if(gamekeydown
[key_weapon
])
388 volatile unsigned int wpcheck
; // I don't know why this is needed, but it is
389 for(wpcheck
=0; wpcheck
<9; wpcheck
++)
390 if(players
[consoleplayer
].weaponowned
[wpcheck
] && wpcheck
>players
[consoleplayer
].readyweapon
)
395 if(players
[consoleplayer
].weaponowned
[wp_chainsaw
]&&newweapon
==0)
401 gamekeydown
[key_weapon1
] ? wp_fist
: // killough 5/2/98: reformatted
402 gamekeydown
[key_weapon2
] ? wp_pistol
:
403 gamekeydown
[key_weapon3
] ? wp_shotgun
:
404 gamekeydown
[key_weapon4
] ? wp_chaingun
:
405 gamekeydown
[key_weapon5
] ? wp_missile
:
406 gamekeydown
[key_weapon6
] && gamemode
!= shareware
? wp_plasma
:
407 gamekeydown
[key_weapon7
] && gamemode
!= shareware
? wp_bfg
:
408 gamekeydown
[key_weapon8
] ? wp_chainsaw
:
409 gamekeydown
[key_weapon9
] && gamemode
== commercial
? wp_supershotgun
:
413 // killough 3/22/98: For network and demo consistency with the
414 // new weapons preferences, we must do the weapons switches here
415 // instead of in p_user.c. But for old demos we must do it in
416 // p_user.c according to the old rules. Therefore demo_compatibility
417 // determines where the weapons switch is made.
420 // Allow user to switch to fist even if they have chainsaw.
421 // Switch to fist or chainsaw based on preferences.
422 // Switch to shotgun or SSG based on preferences.
424 if (!demo_compatibility
)
426 const player_t
*player
= &players
[consoleplayer
];
428 // only select chainsaw from '1' if it's owned, it's
429 // not already in use, and the player prefers it or
430 // the fist is already in use, or the player does not
431 // have the berserker strength.
433 if (newweapon
==wp_fist
&& player
->weaponowned
[wp_chainsaw
] &&
434 player
->readyweapon
!=wp_chainsaw
&&
435 (player
->readyweapon
==wp_fist
||
436 !player
->powers
[pw_strength
] ||
437 P_WeaponPreferred(wp_chainsaw
, wp_fist
)))
438 newweapon
= wp_chainsaw
;
440 // Select SSG from '3' only if it's owned and the player
441 // does not have a shotgun, or if the shotgun is already
442 // in use, or if the SSG is not already in use and the
443 // player prefers it.
444 if(!gamekeydown
[key_weapon
])
445 if (newweapon
== wp_shotgun
&& gamemode
== commercial
&&
446 player
->weaponowned
[wp_supershotgun
] &&
447 (!player
->weaponowned
[wp_shotgun
] ||
448 player
->readyweapon
== wp_shotgun
||
449 (player
->readyweapon
!= wp_supershotgun
&&
450 P_WeaponPreferred(wp_supershotgun
, wp_shotgun
))))
451 newweapon
= wp_supershotgun
;
454 // killough 2/8/98, 3/22/98 -- end of weapon selection changes
457 if(newweapon
>wp_nochange
) // something is messed up with the weapon switching code above allowing it to give values greater
458 { // then wp_nochange which really screws the game up
461 if (newweapon
!= wp_nochange
)
463 cmd
->buttons
|= BT_CHANGE
;
464 cmd
->buttons
|= newweapon
<<BT_WEAPONSHIFT
;
468 if (mousebuttons
[mousebforward
])
469 forward
+= forwardmove
[speed
];
471 // forward double click
472 if (mousebuttons
[mousebforward
] != dclickstate
&& dclicktime
> 1 )
474 dclickstate
= mousebuttons
[mousebforward
];
479 cmd
->buttons
|= BT_USE
;
486 if ((dclicktime
+= ticdup
) > 20)
492 // strafe double click
494 bstrafe
= mousebuttons
[mousebstrafe
] || joybuttons
[joybstrafe
];
495 if (bstrafe
!= dclickstate2
&& dclicktime2
> 1 )
497 dclickstate2
= bstrafe
;
502 cmd
->buttons
|= BT_USE
;
509 if ((dclicktime2
+= ticdup
) > 20)
516 side
+= mousex
/ 4; /* mead Don't want to strafe as fast as turns.*/
518 cmd
->angleturn
-= mousex
; /* mead now have enough dynamic range 2-10-00 */
522 if (forward
> MAXPLMOVE
)
524 else if (forward
< -MAXPLMOVE
)
525 forward
= -MAXPLMOVE
;
526 if (side
> MAXPLMOVE
)
528 else if (side
< -MAXPLMOVE
)
531 cmd
->forwardmove
+= fudgef(forward
);
532 cmd
->sidemove
+= side
;
533 cmd
->angleturn
= fudgea(cmd
->angleturn
);
535 // CPhipps - special events (game new/load/save/pause)
536 if (special_event
& BT_SPECIAL
) {
537 cmd
->buttons
= special_event
;
546 void G_RestartLevel(void)
548 special_event
= BT_SPECIAL
| (BTS_RESTARTLEVEL
& BT_SPECIALMASK
);
551 #include "z_bmalloc.h"
555 extern gamestate_t wipegamestate
;
557 static void G_DoLoadLevel (void)
562 // First thing, we have a dummy sky texture name,
563 // a flat. The data is in the WAD only because
564 // we look for an actual index, instead of simply
567 skyflatnum
= R_FlatNumForName ( SKYFLATNAME
);
569 // DOOM determines the sky texture to be used
570 // depending on the current episode, and the game version.
571 if (gamemode
== commercial
)
572 // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut
573 // || gamemode == pack_plut) //aren't gamemodes, this was matching retail
575 skytexture
= R_TextureNumForName ("SKY3");
577 skytexture
= R_TextureNumForName ("SKY1");
580 skytexture
= R_TextureNumForName ("SKY2");
582 else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh?
586 skytexture
= R_TextureNumForName ("SKY1");
589 skytexture
= R_TextureNumForName ("SKY2");
592 skytexture
= R_TextureNumForName ("SKY3");
594 case 4: // Special Edition sky
595 skytexture
= R_TextureNumForName ("SKY4");
597 }//jff 3/27/98 end sky setting fix
599 levelstarttic
= gametic
; // for time calculation
601 if (!demo_compatibility
&& !mbf_features
) // killough 9/29/98
604 if (wipegamestate
== GS_LEVEL
)
605 wipegamestate
= -1; // force a wipe
607 gamestate
= GS_LEVEL
;
609 for (i
=0 ; i
<MAXPLAYERS
; i
++)
611 if (playeringame
[i
] && players
[i
].playerstate
== PST_DEAD
)
612 players
[i
].playerstate
= PST_REBORN
;
613 memset (players
[i
].frags
,0,sizeof(players
[i
].frags
));
616 // initialize the msecnode_t freelist. phares 3/25/98
617 // any nodes in the freelist are gone by now, cleared
618 // by Z_FreeTags() when the previous level ended or player
622 DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone
);
623 NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone
);
624 //extern msecnode_t *headsecnode; // phares 3/25/98
625 //headsecnode = NULL;
628 P_SetupLevel (gameepisode
, gamemap
, 0, gameskill
);
629 displayplayer
= consoleplayer
; // view the guy you are playing
630 gameaction
= ga_nothing
;
633 // clear cmd building stuff
634 memset (gamekeydown
, 0, sizeof(gamekeydown
));
635 joyxmove
= joyymove
= 0;
637 special_event
= 0; paused
= false;
638 memset (mousebuttons
, 0, sizeof(mousebuttons
));
639 memset (joybuttons
, 0, sizeof(joybuttons
));
641 // killough 5/13/98: in case netdemo has consoleplayer other than green
645 // killough: make -timedemo work on multilevel demos
646 // Move to end of function to minimize noise -- killough 2/22/98:
653 starttime
= I_GetTime ();
661 // Get info needed to make ticcmd_ts for the players.
663 boolean
G_Responder (event_t
* ev
)
665 // allow spy mode changes even during the demo
666 // killough 2/22/98: even during DM demo
668 // killough 11/98: don't autorepeat spy mode switch
671 if (ev
->data1
== key_spy
&& netgame
&& (demoplayback
|| !deathmatch
) &&
672 gamestate
== GS_LEVEL
)
674 if (ev
->type
== ev_keyup
)
675 gamekeydown
[key_spy
] = false;
676 if (ev
->type
== ev_keydown
&& !gamekeydown
[key_spy
])
678 gamekeydown
[key_spy
] = true;
680 if (++displayplayer
>= MAXPLAYERS
)
682 while (!playeringame
[displayplayer
] && displayplayer
!=consoleplayer
);
684 ST_Start(); // killough 3/7/98: switch status bar views too
686 S_UpdateSounds(players
[displayplayer
].mo
);
692 // any other key pops up menu if in demos
694 // killough 8/2/98: enable automap in -timedemo demos
696 // killough 9/29/98: make any key pop up menu regardless of
697 // which kind of demo, and allow other events during playback
699 if (gameaction
== ga_nothing
&& (demoplayback
|| gamestate
== GS_DEMOSCREEN
))
701 // killough 9/29/98: allow user to pause demos during playback
702 if (ev
->type
== ev_keydown
&& ev
->data1
== key_pause
)
711 // Don't pop up menu, if paused in middle
712 // of demo playback, or if automap active.
713 // Don't suck up keys, which may be cheats
715 return gamestate
== GS_DEMOSCREEN
&&
716 !(paused
& 2) && !(automapmode
& am_active
) &&
717 ((ev
->type
== ev_keydown
) ||
718 (ev
->type
== ev_mouse
&& ev
->data1
) ||
719 (ev
->type
== ev_joystick
&& ev
->data1
)) ?
720 M_StartControlPanel(), true : false;
723 if (gamestate
== GS_FINALE
&& F_Responder(ev
))
724 return true; // finale ate the event
729 if (ev
->data1
== key_pause
) // phares
731 special_event
= BT_SPECIAL
| (BTS_PAUSE
& BT_SPECIALMASK
);
734 if (ev
->data1
<NUMKEYS
)
735 gamekeydown
[ev
->data1
] = true;
736 return true; // eat key down events
739 if (ev
->data1
<NUMKEYS
)
740 gamekeydown
[ev
->data1
] = false;
741 return false; // always let key up events filter down
744 mousebuttons
[0] = ev
->data1
& 1;
745 mousebuttons
[1] = ev
->data1
& 2;
746 mousebuttons
[2] = ev
->data1
& 4;
747 mousex
= ev
->data2
*(mouseSensitivity
+5)/10;
748 mousey
= ev
->data3
*(mouseSensitivity
+5)/10;
749 return true; // eat events
752 joybuttons
[0] = ev
->data1
& 1;
753 joybuttons
[1] = ev
->data1
& 2;
754 joybuttons
[2] = ev
->data1
& 4;
755 joybuttons
[3] = ev
->data1
& 8;
756 joyxmove
= ev
->data2
;
757 joyymove
= ev
->data3
;
758 return true; // eat events
768 // Make ticcmd_ts for the players.
770 extern int mapcolor_me
;
775 static gamestate_t prevgamestate
;
778 // do player reborns if needed
779 for (i
=0 ; i
<MAXPLAYERS
; i
++)
780 if (playeringame
[i
] && players
[i
].playerstate
== PST_REBORN
)
784 // do things to change the game state
785 while (gameaction
!= ga_nothing
)
790 // force players to be initialized on level reload
791 for (i
=0 ; i
<MAXPLAYERS
; i
++)
792 players
[i
].playerstate
= PST_REBORN
;
802 G_DoSaveGame (false);
821 if (paused
& 2 || (!demoplayback
&& menuactive
&& !netgame
))
822 basetic
++; // For revenant tracers and RNG -- we must maintain sync
825 // get commands, check consistancy, and build new consistancy check
826 int buf
= (gametic
/ticdup
)%BACKUPTICS
;
828 for (i
=0 ; i
<MAXPLAYERS
; i
++)
832 ticcmd_t
*cmd
= &players
[i
].cmd
;
834 memcpy(cmd
, &netcmds
[i
][buf
], sizeof *cmd
);
837 G_ReadDemoTiccmd (cmd
);
839 G_WriteDemoTiccmd (cmd
);
841 // check for turbo cheats
842 // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
844 if ((netgame
|| demoplayback
) && cmd
->forwardmove
> TURBOTHRESHOLD
&&
845 !(gametic
&31) && ((gametic
>>5)&3) == i
)
847 extern char *player_names
[];
848 /* cph - don't use sprintf, use doom_printf */
849 doom_printf ("%s is turbo!", player_names
[i
]);
852 if (netgame
&& !netdemo
&& !(gametic
%ticdup
) )
854 if (gametic
> BACKUPTICS
855 && consistancy
[i
][buf
] != cmd
->consistancy
)
856 I_Error("G_Ticker: Consistency failure (%i should be %i)",
857 cmd
->consistancy
, consistancy
[i
][buf
]);
859 consistancy
[i
][buf
] = players
[i
].mo
->x
;
861 consistancy
[i
][buf
] = 0; // killough 2/14/98
866 // check for special buttons
867 for (i
=0 ; i
<MAXPLAYERS
; i
++)
871 if (players
[i
].cmd
.buttons
& BT_SPECIAL
)
873 switch (players
[i
].cmd
.buttons
& BT_SPECIALMASK
)
884 if (!savedescription
[0])
885 strcpy(savedescription
, "NET GAME");
887 (players
[i
].cmd
.buttons
& BTS_SAVEMASK
)>>BTS_SAVESHIFT
;
888 gameaction
= ga_savegame
;
891 // CPhipps - remote loadgame request
894 (players
[i
].cmd
.buttons
& BTS_SAVEMASK
)>>BTS_SAVESHIFT
;
895 gameaction
= ga_loadgame
;
896 forced_loadgame
= netgame
; // Force if a netgame
897 command_loadgame
= false;
900 // CPhipps - Restart the level
901 case BTS_RESTARTLEVEL
:
902 if (demoplayback
|| (compatibility_level
< lxdoom_1_compatibility
))
903 break; // CPhipps - Ignore in demos or old games
904 gameaction
= ga_loadlevel
;
907 players
[i
].cmd
.buttons
= 0;
913 // cph - if the gamestate changed, we may need to clean up the old gamestate
914 if (gamestate
!= prevgamestate
) {
915 switch (prevgamestate
) {
916 case GS_INTERMISSION
:
921 prevgamestate
= gamestate
;
934 case GS_INTERMISSION
:
950 // PLAYER STRUCTURE FUNCTIONS
951 // also see P_SpawnPlayer in P_Things
955 // G_PlayerFinishLevel
956 // Can when a player completes a level.
958 void G_PlayerFinishLevel(int player
)
960 player_t
*p
= &players
[player
];
961 memset(p
->powers
, 0, sizeof (p
->powers
));
962 memset(p
->cards
, 0, sizeof (p
->cards
));
963 p
->mo
->flags
&= ~MF_SHADOW
; // cancel invisibility
964 p
->extralight
= 0; // cancel gun flashes
965 p
->fixedcolormap
= 0; // cancel ir gogles
966 p
->damagecount
= 0; // no palette changes
970 // CPhipps - G_SetPlayerColour
971 // Player colours stuff
976 extern byte playernumtotrans
[MAXPLAYERS
];
978 void G_ChangedPlayerColour(int pn
, int cl
)
982 if (!netgame
) return;
984 mapcolor_plyr
[pn
] = cl
;
986 // Rebuild colour translation tables accordingly
987 R_InitTranslationTables();
988 // Change translations on existing player mobj's
989 for (i
=0; i
<MAXPLAYERS
; i
++) {
990 if ((gamestate
== GS_LEVEL
) && playeringame
[i
] && (players
[i
].mo
!= NULL
)) {
991 players
[i
].mo
->flags
&= ~MF_TRANSLATION
;
992 players
[i
].mo
->flags
|= playernumtotrans
[i
] << MF_TRANSSHIFT
;
999 // Called after a player dies
1000 // almost everything is cleared and initialized
1002 void G_PlayerReborn (int player
)
1006 int frags
[MAXPLAYERS
];
1011 memcpy (frags
, players
[player
].frags
, sizeof frags
);
1012 killcount
= players
[player
].killcount
;
1013 itemcount
= players
[player
].itemcount
;
1014 secretcount
= players
[player
].secretcount
;
1016 p
= &players
[player
];
1018 // killough 3/10/98,3/21/98: preserve cheats across idclev
1020 int cheats
= p
->cheats
;
1021 memset (p
, 0, sizeof(*p
));
1025 memcpy(players
[player
].frags
, frags
, sizeof(players
[player
].frags
));
1026 players
[player
].killcount
= killcount
;
1027 players
[player
].itemcount
= itemcount
;
1028 players
[player
].secretcount
= secretcount
;
1030 p
->usedown
= p
->attackdown
= true; // don't do anything immediately
1031 p
->playerstate
= PST_LIVE
;
1032 p
->health
= MAXHEALTH
;
1033 p
->readyweapon
= p
->pendingweapon
= wp_pistol
;
1034 p
->weaponowned
[wp_fist
] = true;
1035 p
->weaponowned
[wp_pistol
] = true;
1036 p
->ammo
[am_clip
] = 50;
1038 for (i
=0 ; i
<NUMAMMO
; i
++)
1039 p
->maxammo
[i
] = maxammo
[i
];
1045 // Returns false if the player cannot be respawned
1046 // at the given mapthing_t spot
1047 // because something is occupying it
1050 void P_SpawnPlayer(mapthing_t
*mthing
);
1052 boolean
G_CheckSpot(int playernum
, mapthing_t
*mthing
)
1058 if (!players
[playernum
].mo
)
1060 // first spawn of level, before corpses
1061 for (i
=0 ; i
<playernum
; i
++)
1062 if (players
[i
].mo
->x
== mthing
->x
<< FRACBITS
1063 && players
[i
].mo
->y
== mthing
->y
<< FRACBITS
)
1068 x
= mthing
->x
<< FRACBITS
;
1069 y
= mthing
->y
<< FRACBITS
;
1071 // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
1072 // corpse to detect collisions with other players in DM starts
1075 // if (!P_CheckPosition (players[playernum].mo, x, y))
1078 players
[playernum
].mo
->flags
|= MF_SOLID
;
1079 i
= P_CheckPosition(players
[playernum
].mo
, x
, y
);
1080 players
[playernum
].mo
->flags
&= ~MF_SOLID
;
1084 // flush an old corpse if needed
1085 // killough 2/8/98: make corpse queue have an adjustable limit
1086 // killough 8/1/98: Fix bugs causing strange crashes
1088 if (bodyquesize
> 0)
1090 static mobj_t
**bodyque
;
1091 static int queuesize
;
1092 if (queuesize
< bodyquesize
)
1094 bodyque
= realloc(bodyque
, bodyquesize
*sizeof*bodyque
);
1095 memset(bodyque
+queuesize
, 0,
1096 (bodyquesize
-queuesize
)*sizeof*bodyque
);
1097 queuesize
= bodyquesize
;
1099 if (bodyqueslot
>= bodyquesize
)
1100 P_RemoveMobj(bodyque
[bodyqueslot
% bodyquesize
]);
1101 bodyque
[bodyqueslot
++ % bodyquesize
] = players
[playernum
].mo
;
1105 P_RemoveMobj(players
[playernum
].mo
);
1107 // spawn a teleport fog
1108 ss
= R_PointInSubsector (x
,y
);
1109 { // Teleport fog at respawn point
1114 /* BUG: an can end up negative, because mthing->angle is (signed) short.
1115 * We have to emulate original Doom's behaviour, deferencing past the start
1116 * of the array, into the previous array (finetangent) */
1117 an
= ( ANG45
* ((signed)mthing
->angle
/45) ) >> ANGLETOFINESHIFT
;
1119 case -4096: xa
= finetangent
[2048]; // finecosine[-4096]
1120 ya
= finetangent
[0]; // finesine[-4096]
1122 case -3072: xa
= finetangent
[3072]; // finecosine[-3072]
1123 ya
= finetangent
[1024]; // finesine[-3072]
1125 case -2048: xa
= finesine
[0]; // finecosine[-2048]
1126 ya
= finetangent
[2048]; // finesine[-2048]
1128 case -1024: xa
= finesine
[1024]; // finecosine[-1024]
1129 ya
= finetangent
[3072]; // finesine[-1024]
1135 case 0: xa
= finecosine
[an
];
1138 default: I_Error("G_CheckSpot: unexpected angle %d\n",an
);
1142 mo
= P_SpawnMobj(x
+20*xa
, y
+20*ya
, ss
->sector
->floorheight
, MT_TFOG
);
1144 if (players
[consoleplayer
].viewz
!= 1)
1145 S_StartSound(mo
, sfx_telept
); // don't start sound on first frame
1153 // G_DeathMatchSpawnPlayer
1154 // Spawns a player at one of the random death match spots
1155 // called at level load and each death
1157 void G_DeathMatchSpawnPlayer (int playernum
)
1159 int j
, selections
= deathmatch_p
- deathmatchstarts
;
1161 if (selections
< MAXPLAYERS
)
1162 I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required",
1163 selections
, MAXPLAYERS
);
1165 for (j
=0 ; j
<20 ; j
++)
1167 int i
= P_Random(pr_dmspawn
) % selections
;
1168 if (G_CheckSpot (playernum
, &deathmatchstarts
[i
]) )
1170 deathmatchstarts
[i
].type
= playernum
+1;
1171 P_SpawnPlayer (&deathmatchstarts
[i
]);
1176 // no good spot, so the player will probably get stuck
1177 P_SpawnPlayer (&playerstarts
[playernum
]);
1184 void G_DoReborn (int playernum
)
1187 gameaction
= ga_loadlevel
; // reload the level from scratch
1191 { // respawn at the start
1194 // first dissasociate the corpse
1195 players
[playernum
].mo
->player
= NULL
;
1197 // spawn at random spot if in death match
1200 G_DeathMatchSpawnPlayer (playernum
);
1204 if (G_CheckSpot (playernum
, &playerstarts
[playernum
]) )
1206 P_SpawnPlayer (&playerstarts
[playernum
]);
1210 // try to spawn at one of the other players spots
1211 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1213 if (G_CheckSpot (playernum
, &playerstarts
[i
]) )
1215 playerstarts
[i
].type
= playernum
+1; // fake as other player
1216 P_SpawnPlayer (&playerstarts
[i
]);
1217 playerstarts
[i
].type
= i
+1; // restore
1220 // he's going to be inside something. Too bad.
1222 P_SpawnPlayer (&playerstarts
[playernum
]);
1231 {0,30,75,120,90,165,180,180,30,165},
1232 {0,90,90,90,120,90,360,240,30,170},
1233 {0,90,45,90,150,90,90,165,30,135}
1236 // DOOM II Par Times
1239 30,90,120,120,90,150,120,120,270,90, // 1-10
1240 210,150,150,150,210,150,420,150,210,150, // 11-20
1241 240,150,180,150,150,300,330,420,300,180, // 21-30
1245 static boolean secretexit
;
1247 void G_ExitLevel (void)
1250 gameaction
= ga_completed
;
1253 // Here's for the german edition.
1254 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1256 void G_SecretExitLevel (void)
1258 if (gamemode
!=commercial
|| haswolflevels
)
1262 gameaction
= ga_completed
;
1269 void G_DoCompleted (void)
1273 gameaction
= ga_nothing
;
1275 for (i
=0; i
<MAXPLAYERS
; i
++)
1276 if (playeringame
[i
])
1277 G_PlayerFinishLevel(i
); // take away cards and stuff
1279 if (automapmode
& am_active
)
1282 if (gamemode
!= commercial
) // kilough 2/7/98
1285 // cph - Remove ExM8 special case, so it gets summary screen displayed
1287 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1288 players
[i
].didsecret
= true;
1292 wminfo
.didsecret
= players
[consoleplayer
].didsecret
;
1293 wminfo
.epsd
= gameepisode
-1;
1294 wminfo
.last
= gamemap
-1;
1296 // wminfo.next is 0 biased, unlike gamemap
1297 if (gamemode
== commercial
)
1303 wminfo
.next
= 30; break;
1305 wminfo
.next
= 31; break;
1312 wminfo
.next
= 15; break;
1314 wminfo
.next
= gamemap
;
1320 wminfo
.next
= 8; // go to secret level
1324 // returning from secret level
1325 switch (gameepisode
)
1342 wminfo
.next
= gamemap
; // go to next level
1345 wminfo
.maxkills
= totalkills
;
1346 wminfo
.maxitems
= totalitems
;
1347 wminfo
.maxsecret
= totalsecret
;
1348 wminfo
.maxfrags
= 0;
1350 if ( gamemode
== commercial
)
1351 wminfo
.partime
= TICRATE
*cpars
[gamemap
-1];
1353 wminfo
.partime
= TICRATE
*pars
[gameepisode
][gamemap
];
1355 wminfo
.pnum
= consoleplayer
;
1357 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1359 wminfo
.plyr
[i
].in
= playeringame
[i
];
1360 wminfo
.plyr
[i
].skills
= players
[i
].killcount
;
1361 wminfo
.plyr
[i
].sitems
= players
[i
].itemcount
;
1362 wminfo
.plyr
[i
].ssecret
= players
[i
].secretcount
;
1363 wminfo
.plyr
[i
].stime
= leveltime
;
1364 memcpy (wminfo
.plyr
[i
].frags
, players
[i
].frags
,
1365 sizeof(wminfo
.plyr
[i
].frags
));
1368 /* cph - modified so that only whole seconds are added to the totalleveltimes
1369 * value; so our total is compatible with the "naive" total of just adding
1370 * the times in seconds shown for each level. Also means our total time
1371 * will agree with Compet-n.
1373 wminfo
.totaltimes
= (totalleveltimes
+= (leveltime
- leveltime
%35));
1375 gamestate
= GS_INTERMISSION
;
1376 automapmode
&= ~am_active
;
1379 memcpy (statcopy
, &wminfo
, sizeof(wminfo
));
1389 void G_WorldDone (void)
1391 gameaction
= ga_worlddone
;
1394 players
[consoleplayer
].didsecret
= true;
1396 if (gamemode
== commercial
)
1412 else if (gamemap
== 8)
1413 gameaction
= ga_victory
; // cph - after ExM8 summary screen, show victory stuff
1416 void G_DoWorldDone (void)
1418 idmusnum
= -1; //jff 3/17/98 allow new level's music to be loaded
1419 gamestate
= GS_LEVEL
;
1420 gamemap
= wminfo
.next
+1;
1422 gameaction
= ga_nothing
;
1423 AM_clearMarks(); //jff 4/12/98 clear any marks on the automap
1426 // killough 2/28/98: A ridiculously large number
1427 // of players, the most you'll ever need in a demo
1428 // or savegame. This is used to prevent problems, in
1429 // case more players in a game are supported later.
1431 #define MIN_MAXPLAYERS 32
1433 extern boolean setsizeneeded
;
1434 void R_ExecuteSetViewSize(void);
1436 //CPhipps - savename variable redundant
1439 * This function returns a signature for the current wad.
1440 * It is used to distinguish between wads, for the purposes
1441 * of savegame compatibility warnings, and options lookups.
1444 static uint_64_t
G_UpdateSignature(uint_64_t s
, const char *name
)
1446 int i
, lump
= W_CheckNumForName(name
);
1447 if (lump
!= -1 && (i
= lump
+10) < numlumps
)
1450 int size
= W_LumpLength(i
);
1451 const byte
*p
= W_CacheLumpNum(i
);
1460 static uint_64_t
G_Signature(void)
1462 static uint_64_t s
= 0;
1463 static boolean computed
= false;
1469 if (gamemode
== commercial
)
1470 for (map
= haswolflevels
? 32 : 30; map
; map
--)
1471 snprintf(name
, sizeof(name
), "map%02d", map
), s
= G_UpdateSignature(s
, name
);
1473 for (episode
= gamemode
==retail
? 4 :
1474 gamemode
==shareware
? 1 : 3; episode
; episode
--)
1475 for (map
= 9; map
; map
--)
1476 snprintf(name
, sizeof(name
), "E%dM%d", episode
, map
), s
= G_UpdateSignature(s
, name
);
1482 // killough 5/15/98: add forced loadgames, which allow user to override checks
1485 void G_ForcedLoadGame(void)
1487 // CPhipps - net loadgames are always forced, so we only reach here
1489 gameaction
= ga_loadgame
;
1490 forced_loadgame
= true;
1493 // killough 3/16/98: add slot info
1494 // killough 5/15/98: add command-line
1495 void G_LoadGame(int slot
, boolean command
)
1497 if (!demoplayback
&& !command
) {
1498 // CPhipps - handle savegame filename in G_DoLoadGame
1499 // - Delay load so it can be communicated in net game
1500 // - store info in special_event
1501 special_event
= BT_SPECIAL
| (BTS_LOADGAME
& BT_SPECIALMASK
) |
1502 ((slot
<< BTS_SAVESHIFT
) & BTS_SAVEMASK
);
1503 forced_loadgame
= netgame
; // CPhipps - always force load netgames
1505 // Do the old thing, immediate load
1506 gameaction
= ga_loadgame
;
1507 forced_loadgame
= false;
1508 savegameslot
= slot
;
1509 demoplayback
= false;
1511 command_loadgame
= command
;
1514 // killough 5/15/98:
1515 // Consistency Error when attempting to load savegame.
1517 static void G_LoadGameErr(const char *msg
)
1519 (void) msg
; // Need to fix, but right now we're ignoring a forced load
1520 Z_Free(savebuffer
); // Free the savegame buffer
1521 // M_ForcedLoadGame(msg); // Print message asking for 'Y' to force
1522 if (command_loadgame
) // If this was a command-line -loadgame
1524 D_StartTitle(); // Start the title screen
1525 gamestate
= GS_DEMOSCREEN
; // And set the game state accordingly
1529 // CPhipps - size of version header
1530 #define VERSIONSIZE 16
1532 const char * comp_lev_str
[MAX_COMPATIBILITY_LEVEL
] =
1533 { "doom v1.2", "demo", "doom", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+",
1534 "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1",
1537 static const struct {
1538 unsigned int comp_level
;
1539 const char* ver_printf
;
1541 } version_headers
[] = {
1542 { prboom_1_compatibility
, "PrBoom %d", 260},
1543 /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since
1544 * the file format is unchanged. */
1545 { prboom_3_compatibility
, "PrBoom %d", 210}
1548 static const size_t num_version_headers
= sizeof(version_headers
) / sizeof(version_headers
[0]);
1550 void G_DoLoadGame(void)
1553 // CPhipps - do savegame filename stuff here
1554 char name
[100+1]; // killough 3/22/98
1555 int savegame_compatibility
= -1;
1557 G_SaveGameName(name
,sizeof(name
),savegameslot
, demoplayback
);
1559 gameaction
= ga_nothing
;
1561 length
= M_ReadFile(name
, &savebuffer
);
1562 save_p
= savebuffer
+ SAVESTRINGSIZE
;
1564 // CPhipps - read the description field, compare with supported ones
1565 for (i
=0; (size_t)i
<num_version_headers
; i
++) {
1566 char vcheck
[VERSIONSIZE
];
1567 // killough 2/22/98: "proprietary" version string :-)
1568 snprintf (vcheck
,sizeof(vcheck
), version_headers
[i
].ver_printf
, version_headers
[i
].version
);
1570 if (!strncmp(save_p
, vcheck
, VERSIONSIZE
)) {
1571 savegame_compatibility
= version_headers
[i
].comp_level
;
1572 i
= num_version_headers
;
1575 if (savegame_compatibility
== -1) {
1576 if (forced_loadgame
) {
1577 savegame_compatibility
= MAX_COMPATIBILITY_LEVEL
-1;
1579 G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
1584 save_p
+= VERSIONSIZE
;
1586 // CPhipps - always check savegames even when forced,
1587 // only print a warning if forced
1588 { // killough 3/16/98: check lump name checksum (independent of order)
1589 uint_64_t checksum
= 0;
1591 checksum
= G_Signature();
1593 if (memcmp(&checksum
, save_p
, sizeof checksum
)) {
1594 if (!forced_loadgame
) {
1595 char *msg
= malloc(strlen(save_p
+ sizeof checksum
) + 128);
1596 strcpy(msg
,"Incompatible Savegame!!!\n");
1597 if (save_p
[sizeof checksum
])
1598 strcat(strcat(msg
,"Wads expected:\n\n"), save_p
+ sizeof checksum
);
1599 strcat(msg
, "\nAre you sure?");
1604 printf("G_DoLoadGame: Incompatible savegame\n");
1606 save_p
+= sizeof checksum
;
1609 save_p
+= strlen(save_p
)+1;
1611 /* cph - FIXME - compatibility flag? */
1612 compatibility_level
= savegame_compatibility
;
1615 gameskill
= *save_p
++;
1616 gameepisode
= *save_p
++;
1617 gamemap
= *save_p
++;
1619 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1620 playeringame
[i
] = *save_p
++;
1621 save_p
+= MIN_MAXPLAYERS
-MAXPLAYERS
; // killough 2/28/98
1623 idmusnum
= *save_p
++; // jff 3/17/98 restore idmus music
1624 if (idmusnum
==255) idmusnum
=-1; // jff 3/18/98 account for unsigned byte
1626 /* killough 3/1/98: Read game options
1627 * killough 11/98: move down to here
1629 save_p
= (char*)G_ReadOptions(save_p
);
1631 // load a base level
1632 G_InitNew (gameskill
, gameepisode
, gamemap
);
1634 /* get the times - killough 11/98: save entire word */
1635 memcpy(&leveltime
, save_p
, sizeof leveltime
);
1636 save_p
+= sizeof leveltime
;
1638 /* cph - total episode time */
1639 if (compatibility_level
>= prboom_2_compatibility
) {
1640 memcpy(&totalleveltimes
, save_p
, sizeof totalleveltimes
);
1641 save_p
+= sizeof totalleveltimes
;
1643 else totalleveltimes
= 0;
1645 // killough 11/98: load revenant tracer state
1646 basetic
= gametic
- *save_p
++;
1648 // dearchive all the modifications
1649 P_UnArchivePlayers ();
1650 P_UnArchiveWorld ();
1651 P_UnArchiveThinkers ();
1652 P_UnArchiveSpecials ();
1653 P_UnArchiveRNG (); // killough 1/18/98: load RNG information
1654 P_UnArchiveMap (); // killough 1/22/98: load automap information
1656 if (*save_p
!= 0xe6)
1657 I_Error ("G_DoLoadGame: Bad savegame");
1660 Z_Free (savebuffer
);
1663 R_ExecuteSetViewSize ();
1665 // draw the pattern into the back screen
1666 R_FillBackScreen ();
1668 /* killough 12/98: support -recordfrom and -loadgame -playdemo */
1669 if (!command_loadgame
)
1670 singledemo
= false; /* Clear singledemo flag if loading from menu */
1673 gameaction
= ga_loadgame
; /* Mark that we're loading a game before demo */
1674 G_DoPlayDemo(); /* This will detect it and won't reinit level */
1675 } else /* Command line + record means it's a recordfrom */
1682 // Called by the menu task.
1683 // Description is a 24 byte text string
1686 void G_SaveGame(int slot
, char *description
)
1688 strcpy(savedescription
, description
);
1690 /* cph - We're doing a user-initiated save game while a demo is
1691 * running so, go outside normal mechanisms
1693 savegameslot
= slot
;
1696 // CPhipps - store info in special_event
1697 special_event
= BT_SPECIAL
| (BTS_SAVEGAME
& BT_SPECIALMASK
) |
1698 ((slot
<< BTS_SAVESHIFT
) & BTS_SAVEMASK
);
1700 D_NetSendMisc(nm_savegamename
, strlen(savedescription
)+1, savedescription
);
1704 // Check for overrun and realloc if necessary -- Lee Killough 1/22/98
1705 void CheckSaveGame(size_t size
)
1707 size_t pos
= save_p
- savebuffer
;
1708 size
+= 1024; // breathing room
1709 if (pos
+size
> savegamesize
)
1710 save_p
= (savebuffer
= realloc(savebuffer
,
1711 savegamesize
+= (size
+1023) & ~1023)) + pos
;
1714 /* killough 3/22/98: form savegame name in one location
1715 * (previously code was scattered around in multiple places)
1716 * cph - Avoid possible buffer overflow problems by passing
1717 * size to this function and using snprintf */
1719 void G_SaveGameName(char *name
, size_t size
, int slot
, boolean demoplayback
)
1721 const char* sgn
= demoplayback
? "demosav" : SAVEGAMENAME
;
1722 snprintf (name
, size
, "%s%d.dsg", sgn
, slot
);
1725 static void G_DoSaveGame (boolean menu
)
1728 char name2
[VERSIONSIZE
];
1732 gameaction
= ga_nothing
; // cph - cancel savegame at top of this function,
1733 // in case later problems cause a premature exit
1735 G_SaveGameName(name
,sizeof(name
),savegameslot
, demoplayback
&& !menu
);
1737 description
= savedescription
;
1739 save_p
= savebuffer
= malloc(savegamesize
);
1741 CheckSaveGame(SAVESTRINGSIZE
+VERSIONSIZE
+sizeof(unsigned long));
1742 memcpy (save_p
, description
, SAVESTRINGSIZE
);
1743 save_p
+= SAVESTRINGSIZE
;
1744 memset (name2
,0,sizeof(name2
));
1746 // CPhipps - scan for the version header
1747 for (i
=0; (size_t)i
<num_version_headers
; i
++)
1748 if (version_headers
[i
].comp_level
== compatibility_level
) {
1749 // killough 2/22/98: "proprietary" version string :-)
1750 snprintf (name2
,sizeof(name2
),version_headers
[i
].ver_printf
,version_headers
[i
].version
);
1751 memcpy (save_p
, name2
, VERSIONSIZE
);
1752 i
= num_version_headers
+1;
1755 if ((size_t)i
== num_version_headers
) {
1756 doom_printf("No savegame signature known for\nthis compatibility level\n"
1757 "%d/%d, %d registered", compatibility_level
,
1758 MAX_COMPATIBILITY_LEVEL
, (signed)num_version_headers
);
1759 free(savebuffer
); // cph - free data
1763 save_p
+= VERSIONSIZE
;
1765 { /* killough 3/16/98, 12/98: store lump name checksum */
1766 uint_64_t checksum
= G_Signature();
1767 memcpy(save_p
, &checksum
, sizeof checksum
);
1768 save_p
+= sizeof checksum
;
1771 // killough 3/16/98: store pwad filenames in savegame
1773 // CPhipps - changed for new wadfiles handling
1775 for (*save_p
= 0; (size_t)i
<numwadfiles
; i
++)
1777 const char *const w
= wadfiles
[i
].name
;
1778 CheckSaveGame(strlen(w
)+2);
1779 strcat(strcat(save_p
, w
), "\n");
1781 save_p
+= strlen(save_p
)+1;
1784 CheckSaveGame(GAME_OPTION_SIZE
+MIN_MAXPLAYERS
+10);
1786 /* cph - FIXME? - Save compatibility level */
1789 *save_p
++ = gameskill
;
1790 *save_p
++ = gameepisode
;
1791 *save_p
++ = gamemap
;
1793 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1794 *save_p
++ = playeringame
[i
];
1796 for (;i
<MIN_MAXPLAYERS
;i
++) // killough 2/28/98
1799 *save_p
++ = idmusnum
; // jff 3/17/98 save idmus state
1801 save_p
= G_WriteOptions(save_p
); // killough 3/1/98: save game options
1803 /* cph - FIXME - endianness? */
1804 /* killough 11/98: save entire word */
1805 memcpy(save_p
, &leveltime
, sizeof leveltime
);
1806 save_p
+= sizeof leveltime
;
1808 /* cph - total episode time */
1809 if (compatibility_level
>= prboom_2_compatibility
) {
1810 memcpy(save_p
, &totalleveltimes
, sizeof totalleveltimes
);
1811 save_p
+= sizeof totalleveltimes
;
1813 else totalleveltimes
= 0;
1815 // killough 11/98: save revenant tracer state
1816 *save_p
++ = (gametic
-basetic
) & 255;
1818 // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
1823 // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the
1824 // indices can be used by P_ArchiveWorld when the sectors are saved.
1825 // This is so we can save the index of the mobj_t of the thinker that
1826 // caused a sound, referenced by sector_t->soundtarget.
1831 P_ArchiveThinkers();
1833 // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply
1834 // for symmetry with the P_ThinkerToIndex call above.
1839 P_ArchiveSpecials();
1840 P_ArchiveRNG(); // killough 1/18/98: save RNG information
1842 P_ArchiveMap(); // killough 1/22/98: save automap information
1844 *save_p
++ = 0xe6; // consistancy marker
1846 length
= save_p
- savebuffer
;
1849 doom_printf( "%s", M_WriteFile(name
, savebuffer
, length
)
1850 ? GGSAVED
/* Ty - externalised */
1851 : "Game save failed!"); // CPhipps - not externalised
1853 free(savebuffer
); // killough
1854 savebuffer
= save_p
= NULL
;
1856 savedescription
[0] = 0;
1859 static skill_t d_skill
;
1860 static int d_episode
;
1863 void G_DeferedInitNew(skill_t skill
, int episode
, int map
)
1866 d_episode
= episode
;
1868 gameaction
= ga_newgame
;
1871 extern int variable_friction
;
1872 extern int default_variable_friction
; // ice & mud
1874 extern int weapon_recoil
, default_weapon_recoil
; // weapon recoil
1876 extern int allow_pushers
;
1877 extern int default_allow_pushers
; // MT_PUSH Things
1879 extern int player_bobbing
;
1880 extern int default_player_bobbing
; // whether player bobs or not
1882 extern int monsters_remember
, default_monsters_remember
;
1887 * Initialises the comp[] array based on the compatibility_level
1888 * For reference, MBF did:
1889 * for (i=0; i < COMP_TOTAL; i++)
1890 * comp[i] = compatibility;
1892 * Instead, we have a lookup table showing at what version a fix was
1896 void G_Compatibility(void)
1898 static const complevel_t fix_levels
[COMP_NUM
] = {
1899 mbf_compatibility
, /* comp_telefrag - monsters used to telefrag only
1900 * on MAP30, now they do it for spawners only */
1901 mbf_compatibility
, /* comp_dropoff - MBF encourages things to drop
1902 * off of overhangs */
1903 boom_compatibility
,/* comp_vile - original Doom archville bugs like
1905 boom_compatibility
,/* comp_pain - original Doom limits Pain Elements
1906 * from spawning too many skulls */
1907 boom_compatibility
,/* comp_skull - original Doom let skulls be spit
1908 * through walls by Pain Elementals */
1909 boom_compatibility
,/* comp_blazing - original Doom duplicated
1910 * blazing door sound */
1911 mbf_compatibility
, /* comp_doorlight - MBF made door lighting changes
1913 boom_compatibility
,/* comp_model - improvements to the game physics */
1914 boom_compatibility
,/* comp_god - fixes to God mode */
1915 mbf_compatibility
, /* comp_falloff - MBF encourages things to drop
1916 * off of overhangs */
1917 boom_compatibility_compatibility
,
1918 /* comp_floors - fixes for moving floors bugs */
1919 boom_compatibility
,/* comp_skymap */
1920 mbf_compatibility
, /* comp_pursuit - MBF AI change, limited pursuit? */
1921 boom_compatibility
,/* comp_doorstuck - monsters stuck in doors fix */
1922 mbf_compatibility
, /* comp_staylift - MBF AI change, monsters try
1923 * to stay on lifts */
1924 lxdoom_1_compatibility
, /* comp_zombie - prevent dead players
1925 * triggering stuff */
1926 boom_compatibility_compatibility
, /* comp_stairs - see p_floor.c */
1927 mbf_compatibility
, /* comp_infcheat - FIXME */
1928 boom_compatibility
,/* comp_zerotags - allow zero tags in wads */
1929 lxdoom_1_compatibility
, /* comp_moveblock - enables keygrab and
1930 * mancubi shots going thru walls */
1931 prboom_2_compatibility
, /* comp_respawn - objects which aren't on the map
1932 * at game start respawn at (0,0) */
1933 boom_compatibility_compatibility
, /* comp_sound - see s_sound.c */
1936 for (i
=0; i
<COMP_NUM
; i
++)
1937 comp
[i
] = compatibility_level
< fix_levels
[i
];
1938 for (; i
<COMP_TOTAL
; i
++) comp
[i
] = 1;
1942 /* killough 7/19/98: Marine's best friend :) */
1943 static int G_GetHelpers(void)
1945 int j
= M_CheckParm ("-dog");
1948 j
= M_CheckParm ("-dogs");
1949 return j
? j
+1 < myargc
? atoi(myargv
[j
+1]) : 1 : default_dogs
;
1954 // killough 3/1/98: function to reload all the default parameter
1955 // settings before a new game begins
1957 void G_ReloadDefaults(void)
1959 // killough 3/1/98: Initialize options based on config file
1960 // (allows functions above to load different values for demos
1961 // and savegames without messing up defaults).
1963 weapon_recoil
= default_weapon_recoil
; // weapon recoil
1965 player_bobbing
= default_player_bobbing
; // whether player bobs or not
1967 variable_friction
= allow_pushers
= true;
1969 monsters_remember
= default_monsters_remember
; // remember former enemies
1971 monster_infighting
= default_monster_infighting
; // killough 7/19/98
1974 dogs
= netgame
? 0 : G_GetHelpers(); // killough 7/19/98
1975 dog_jumping
= default_dog_jumping
;
1978 distfriend
= default_distfriend
; // killough 8/8/98
1980 monster_backing
= default_monster_backing
; // killough 9/8/98
1982 monster_avoid_hazards
= default_monster_avoid_hazards
; // killough 9/9/98
1984 monster_friction
= default_monster_friction
; // killough 10/98
1986 help_friends
= default_help_friends
; // killough 9/9/98
1988 monkeys
= default_monkeys
;
1990 // jff 1/24/98 reset play mode to command line spec'd version
1991 // killough 3/1/98: moved to here
1992 // respawnparm = clrespawnparm;
1993 // fastparm = clfastparm;
1994 // nomonsters = clnomonsters;
1996 //jff 3/24/98 set startskill from defaultskill in config file, unless
1997 // it has already been set by a -skill parameter
1998 if (startskill
==sk_none
)
1999 startskill
= (skill_t
)(defaultskill
-1);
2001 demoplayback
= false;
2002 singledemo
= false; // killough 9/29/98: don't stop after 1 demo
2005 // killough 2/21/98:
2006 memset(playeringame
+1, 0, sizeof(*playeringame
)*(MAXPLAYERS
-1));
2010 compatibility_level
= default_compatibility_level
;
2012 int i
= M_CheckParm("-complevel");
2013 if (i
&& (1+i
) < myargc
) compatibility_level
= atoi(myargv
[i
+1]);
2015 if ((signed)compatibility_level
== -1)
2016 compatibility_level
= MAX_COMPATIBILITY_LEVEL
-1;
2019 memcpy(comp
, default_comp
, sizeof comp
);
2023 // killough 3/31/98, 4/5/98: demo sync insurance
2024 demo_insurance
= default_demo_insurance
== 1;
2026 rngseed
+= 1 + gametic
; // CPhipps
2027 // rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
2030 void G_DoNewGame (void)
2032 G_ReloadDefaults(); // killough 3/1/98
2033 netgame
= false; // killough 3/1/98
2035 G_InitNew (d_skill
, d_episode
, d_map
);
2036 gameaction
= ga_nothing
;
2038 //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
2042 // killough 4/10/98: New function to fix bug which caused Doom
2043 // lockups when idclev was used in conjunction with -fast.
2045 void G_SetFastParms(int fast_pending
)
2047 static int fast
= 0; // remembers fast state
2049 if (fast
!= fast_pending
) { /* only change if necessary */
2050 if ((fast
= fast_pending
))
2052 for (i
=S_SARG_RUN1
; i
<=S_SARG_PAIN2
; i
++)
2053 if (states
[i
].tics
!= 1 || demo_compatibility
) // killough 4/10/98
2054 states
[i
].tics
>>= 1; // don't change 1->0 since it causes cycles
2055 mobjinfo
[MT_BRUISERSHOT
].speed
= 20*FRACUNIT
;
2056 mobjinfo
[MT_HEADSHOT
].speed
= 20*FRACUNIT
;
2057 mobjinfo
[MT_TROOPSHOT
].speed
= 20*FRACUNIT
;
2061 for (i
=S_SARG_RUN1
; i
<=S_SARG_PAIN2
; i
++)
2062 states
[i
].tics
<<= 1;
2063 mobjinfo
[MT_BRUISERSHOT
].speed
= 15*FRACUNIT
;
2064 mobjinfo
[MT_HEADSHOT
].speed
= 10*FRACUNIT
;
2065 mobjinfo
[MT_TROOPSHOT
].speed
= 10*FRACUNIT
;
2070 // The sky texture to be used instead of the F_SKY1 dummy.
2071 extern int skytexture
;
2075 // Can be called by the startup code or the menu task,
2076 // consoleplayer, displayplayer, playeringame[] should be set.
2079 void G_InitNew(skill_t skill
, int episode
, int map
)
2089 if (skill
> sk_nightmare
)
2090 skill
= sk_nightmare
;
2095 if (gamemode
== retail
)
2101 if (gamemode
== shareware
)
2104 episode
= 1; // only start episode 1 on shareware
2112 if (map
> 9 && gamemode
!= commercial
)
2115 G_SetFastParms(fastparm
|| skill
== sk_nightmare
); // killough 4/10/98
2119 respawnmonsters
= skill
== sk_nightmare
|| respawnparm
;
2121 // force players to be initialized upon first level load
2122 for (i
=0 ; i
<MAXPLAYERS
; i
++)
2123 players
[i
].playerstate
= PST_REBORN
;
2125 usergame
= true; // will be set false if a demo
2127 automapmode
&= ~am_active
;
2128 gameepisode
= episode
;
2132 totalleveltimes
= 0; // cph
2134 //jff 4/16/98 force marks on automap cleared every new level start
2145 unsigned char DEMOMARKER
=0x80;
2147 void G_ReadDemoTiccmd (ticcmd_t
* cmd
)
2149 if (*demo_p
== DEMOMARKER
)
2150 G_CheckDemoStatus(); // end of demo data stream
2153 cmd
->forwardmove
= ((signed char)*demo_p
++);
2154 cmd
->sidemove
= ((signed char)*demo_p
++);
2156 cmd
->angleturn
= ((unsigned char)*demo_p
++)<<8;
2158 unsigned int lowbyte
= (unsigned char)*demo_p
++;
2159 cmd
->angleturn
= (((signed int)(*demo_p
++))<<8) + lowbyte
;
2161 cmd
->buttons
= (unsigned char)*demo_p
++;
2165 /* Demo limits removed -- killough
2166 * cph - record straight to file
2168 void G_WriteDemoTiccmd (ticcmd_t
* cmd
)
2173 *p
++ = cmd
->forwardmove
;
2174 *p
++ = cmd
->sidemove
;
2176 *p
++ = (cmd
->angleturn
+128)>>8;
2178 signed short a
= cmd
->angleturn
;
2180 *p
++ = (a
>> 8) & 0xff;
2182 *p
++ = cmd
->buttons
;
2183 if (write(demofd
, buf
, p
-buf
) != p
-buf
)
2184 I_Error("G_WriteDemoTiccmd: error writing demo");
2186 /* cph - alias demo_p to it so we can read it back */
2188 G_ReadDemoTiccmd (cmd
); // make SURE it is exactly the same
2195 void G_RecordDemo (const char* name
)
2199 AddDefaultExtension(strcpy(demoname
, name
), ".lmp"); // 1/18/98 killough
2200 demorecording
= true;
2201 /* cph - Record demos straight to file
2202 * If file already exists, try to continue existing demo
2204 if (fileexists(demoname
)) {
2205 demofd
= open(demoname
, O_WRONLY
| O_APPEND
);
2207 demofd
= open(demoname
, O_WRONLY
| O_RDONLY
);
2214 read(demofd
, buf
, sizeof(buf
));
2216 len
= G_ReadDemoHeader(buf
) - buf
;
2217 lseek(demofd
, len
, SEEK_SET
);
2221 rc
= read(demofd
, buf
, sizeof(buf
));
2222 if (buf
[0] == DEMOMARKER
) break;
2223 if (buf
[3] & BT_SPECIAL
)
2224 if ((buf
[3] & BT_SPECIALMASK
) == BTS_SAVEGAME
)
2225 slot
= (buf
[3] & BTS_SAVEMASK
)>>BTS_SAVESHIFT
;
2226 } while (rc
== /* sizeof(buf) is out of scope here */ 4 );
2227 if (slot
== -1) I_Error("G_RecordDemo: No save in demo, can't continue");
2228 lseek(demofd
, -rc
, SEEK_CUR
);
2229 G_LoadGame(slot
, false);
2233 if (!demofd
) I_Error("G_RecordDemo: failed to open %s", name
);
2236 // These functions are used to read and write game-specific options in demos
2237 // and savegames so that demo sync is preserved and savegame restoration is
2238 // complete. Not all options (for example "compatibility"), however, should
2239 // be loaded and saved here. It is extremely important to use the same
2240 // positions as before for the variables, so if one becomes obsolete, the
2241 // byte(s) should still be skipped over or padded with 0's.
2242 // Lee Killough 3/1/98
2244 extern int forceOldBsp
;
2246 byte
*G_WriteOptions(byte
*demo_p
)
2248 byte
*target
= demo_p
+ GAME_OPTION_SIZE
;
2250 *demo_p
++ = monsters_remember
; // part of monster AI
2252 *demo_p
++ = variable_friction
; // ice & mud
2254 *demo_p
++ = weapon_recoil
; // weapon recoil
2256 *demo_p
++ = allow_pushers
; // MT_PUSH Things
2260 *demo_p
++ = player_bobbing
; // whether player bobs or not
2262 // killough 3/6/98: add parameters to savegame, move around some in demos
2263 *demo_p
++ = respawnparm
;
2264 *demo_p
++ = fastparm
;
2265 *demo_p
++ = nomonsters
;
2267 *demo_p
++ = demo_insurance
; // killough 3/31/98
2269 // killough 3/26/98: Added rngseed. 3/31/98: moved here
2270 *demo_p
++ = (byte
)((rngseed
>> 24) & 0xff);
2271 *demo_p
++ = (byte
)((rngseed
>> 16) & 0xff);
2272 *demo_p
++ = (byte
)((rngseed
>> 8) & 0xff);
2273 *demo_p
++ = (byte
)( rngseed
& 0xff);
2275 // Options new to v2.03 begin here
2277 *demo_p
++ = monster_infighting
; // killough 7/19/98
2280 *demo_p
++ = dogs
; // killough 7/19/98
2288 *demo_p
++ = (distfriend
>> 8) & 0xff; // killough 8/8/98
2289 *demo_p
++ = distfriend
& 0xff; // killough 8/8/98
2291 *demo_p
++ = monster_backing
; // killough 9/8/98
2293 *demo_p
++ = monster_avoid_hazards
; // killough 9/9/98
2295 *demo_p
++ = monster_friction
; // killough 10/98
2297 *demo_p
++ = help_friends
; // killough 9/9/98
2300 *demo_p
++ = dog_jumping
;
2305 *demo_p
++ = monkeys
;
2307 { // killough 10/98: a compatibility vector now
2309 for (i
=0; i
< COMP_TOTAL
; i
++)
2310 *demo_p
++ = comp
[i
] != 0;
2313 *demo_p
++ = (compatibility_level
>= prboom_2_compatibility
) && forceOldBsp
; // cph 2002/07/20
2318 while (demo_p
< target
)
2321 if (demo_p
!= target
)
2322 I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small");
2327 /* Same, but read instead of write
2328 * cph - const byte*'s
2331 const byte
*G_ReadOptions(const byte
*demo_p
)
2333 const byte
*target
= demo_p
+ GAME_OPTION_SIZE
;
2335 monsters_remember
= *demo_p
++;
2337 variable_friction
= *demo_p
; // ice & mud
2340 weapon_recoil
= *demo_p
; // weapon recoil
2343 allow_pushers
= *demo_p
; // MT_PUSH Things
2348 player_bobbing
= *demo_p
; // whether player bobs or not
2351 // killough 3/6/98: add parameters to savegame, move from demo
2352 respawnparm
= *demo_p
++;
2353 fastparm
= *demo_p
++;
2354 nomonsters
= *demo_p
++;
2356 demo_insurance
= *demo_p
++; // killough 3/31/98
2358 // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here
2360 rngseed
= *demo_p
++ & 0xff;
2362 rngseed
+= *demo_p
++ & 0xff;
2364 rngseed
+= *demo_p
++ & 0xff;
2366 rngseed
+= *demo_p
++ & 0xff;
2368 // Options new to v2.03
2371 monster_infighting
= *demo_p
++; // killough 7/19/98
2374 dogs
= *demo_p
++; // killough 7/19/98
2381 distfriend
= *demo_p
++ << 8; // killough 8/8/98
2382 distfriend
+= *demo_p
++;
2384 monster_backing
= *demo_p
++; // killough 9/8/98
2386 monster_avoid_hazards
= *demo_p
++; // killough 9/9/98
2388 monster_friction
= *demo_p
++; // killough 10/98
2390 help_friends
= *demo_p
++; // killough 9/9/98
2393 dog_jumping
= *demo_p
++; // killough 10/98
2398 monkeys
= *demo_p
++;
2400 { // killough 10/98: a compatibility vector now
2402 for (i
=0; i
< COMP_TOTAL
; i
++)
2403 comp
[i
] = *demo_p
++;
2406 forceOldBsp
= *demo_p
++; // cph 2002/07/20
2408 else /* defaults for versions <= 2.02 */
2410 /* cph - comp[] has already been set up right by G_Compatibility */
2412 monster_infighting
= 1; // killough 7/19/98
2414 monster_backing
= 0; // killough 9/8/98
2416 monster_avoid_hazards
= 0; // killough 9/9/98
2418 monster_friction
= 0; // killough 10/98
2420 help_friends
= 0; // killough 9/9/98
2423 dogs
= 0; // killough 7/19/98
2424 dog_jumping
= 0; // killough 10/98
2433 void G_BeginRecording (void)
2436 byte
*demostart
, *demo_p
;
2437 demostart
= demo_p
= malloc(1000);
2439 /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */
2441 { /* Write version code into demo */
2443 switch(compatibility_level
) {
2444 case doom_12_compatibility
:
2445 case doom_demo_compatibility
:
2446 case doom_compatibility
:
2447 case boom_compatibility_compatibility
:
2448 case boom_201_compatibility
:
2449 case boom_202_compatibility
:
2450 case lxdoom_1_compatibility
:
2451 case prboom_1_compatibility
:
2452 case MAX_COMPATIBILITY_LEVEL
:
2453 case mbf_compatibility
: v
= 204; break;
2454 case prboom_2_compatibility
: v
= 210; break;
2455 case prboom_3_compatibility
: v
= 211; break;
2468 /* killough 2/22/98: save compatibility flag in new demos
2469 * cph - FIXME? MBF demos will always be not in compat. mode */
2472 *demo_p
++ = gameskill
;
2473 *demo_p
++ = gameepisode
;
2474 *demo_p
++ = gamemap
;
2475 *demo_p
++ = deathmatch
;
2476 *demo_p
++ = consoleplayer
;
2478 demo_p
= G_WriteOptions(demo_p
); // killough 3/1/98: Save game options
2480 for (i
=0 ; i
<MAXPLAYERS
; i
++)
2481 *demo_p
++ = playeringame
[i
];
2483 // killough 2/28/98:
2484 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2485 // support enhancements later w/o losing demo compatibility
2487 for (; i
<MIN_MAXPLAYERS
; i
++)
2490 } else if (compatibility_level
> doom_compatibility
) {
2491 byte v
=0, c
=0; /* Nominally, version and compatibility bits */
2492 switch (compatibility_level
) {
2493 case boom_compatibility_compatibility
: v
= 202, c
= 1; break;
2494 case boom_201_compatibility
: v
= 201; c
= 0; break;
2495 case boom_202_compatibility
: v
= 202, c
= 0; break;
2496 default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?");
2508 /* CPhipps - save compatibility level in demos */
2511 *demo_p
++ = gameskill
;
2512 *demo_p
++ = gameepisode
;
2513 *demo_p
++ = gamemap
;
2514 *demo_p
++ = deathmatch
;
2515 *demo_p
++ = consoleplayer
;
2517 demo_p
= G_WriteOptions(demo_p
); // killough 3/1/98: Save game options
2519 for (i
=0 ; i
<MAXPLAYERS
; i
++)
2520 *demo_p
++ = playeringame
[i
];
2522 // killough 2/28/98:
2523 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2524 // support enhancements later w/o losing demo compatibility
2526 for (; i
<MIN_MAXPLAYERS
; i
++)
2528 } else { // cph - write old v1.9 demos (might even sync)
2529 longtics
= M_CheckParm("-longtics");
2530 *demo_p
++ = longtics
? 111 : 109; // v1.9 has best chance of syncing these
2531 *demo_p
++ = gameskill
;
2532 *demo_p
++ = gameepisode
;
2533 *demo_p
++ = gamemap
;
2534 *demo_p
++ = deathmatch
;
2535 *demo_p
++ = respawnparm
;
2536 *demo_p
++ = fastparm
;
2537 *demo_p
++ = nomonsters
;
2538 *demo_p
++ = consoleplayer
;
2539 for (i
=0; i
<4; i
++) // intentionally hard-coded 4 -- killough
2540 *demo_p
++ = playeringame
[i
];
2543 if (write(demofd
, demostart
, demo_p
-demostart
) != (signed)(size_t)(demo_p
-demostart
))
2544 I_Error("G_BeginRecording: Error writing demo header");
2553 static const char *defdemoname
;
2555 void G_DeferedPlayDemo (const char* name
)
2558 gameaction
= ga_playdemo
;
2561 static int demolumpnum
= -1;
2563 static const byte
* G_ReadDemoHeader(const byte
*demo_p
)
2566 int i
, episode
, map
;
2568 const byte
*option_p
= NULL
; /* killough 11/98 */
2570 basetic
= gametic
; // killough 9/29/98
2572 // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
2573 // Old demos turn on demo_compatibility => compatibility; new demos load
2574 // compatibility flag, and other flags as well, as a part of the demo.
2576 demover
= *demo_p
++;
2578 if (demover
< 200) // Autodetect old demos
2580 compatibility_level
= doom_demo_compatibility
;
2581 if (demover
>= 111) longtics
= 1;
2585 // killough 3/2/98: force these variables to be 0 in demo_compatibility
2587 variable_friction
= 0;
2593 monster_infighting
= 1; // killough 7/19/98
2596 dogs
= 0; // killough 7/19/98
2597 dog_jumping
= 0; // killough 10/98
2600 monster_backing
= 0; // killough 9/8/98
2602 monster_avoid_hazards
= 0; // killough 9/9/98
2604 monster_friction
= 0; // killough 10/98
2605 help_friends
= 0; // killough 9/9/98
2608 // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm,
2609 // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions())
2611 if ((skill
=demover
) >= 100) // For demos from versions >= 1.4
2614 episode
= *demo_p
++;
2616 deathmatch
= *demo_p
++;
2617 respawnparm
= *demo_p
++;
2618 fastparm
= *demo_p
++;
2619 nomonsters
= *demo_p
++;
2620 consoleplayer
= *demo_p
++;
2624 episode
= *demo_p
++;
2626 deathmatch
= respawnparm
= fastparm
=
2627 nomonsters
= consoleplayer
= 0;
2630 else // new versions of demos
2632 demo_p
+= 6; // skip signature;
2634 case 200: /* BOOM */
2637 compatibility_level
= boom_201_compatibility
;
2639 compatibility_level
= boom_compatibility_compatibility
;
2643 compatibility_level
= boom_202_compatibility
;
2645 compatibility_level
= boom_compatibility_compatibility
;
2648 /* LxDoom or MBF - determine from signature
2649 * cph - load compatibility level */
2650 switch (demobuffer
[2]) {
2651 case 'B': /* LxDoom */
2652 /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */
2653 compatibility_level
= lxdoom_1_compatibility
;
2656 compatibility_level
= mbf_compatibility
;
2662 compatibility_level
= prboom_2_compatibility
;
2666 compatibility_level
= prboom_3_compatibility
;
2672 episode
= *demo_p
++;
2674 deathmatch
= *demo_p
++;
2675 consoleplayer
= *demo_p
++;
2677 /* killough 11/98: save option pointer for below */
2681 demo_p
= G_ReadOptions(demo_p
); // killough 3/1/98: Read game options
2683 if (demover
== 200) // killough 6/3/98: partially fix v2.00 demos
2684 demo_p
+= 128-GAME_OPTION_SIZE
;
2687 // printf( "G_DoPlayDemo: playing demo with %s compatibility\n",
2688 // comp_lev_str[compatibility_level]);
2690 if (demo_compatibility
) // only 4 players can exist in old demos
2692 for (i
=0; i
<4; i
++) // intentionally hard-coded 4 -- killough
2693 playeringame
[i
] = *demo_p
++;
2694 for (;i
< MAXPLAYERS
; i
++)
2695 playeringame
[i
] = 0;
2699 for (i
=0 ; i
< MAXPLAYERS
; i
++)
2700 playeringame
[i
] = *demo_p
++;
2701 demo_p
+= MIN_MAXPLAYERS
- MAXPLAYERS
;
2704 if (playeringame
[1])
2710 if (gameaction
!= ga_loadgame
) { /* killough 12/98: support -loadgame */
2711 G_InitNew(skill
, episode
, map
);
2714 for (i
=0; i
<MAXPLAYERS
;i
++) // killough 4/24/98
2715 players
[i
].cheats
= 0;
2720 void G_DoPlayDemo(void)
2724 ExtractFileBase(defdemoname
,basename
); // killough
2726 demobuffer
= demo_p
= W_CacheLumpNum(demolumpnum
= W_GetNumForName(basename
));
2727 /* cph - store lump number for unlocking later */
2729 demo_p
= G_ReadDemoHeader(demo_p
);
2731 gameaction
= ga_nothing
;
2734 demoplayback
= true;
2741 void G_TimeDemo(const char *name
) // CPhipps - const char*
2746 gameaction
= ga_playdemo
;
2750 /* G_CheckDemoStatus
2752 * Called after a death or level completion to allow demos to be cleaned up
2753 * Returns true if a new demo loop action will take place
2756 boolean
G_CheckDemoStatus (void)
2760 demorecording
= false;
2761 write(demofd
, &DEMOMARKER
, 1);
2763 I_Error("G_CheckDemoStatus: Demo recorded");
2764 return false; // killough
2769 // int endtime = I_GetTime_RealTime ();
2770 int endtime
= I_GetTime ();
2771 // killough -- added fps information and made it work for longer demos:
2772 unsigned realtics
= endtime
-starttime
;
2773 int fd
=open(GAMEBASE
"timedemo.txt",O_WRONLY
| O_CREAT
);
2774 fdprintf (fd
,"Timed %d gametics in %d realtics = %d frames per second",
2775 (unsigned) gametic
, realtics
,
2776 (unsigned) gametic
* TICRATE
/ realtics
);
2778 I_Error ("%d gametics in %d realtics",
2779 (unsigned) gametic
,realtics
,
2780 (unsigned) gametic
* TICRATE
/ realtics
);
2787 I_Error("Done Playing Demo");
2789 // exit(0); // killough
2791 if (demolumpnum
!= -1) {
2792 // cph - unlock the demo lump
2793 W_UnlockLumpNum(demolumpnum
);
2796 G_ReloadDefaults(); // killough 3/1/98
2797 netgame
= false; // killough 3/29/98
2805 // killough 1/22/98: this is a "Doom printf" for messages. I've gotten
2806 // tired of using players->message=... and so I've added this dprintf.
2808 // killough 3/6/98: Made limit static to allow z_zone functions to call
2809 // this function, without calling realloc(), which seems to cause problems.
2811 #define MAX_MESSAGE_SIZE 1024
2812 static char msg
[MAX_MESSAGE_SIZE
];
2814 // CPhipps - renamed to doom_printf to avoid name collision with glibc
2815 void doom_printf(const char *s
, ...)
2819 vsnprintf(msg
,sizeof(msg
),s
,v
); /* print message in buffer */
2821 players
[consoleplayer
].message
= msg
; // set new message