Accept FS#5153 - Doom Scrollwheel Patch
[kugel-rb.git] / apps / plugins / doom / g_game.c
blob99f8e63187557f70e5d52ed54731cc18f579349e
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
25 * 02111-1307, USA.
27 * DESCRIPTION: none
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 *-----------------------------------------------------------------------------
36 #include "doomdef.h"
37 #include "doomstat.h"
38 #include "z_zone.h"
39 #include "f_finale.h"
40 #include "m_argv.h"
41 #include "m_misc.h"
42 #include "m_menu.h"
43 #include "m_random.h"
44 #include "i_system.h"
45 #include "p_map.h"
46 #include "p_setup.h"
47 #include "p_saveg.h"
48 #include "p_tick.h"
50 #include "d_main.h"
52 #include "wi_stuff.h"
53 #include "hu_stuff.h"
54 #include "st_stuff.h"
55 #include "am_map.h"
57 // Needs access to LFB.
58 #include "v_video.h"
60 #include "w_wad.h"
61 #include "r_main.h"
62 #include "s_sound.h"
64 // Data.
65 #include "dstrings.h"
66 #include "sounds.h"
68 // SKY handling - still the wrong place.
69 #include "r_data.h"
70 #include "r_sky.h"
71 #include "p_inter.h"
72 #include "g_game.h"
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;
88 skill_t gameskill;
89 boolean respawnmonsters;
90 int gameepisode;
91 int gamemap;
92 boolean paused;
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
109 int gametic;
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
121 int longtics;
124 // controls (have defaults)
126 int key_right;
127 int key_left;
128 int key_up;
129 int key_down;
130 int key_menu_right; // phares 3/7/98
131 int key_menu_left; // |
132 int key_menu_up; // V
133 int key_menu_down;
134 int key_menu_backspace; // ^
135 int key_menu_escape; // |
136 int key_menu_enter; // phares 3/7/98
137 int key_strafeleft;
138 int key_straferight;
139 int key_fire;
140 int key_use;
141 int key_strafe;
142 int key_speed;
143 int key_escape = KEY_ESCAPE; // phares 4/13/98
144 int key_weapon;
146 int key_savegame; // phares
147 int key_loadgame; // |
148 int key_autorun; // V
149 int key_reverse;
150 int key_zoomin;
151 int key_zoomout;
153 int key_reverse;
155 int key_chat;
156 int key_backspace;
157 int key_enter;
158 int key_map_right;
159 int key_map_left;
160 int key_map_up;
161 int key_map_down;
162 int key_map_zoomin;
163 int key_map_zoomout;
164 int key_map;
165 int key_map_gobig;
166 int key_map_follow;
167 int key_map_mark;
168 int key_map_clear;
169 int key_map_grid;
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
173 int key_soundvolume;
174 int key_hud;
175 int key_quicksave;
176 int key_endgame;
177 int key_messages;
178 int key_quickload;
179 int key_quit;
180 int key_gamma;
181 int key_spy;
182 int key_pause;
183 int key_setup;
184 int destination_keys[MAXPLAYERS];
185 int key_weapontoggle;
186 int key_weapon1;
187 int key_weapon2;
188 int key_weapon3;
189 int key_weapon4;
190 int key_weapon5;
191 int key_weapon6;
192 int key_weapon7; // ^
193 int key_weapon8; // |
194 int key_weapon9; // phares
196 int key_screenshot; // killough 2/22/98: screenshot key
197 int mousebfire;
198 int mousebstrafe;
199 int mousebforward;
200 int joybfire;
201 int joybstrafe;
202 int joybuse;
203 int joybspeed;
205 #define MAXPLMOVE (forwardmove[1])
206 #define TURBOTHRESHOLD 0x32
207 #define SLOWTURNTICS 6
208 #define QUICKREVERSE (short)32768 // 180 degree reverse // phares
209 #define NUMKEYS 512
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
223 static int mousex;
224 static int mousey;
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 // scrollwheel values
233 static int scrollmag;
235 // joystick values are repeated
236 static int joyxmove;
237 static int joyymove;
238 static boolean joyarray[5];
239 static boolean *joybuttons = &joyarray[1]; // allow [-1]
241 // Game events info
242 static buttoncode_t special_event; // Event triggered by local player, to send
243 static byte savegameslot; // Slot to load if gameaction == ga_loadgame
244 char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame
246 //jff 3/24/98 declare startskill external, define defaultskill here
247 extern skill_t startskill; //note 0-based
248 int defaultskill; //note 1-based
250 // killough 2/8/98: make corpse queue variable in size
251 int bodyqueslot, bodyquesize; // killough 2/8/98
252 mobj_t **bodyque = 0; // phares 8/10/98
254 void* statcopy; // for statistics driver
256 static void G_DoSaveGame (boolean menu);
257 static const byte* G_ReadDemoHeader(const byte* demo_p);
260 // G_BuildTiccmd
261 // Builds a ticcmd from all of the available inputs
262 // or reads it from the demo buffer.
263 // If recording a demo, write it out
265 static inline signed char fudgef(signed char b)
267 static int c;
268 if (!b || !demo_compatibility || longtics) return b;
269 if (++c & 0x1f) return b;
270 b |= 1; if (b>2) b-=2;
271 return b;
274 static inline signed short fudgea(signed short b)
276 if (!b || !demo_compatibility || !longtics) return b;
277 b |= 1; if (b>2) b-=2;
278 return b;
281 void G_BuildTiccmd(ticcmd_t* cmd)
283 boolean strafe;
284 boolean bstrafe;
285 int speed;
286 int tspeed;
287 int forward;
288 int side;
289 int newweapon=0; // phares
290 /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */
291 memset(cmd,0,sizeof*cmd);
292 cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
294 strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
295 || joybuttons[joybstrafe];
296 speed = autorun || gamekeydown[key_speed] || joybuttons[joybspeed]; // phares
298 forward = side = 0;
300 // use two stage accelerative turning
301 // on the keyboard and joystick
302 if (joyxmove < 0 || joyxmove > 0 ||
303 gamekeydown[key_right] || gamekeydown[key_left])
304 turnheld += ticdup;
305 else
306 turnheld = 0;
308 if (turnheld < SLOWTURNTICS)
309 tspeed = 2; // slow turn
310 else
311 tspeed = speed;
313 // turn 180 degrees in one keystroke? // phares
314 // |
315 if (gamekeydown[key_reverse]) // V
317 cmd->angleturn += QUICKREVERSE; // ^
318 gamekeydown[key_reverse] = false; // |
319 } // phares
321 // let movement keys cancel each other out
323 /* strafe with scrollwheel */
324 if (scrollmag > 0)
325 side += 5*sidemove[speed];
326 if (scrollmag < 0)
327 side -= 5*sidemove[speed];
328 scrollmag = 0;
330 if (strafe)
332 if (gamekeydown[key_right])
333 side += sidemove[speed];
334 if (gamekeydown[key_left])
335 side -= sidemove[speed];
336 if (joyxmove > 0)
337 side += sidemove[speed];
338 if (joyxmove < 0)
339 side -= sidemove[speed];
341 else
343 if (gamekeydown[key_right])
344 cmd->angleturn -= angleturn[tspeed];
345 if (gamekeydown[key_left])
346 cmd->angleturn += angleturn[tspeed];
347 if (joyxmove > 0)
348 cmd->angleturn -= angleturn[tspeed];
349 if (joyxmove < 0)
350 cmd->angleturn += angleturn[tspeed];
353 if (gamekeydown[key_up])
354 forward += forwardmove[speed];
355 if (gamekeydown[key_down])
356 forward -= forwardmove[speed];
357 if (joyymove < 0)
358 forward += forwardmove[speed];
359 if (joyymove > 0)
360 forward -= forwardmove[speed];
361 if (gamekeydown[key_straferight])
362 side += sidemove[speed];
363 if (gamekeydown[key_strafeleft])
364 side -= sidemove[speed];
366 // buttons
367 cmd->chatchar = HU_dequeueChatChar();
369 if (gamekeydown[key_fire] || mousebuttons[mousebfire] ||
370 joybuttons[joybfire])
371 cmd->buttons |= BT_ATTACK;
373 if (gamekeydown[key_use] || joybuttons[joybuse])
375 cmd->buttons |= BT_USE;
376 // clear double clicks if hit use button
377 dclicks = 0;
380 // Toggle between the top 2 favorite weapons. // phares
381 // If not currently aiming one of these, switch to // phares
382 // the favorite. Only switch if you possess the weapon. // phares
384 // killough 3/22/98:
386 // Perform automatic weapons switch here rather than in p_pspr.c,
387 // except in demo_compatibility mode.
389 // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left
391 if ((!demo_compatibility && players[consoleplayer].attackdown && // killough
392 !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle])
393 newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares
394 else
395 { // phares 02/26/98: Added gamemode checks
396 if(gamekeydown[key_weapon])
398 volatile unsigned int wpcheck; // I don't know why this is needed, but it is
399 for(wpcheck=0; wpcheck<9; wpcheck++)
400 if(players[consoleplayer].weaponowned[wpcheck] && wpcheck>players[consoleplayer].readyweapon )
402 newweapon=wpcheck;
403 break;
405 if(players[consoleplayer].weaponowned[wp_chainsaw]&&newweapon==0)
406 newweapon=1;
408 else
410 newweapon =
411 gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted
412 gamekeydown[key_weapon2] ? wp_pistol :
413 gamekeydown[key_weapon3] ? wp_shotgun :
414 gamekeydown[key_weapon4] ? wp_chaingun :
415 gamekeydown[key_weapon5] ? wp_missile :
416 gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma :
417 gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg :
418 gamekeydown[key_weapon8] ? wp_chainsaw :
419 gamekeydown[key_weapon9] && gamemode == commercial ? wp_supershotgun :
420 wp_nochange;
423 // killough 3/22/98: For network and demo consistency with the
424 // new weapons preferences, we must do the weapons switches here
425 // instead of in p_user.c. But for old demos we must do it in
426 // p_user.c according to the old rules. Therefore demo_compatibility
427 // determines where the weapons switch is made.
429 // killough 2/8/98:
430 // Allow user to switch to fist even if they have chainsaw.
431 // Switch to fist or chainsaw based on preferences.
432 // Switch to shotgun or SSG based on preferences.
434 if (!demo_compatibility)
436 const player_t *player = &players[consoleplayer];
438 // only select chainsaw from '1' if it's owned, it's
439 // not already in use, and the player prefers it or
440 // the fist is already in use, or the player does not
441 // have the berserker strength.
443 if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] &&
444 player->readyweapon!=wp_chainsaw &&
445 (player->readyweapon==wp_fist ||
446 !player->powers[pw_strength] ||
447 P_WeaponPreferred(wp_chainsaw, wp_fist)))
448 newweapon = wp_chainsaw;
450 // Select SSG from '3' only if it's owned and the player
451 // does not have a shotgun, or if the shotgun is already
452 // in use, or if the SSG is not already in use and the
453 // player prefers it.
454 if(!gamekeydown[key_weapon])
455 if (newweapon == wp_shotgun && gamemode == commercial &&
456 player->weaponowned[wp_supershotgun] &&
457 (!player->weaponowned[wp_shotgun] ||
458 player->readyweapon == wp_shotgun ||
459 (player->readyweapon != wp_supershotgun &&
460 P_WeaponPreferred(wp_supershotgun, wp_shotgun))))
461 newweapon = wp_supershotgun;
464 // killough 2/8/98, 3/22/98 -- end of weapon selection changes
467 if(newweapon >wp_nochange) // something is messed up with the weapon switching code above allowing it to give values greater
468 { // then wp_nochange which really screws the game up
469 newweapon=0;
471 if (newweapon != wp_nochange)
473 cmd->buttons |= BT_CHANGE;
474 cmd->buttons |= newweapon<<BT_WEAPONSHIFT;
477 // mouse
478 if (mousebuttons[mousebforward])
479 forward += forwardmove[speed];
481 // forward double click
482 if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
484 dclickstate = mousebuttons[mousebforward];
485 if (dclickstate)
486 dclicks++;
487 if (dclicks == 2)
489 cmd->buttons |= BT_USE;
490 dclicks = 0;
492 else
493 dclicktime = 0;
495 else
496 if ((dclicktime += ticdup) > 20)
498 dclicks = 0;
499 dclickstate = 0;
502 // strafe double click
504 bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe];
505 if (bstrafe != dclickstate2 && dclicktime2 > 1 )
507 dclickstate2 = bstrafe;
508 if (dclickstate2)
509 dclicks2++;
510 if (dclicks2 == 2)
512 cmd->buttons |= BT_USE;
513 dclicks2 = 0;
515 else
516 dclicktime2 = 0;
518 else
519 if ((dclicktime2 += ticdup) > 20)
521 dclicks2 = 0;
522 dclickstate2 = 0;
524 forward += mousey;
525 if (strafe)
526 side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/
527 else
528 cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */
530 mousex = mousey = 0;
532 if (forward > MAXPLMOVE)
533 forward = MAXPLMOVE;
534 else if (forward < -MAXPLMOVE)
535 forward = -MAXPLMOVE;
536 if (side > MAXPLMOVE)
537 side = MAXPLMOVE;
538 else if (side < -MAXPLMOVE)
539 side = -MAXPLMOVE;
541 cmd->forwardmove += fudgef(forward);
542 cmd->sidemove += side;
543 cmd->angleturn = fudgea(cmd->angleturn);
545 // CPhipps - special events (game new/load/save/pause)
546 if (special_event & BT_SPECIAL) {
547 cmd->buttons = special_event;
548 special_event = 0;
553 // G_RestartLevel
556 void G_RestartLevel(void)
558 special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK);
561 #include "z_bmalloc.h"
563 // G_DoLoadLevel
565 extern gamestate_t wipegamestate;
567 static void G_DoLoadLevel (void)
569 int i;
571 // Set the sky map.
572 // First thing, we have a dummy sky texture name,
573 // a flat. The data is in the WAD only because
574 // we look for an actual index, instead of simply
575 // setting one.
577 skyflatnum = R_FlatNumForName ( SKYFLATNAME );
579 // DOOM determines the sky texture to be used
580 // depending on the current episode, and the game version.
581 if (gamemode == commercial)
582 // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut
583 // || gamemode == pack_plut) //aren't gamemodes, this was matching retail
585 skytexture = R_TextureNumForName ("SKY3");
586 if (gamemap < 12)
587 skytexture = R_TextureNumForName ("SKY1");
588 else
589 if (gamemap < 21)
590 skytexture = R_TextureNumForName ("SKY2");
592 else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh?
593 switch (gameepisode)
595 case 1:
596 skytexture = R_TextureNumForName ("SKY1");
597 break;
598 case 2:
599 skytexture = R_TextureNumForName ("SKY2");
600 break;
601 case 3:
602 skytexture = R_TextureNumForName ("SKY3");
603 break;
604 case 4: // Special Edition sky
605 skytexture = R_TextureNumForName ("SKY4");
606 break;
607 }//jff 3/27/98 end sky setting fix
609 levelstarttic = gametic; // for time calculation
611 if (!demo_compatibility && !mbf_features) // killough 9/29/98
612 basetic = gametic;
614 if (wipegamestate == GS_LEVEL)
615 wipegamestate = -1; // force a wipe
617 gamestate = GS_LEVEL;
619 for (i=0 ; i<MAXPLAYERS ; i++)
621 if (playeringame[i] && players[i].playerstate == PST_DEAD)
622 players[i].playerstate = PST_REBORN;
623 memset (players[i].frags,0,sizeof(players[i].frags));
626 // initialize the msecnode_t freelist. phares 3/25/98
627 // any nodes in the freelist are gone by now, cleared
628 // by Z_FreeTags() when the previous level ended or player
629 // died.
632 DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
633 NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone);
634 //extern msecnode_t *headsecnode; // phares 3/25/98
635 //headsecnode = NULL;
638 P_SetupLevel (gameepisode, gamemap, 0, gameskill);
639 displayplayer = consoleplayer; // view the guy you are playing
640 gameaction = ga_nothing;
641 Z_CheckHeap ();
643 // clear cmd building stuff
644 memset (gamekeydown, 0, sizeof(gamekeydown));
645 joyxmove = joyymove = 0;
646 mousex = mousey = 0;
647 special_event = 0; paused = false;
648 memset (mousebuttons, 0, sizeof(mousebuttons));
649 memset (joybuttons, 0, sizeof(joybuttons));
651 // killough 5/13/98: in case netdemo has consoleplayer other than green
652 ST_Start();
653 HU_Start();
655 // killough: make -timedemo work on multilevel demos
656 // Move to end of function to minimize noise -- killough 2/22/98:
658 if (timingdemo)
660 static int first=1;
661 if (first)
663 starttime = I_GetTime ();
664 first=0;
670 // G_Responder
671 // Get info needed to make ticcmd_ts for the players.
673 boolean G_Responder (event_t* ev)
675 // allow spy mode changes even during the demo
676 // killough 2/22/98: even during DM demo
678 // killough 11/98: don't autorepeat spy mode switch
680 #if 0
681 if (ev->data1 == key_spy && netgame && (demoplayback || !deathmatch) &&
682 gamestate == GS_LEVEL)
684 if (ev->type == ev_keyup)
685 gamekeydown[key_spy] = false;
686 if (ev->type == ev_keydown && !gamekeydown[key_spy])
688 gamekeydown[key_spy] = true;
689 do // spy mode
690 if (++displayplayer >= MAXPLAYERS)
691 displayplayer = 0;
692 while (!playeringame[displayplayer] && displayplayer!=consoleplayer);
694 ST_Start(); // killough 3/7/98: switch status bar views too
695 HU_Start();
696 S_UpdateSounds(players[displayplayer].mo);
698 return true;
700 #endif
702 // any other key pops up menu if in demos
704 // killough 8/2/98: enable automap in -timedemo demos
706 // killough 9/29/98: make any key pop up menu regardless of
707 // which kind of demo, and allow other events during playback
709 if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN))
711 // killough 9/29/98: allow user to pause demos during playback
712 if (ev->type == ev_keydown && ev->data1 == key_pause)
714 if (paused ^= 2)
715 S_PauseSound();
716 else
717 S_ResumeSound();
718 return true;
720 // killough 10/98:
721 // Don't pop up menu, if paused in middle
722 // of demo playback, or if automap active.
723 // Don't suck up keys, which may be cheats
725 return gamestate == GS_DEMOSCREEN &&
726 !(paused & 2) && !(automapmode & am_active) &&
727 ((ev->type == ev_keydown) ||
728 (ev->type == ev_mouse && ev->data1) ||
729 (ev->type == ev_joystick && ev->data1)) ?
730 M_StartControlPanel(), true : false;
733 if (gamestate == GS_FINALE && F_Responder(ev))
734 return true; // finale ate the event
736 switch (ev->type)
738 case ev_keydown:
739 if (ev->data1 == key_pause) // phares
741 special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK);
742 return true;
744 if (ev->data1 <NUMKEYS)
745 gamekeydown[ev->data1] = true;
746 return true; // eat key down events
748 case ev_keyup:
749 if (ev->data1 <NUMKEYS)
750 gamekeydown[ev->data1] = false;
751 return false; // always let key up events filter down
753 case ev_mouse:
754 mousebuttons[0] = ev->data1 & 1;
755 mousebuttons[1] = ev->data1 & 2;
756 mousebuttons[2] = ev->data1 & 4;
757 mousex = ev->data2*(mouseSensitivity+5)/10;
758 mousey = ev->data3*(mouseSensitivity+5)/10;
759 return true; // eat events
761 case ev_joystick:
762 joybuttons[0] = ev->data1 & 1;
763 joybuttons[1] = ev->data1 & 2;
764 joybuttons[2] = ev->data1 & 4;
765 joybuttons[3] = ev->data1 & 8;
766 joyxmove = ev->data2;
767 joyymove = ev->data3;
768 return true; // eat events
770 case ev_scroll:
771 scrollmag = ev->data1;
773 default:
774 break;
776 return false;
780 // G_Ticker
781 // Make ticcmd_ts for the players.
783 extern int mapcolor_me;
785 void G_Ticker (void)
787 int i;
788 static gamestate_t prevgamestate;
790 P_MapStart();
791 // do player reborns if needed
792 for (i=0 ; i<MAXPLAYERS ; i++)
793 if (playeringame[i] && players[i].playerstate == PST_REBORN)
794 G_DoReborn (i);
795 P_MapEnd();
797 // do things to change the game state
798 while (gameaction != ga_nothing)
800 switch (gameaction)
802 case ga_loadlevel:
803 // force players to be initialized on level reload
804 for (i=0 ; i<MAXPLAYERS ; i++)
805 players[i].playerstate = PST_REBORN;
806 G_DoLoadLevel ();
807 break;
808 case ga_newgame:
809 G_DoNewGame ();
810 break;
811 case ga_loadgame:
812 G_DoLoadGame ();
813 break;
814 case ga_savegame:
815 G_DoSaveGame (false);
816 break;
817 case ga_playdemo:
818 G_DoPlayDemo ();
819 break;
820 case ga_completed:
821 G_DoCompleted ();
822 break;
823 case ga_victory:
824 F_StartFinale ();
825 break;
826 case ga_worlddone:
827 G_DoWorldDone ();
828 break;
829 case ga_nothing:
830 break;
834 if (paused & 2 || (!demoplayback && menuactive && !netgame))
835 basetic++; // For revenant tracers and RNG -- we must maintain sync
836 else
838 // get commands, check consistancy, and build new consistancy check
839 int buf = (gametic/ticdup)%BACKUPTICS;
841 for (i=0 ; i<MAXPLAYERS ; i++)
843 if (playeringame[i])
845 ticcmd_t *cmd = &players[i].cmd;
847 memcpy(cmd, &netcmds[i][buf], sizeof *cmd);
849 if (demoplayback)
850 G_ReadDemoTiccmd (cmd);
851 if (demorecording)
852 G_WriteDemoTiccmd (cmd);
854 // check for turbo cheats
855 // killough 2/14/98, 2/20/98 -- only warn in netgames and demos
857 if ((netgame || demoplayback) && cmd->forwardmove > TURBOTHRESHOLD &&
858 !(gametic&31) && ((gametic>>5)&3) == i )
860 extern const char *player_names[];
861 /* cph - don't use sprintf, use doom_printf */
862 doom_printf ("%s is turbo!", player_names[i]);
865 if (netgame && !netdemo && !(gametic%ticdup) )
867 if (gametic > BACKUPTICS
868 && consistancy[i][buf] != cmd->consistancy)
869 I_Error("G_Ticker: Consistency failure (%i should be %i)",
870 cmd->consistancy, consistancy[i][buf]);
871 if (players[i].mo)
872 consistancy[i][buf] = players[i].mo->x;
873 else
874 consistancy[i][buf] = 0; // killough 2/14/98
879 // check for special buttons
880 for (i=0 ; i<MAXPLAYERS ; i++)
882 if (playeringame[i])
884 if (players[i].cmd.buttons & BT_SPECIAL)
886 switch (players[i].cmd.buttons & BT_SPECIALMASK)
888 case BTS_PAUSE:
889 paused ^= 1;
890 if (paused)
891 S_PauseSound ();
892 else
893 S_ResumeSound ();
894 break;
896 case BTS_SAVEGAME:
897 if (!savedescription[0])
898 strcpy(savedescription, "NET GAME");
899 savegameslot =
900 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
901 gameaction = ga_savegame;
902 break;
904 // CPhipps - remote loadgame request
905 case BTS_LOADGAME:
906 savegameslot =
907 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
908 gameaction = ga_loadgame;
909 forced_loadgame = netgame; // Force if a netgame
910 command_loadgame = false;
911 break;
913 // CPhipps - Restart the level
914 case BTS_RESTARTLEVEL:
915 if (demoplayback || (compatibility_level < lxdoom_1_compatibility))
916 break; // CPhipps - Ignore in demos or old games
917 gameaction = ga_loadlevel;
918 break;
920 players[i].cmd.buttons = 0;
926 // cph - if the gamestate changed, we may need to clean up the old gamestate
927 if (gamestate != prevgamestate) {
928 switch (prevgamestate) {
929 case GS_INTERMISSION:
930 WI_End();
931 default:
932 break;
934 prevgamestate = gamestate;
937 // do main actions
938 switch (gamestate)
940 case GS_LEVEL:
941 P_Ticker ();
942 ST_Ticker ();
943 AM_Ticker ();
944 HU_Ticker ();
945 break;
947 case GS_INTERMISSION:
948 WI_Ticker ();
949 break;
951 case GS_FINALE:
952 F_Ticker ();
953 break;
955 case GS_DEMOSCREEN:
956 D_PageTicker ();
957 break;
963 // PLAYER STRUCTURE FUNCTIONS
964 // also see P_SpawnPlayer in P_Things
968 // G_PlayerFinishLevel
969 // Can when a player completes a level.
971 void G_PlayerFinishLevel(int player)
973 player_t *p = &players[player];
974 memset(p->powers, 0, sizeof (p->powers));
975 memset(p->cards, 0, sizeof (p->cards));
976 p->mo->flags &= ~MF_SHADOW; // cancel invisibility
977 p->extralight = 0; // cancel gun flashes
978 p->fixedcolormap = 0; // cancel ir gogles
979 p->damagecount = 0; // no palette changes
980 p->bonuscount = 0;
983 // CPhipps - G_SetPlayerColour
984 // Player colours stuff
986 // G_SetPlayerColour
988 #include "r_draw.h"
989 extern byte playernumtotrans[MAXPLAYERS];
991 void G_ChangedPlayerColour(int pn, int cl)
993 int i;
995 if (!netgame) return;
997 mapcolor_plyr[pn] = cl;
999 // Rebuild colour translation tables accordingly
1000 R_InitTranslationTables();
1001 // Change translations on existing player mobj's
1002 for (i=0; i<MAXPLAYERS; i++) {
1003 if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) {
1004 players[i].mo->flags &= ~MF_TRANSLATION;
1005 players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT;
1011 // G_PlayerReborn
1012 // Called after a player dies
1013 // almost everything is cleared and initialized
1015 void G_PlayerReborn (int player)
1017 player_t *p;
1018 int i;
1019 int frags[MAXPLAYERS];
1020 int killcount;
1021 int itemcount;
1022 int secretcount;
1024 memcpy (frags, players[player].frags, sizeof frags);
1025 killcount = players[player].killcount;
1026 itemcount = players[player].itemcount;
1027 secretcount = players[player].secretcount;
1029 p = &players[player];
1031 // killough 3/10/98,3/21/98: preserve cheats across idclev
1033 int cheats = p->cheats;
1034 memset (p, 0, sizeof(*p));
1035 p->cheats = cheats;
1038 memcpy(players[player].frags, frags, sizeof(players[player].frags));
1039 players[player].killcount = killcount;
1040 players[player].itemcount = itemcount;
1041 players[player].secretcount = secretcount;
1043 p->usedown = p->attackdown = true; // don't do anything immediately
1044 p->playerstate = PST_LIVE;
1045 p->health = MAXHEALTH;
1046 p->readyweapon = p->pendingweapon = wp_pistol;
1047 p->weaponowned[wp_fist] = true;
1048 p->weaponowned[wp_pistol] = true;
1049 p->ammo[am_clip] = 50;
1051 for (i=0 ; i<NUMAMMO ; i++)
1052 p->maxammo[i] = maxammo[i];
1057 // G_CheckSpot
1058 // Returns false if the player cannot be respawned
1059 // at the given mapthing_t spot
1060 // because something is occupying it
1063 void P_SpawnPlayer(mapthing_t *mthing);
1065 boolean G_CheckSpot(int playernum, mapthing_t *mthing)
1067 fixed_t x,y;
1068 subsector_t *ss;
1069 int i;
1071 if (!players[playernum].mo)
1073 // first spawn of level, before corpses
1074 for (i=0 ; i<playernum ; i++)
1075 if (players[i].mo->x == mthing->x << FRACBITS
1076 && players[i].mo->y == mthing->y << FRACBITS)
1077 return false;
1078 return true;
1081 x = mthing->x << FRACBITS;
1082 y = mthing->y << FRACBITS;
1084 // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid
1085 // corpse to detect collisions with other players in DM starts
1087 // Old code:
1088 // if (!P_CheckPosition (players[playernum].mo, x, y))
1089 // return false;
1091 players[playernum].mo->flags |= MF_SOLID;
1092 i = P_CheckPosition(players[playernum].mo, x, y);
1093 players[playernum].mo->flags &= ~MF_SOLID;
1094 if (!i)
1095 return false;
1097 // flush an old corpse if needed
1098 // killough 2/8/98: make corpse queue have an adjustable limit
1099 // killough 8/1/98: Fix bugs causing strange crashes
1101 if (bodyquesize > 0)
1103 static mobj_t **bodyque;
1104 static int queuesize;
1105 if (queuesize < bodyquesize)
1107 bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque);
1108 memset(bodyque+queuesize, 0,
1109 (bodyquesize-queuesize)*sizeof*bodyque);
1110 queuesize = bodyquesize;
1112 if (bodyqueslot >= bodyquesize)
1113 P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]);
1114 bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo;
1116 else
1117 if (!bodyquesize)
1118 P_RemoveMobj(players[playernum].mo);
1120 // spawn a teleport fog
1121 ss = R_PointInSubsector (x,y);
1122 { // Teleport fog at respawn point
1123 fixed_t xa=0,ya=0;
1124 int an;
1125 mobj_t *mo;
1127 /* BUG: an can end up negative, because mthing->angle is (signed) short.
1128 * We have to emulate original Doom's behaviour, deferencing past the start
1129 * of the array, into the previous array (finetangent) */
1130 an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT;
1131 switch (an) {
1132 case -4096: xa = finetangent[2048]; // finecosine[-4096]
1133 ya = finetangent[0]; // finesine[-4096]
1134 break;
1135 case -3072: xa = finetangent[3072]; // finecosine[-3072]
1136 ya = finetangent[1024]; // finesine[-3072]
1137 break;
1138 case -2048: xa = finesine[0]; // finecosine[-2048]
1139 ya = finetangent[2048]; // finesine[-2048]
1140 break;
1141 case -1024: xa = finesine[1024]; // finecosine[-1024]
1142 ya = finetangent[3072]; // finesine[-1024]
1143 break;
1144 case 1024:
1145 case 2048:
1146 case 3072:
1147 case 4096:
1148 case 0: xa = finecosine[an];
1149 ya = finesine[an];
1150 break;
1151 default: I_Error("G_CheckSpot: unexpected angle %d\n",an);
1155 mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG);
1157 if (players[consoleplayer].viewz != 1)
1158 S_StartSound(mo, sfx_telept); // don't start sound on first frame
1161 return true;
1166 // G_DeathMatchSpawnPlayer
1167 // Spawns a player at one of the random death match spots
1168 // called at level load and each death
1170 void G_DeathMatchSpawnPlayer (int playernum)
1172 int j, selections = deathmatch_p - deathmatchstarts;
1174 if (selections < MAXPLAYERS)
1175 I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required",
1176 selections, MAXPLAYERS);
1178 for (j=0 ; j<20 ; j++)
1180 int i = P_Random(pr_dmspawn) % selections;
1181 if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1183 deathmatchstarts[i].type = playernum+1;
1184 P_SpawnPlayer (&deathmatchstarts[i]);
1185 return;
1189 // no good spot, so the player will probably get stuck
1190 P_SpawnPlayer (&playerstarts[playernum]);
1194 // G_DoReborn
1197 void G_DoReborn (int playernum)
1199 if (!netgame)
1200 gameaction = ga_loadlevel; // reload the level from scratch
1201 (void)playernum;
1202 #if 0
1203 else
1204 { // respawn at the start
1205 int i;
1207 // first dissasociate the corpse
1208 players[playernum].mo->player = NULL;
1210 // spawn at random spot if in death match
1211 if (deathmatch)
1213 G_DeathMatchSpawnPlayer (playernum);
1214 return;
1217 if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1219 P_SpawnPlayer (&playerstarts[playernum]);
1220 return;
1223 // try to spawn at one of the other players spots
1224 for (i=0 ; i<MAXPLAYERS ; i++)
1226 if (G_CheckSpot (playernum, &playerstarts[i]) )
1228 playerstarts[i].type = playernum+1; // fake as other player
1229 P_SpawnPlayer (&playerstarts[i]);
1230 playerstarts[i].type = i+1; // restore
1231 return;
1233 // he's going to be inside something. Too bad.
1235 P_SpawnPlayer (&playerstarts[playernum]);
1237 #endif
1240 // DOOM Par Times
1241 int pars[4][10] =
1243 {0},
1244 {0,30,75,120,90,165,180,180,30,165},
1245 {0,90,90,90,120,90,360,240,30,170},
1246 {0,90,45,90,150,90,90,165,30,135}
1249 // DOOM II Par Times
1250 int cpars[32] =
1252 30,90,120,120,90,150,120,120,270,90, // 1-10
1253 210,150,150,150,210,150,420,150,210,150, // 11-20
1254 240,150,180,150,150,300,330,420,300,180, // 21-30
1255 120,30 // 31-32
1258 static boolean secretexit;
1260 void G_ExitLevel (void)
1262 secretexit = false;
1263 gameaction = ga_completed;
1266 // Here's for the german edition.
1267 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1269 void G_SecretExitLevel (void)
1271 if (gamemode!=commercial || haswolflevels)
1272 secretexit = true;
1273 else
1274 secretexit = false;
1275 gameaction = ga_completed;
1279 // G_DoCompleted
1282 void G_DoCompleted (void)
1284 int i;
1286 gameaction = ga_nothing;
1288 for (i=0; i<MAXPLAYERS; i++)
1289 if (playeringame[i])
1290 G_PlayerFinishLevel(i); // take away cards and stuff
1292 if (automapmode & am_active)
1293 AM_Stop();
1295 if (gamemode != commercial) // kilough 2/7/98
1296 switch(gamemap)
1298 // cph - Remove ExM8 special case, so it gets summary screen displayed
1299 case 9:
1300 for (i=0 ; i<MAXPLAYERS ; i++)
1301 players[i].didsecret = true;
1302 break;
1305 wminfo.didsecret = players[consoleplayer].didsecret;
1306 wminfo.epsd = gameepisode -1;
1307 wminfo.last = gamemap -1;
1309 // wminfo.next is 0 biased, unlike gamemap
1310 if (gamemode == commercial)
1312 if (secretexit)
1313 switch(gamemap)
1315 case 15:
1316 wminfo.next = 30; break;
1317 case 31:
1318 wminfo.next = 31; break;
1320 else
1321 switch(gamemap)
1323 case 31:
1324 case 32:
1325 wminfo.next = 15; break;
1326 default:
1327 wminfo.next = gamemap;
1330 else
1332 if (secretexit)
1333 wminfo.next = 8; // go to secret level
1334 else
1335 if (gamemap == 9)
1337 // returning from secret level
1338 switch (gameepisode)
1340 case 1:
1341 wminfo.next = 3;
1342 break;
1343 case 2:
1344 wminfo.next = 5;
1345 break;
1346 case 3:
1347 wminfo.next = 6;
1348 break;
1349 case 4:
1350 wminfo.next = 2;
1351 break;
1354 else
1355 wminfo.next = gamemap; // go to next level
1358 wminfo.maxkills = totalkills;
1359 wminfo.maxitems = totalitems;
1360 wminfo.maxsecret = totalsecret;
1361 wminfo.maxfrags = 0;
1363 if ( gamemode == commercial )
1364 wminfo.partime = TICRATE*cpars[gamemap-1];
1365 else
1366 wminfo.partime = TICRATE*pars[gameepisode][gamemap];
1368 wminfo.pnum = consoleplayer;
1370 for (i=0 ; i<MAXPLAYERS ; i++)
1372 wminfo.plyr[i].in = playeringame[i];
1373 wminfo.plyr[i].skills = players[i].killcount;
1374 wminfo.plyr[i].sitems = players[i].itemcount;
1375 wminfo.plyr[i].ssecret = players[i].secretcount;
1376 wminfo.plyr[i].stime = leveltime;
1377 memcpy (wminfo.plyr[i].frags, players[i].frags,
1378 sizeof(wminfo.plyr[i].frags));
1381 /* cph - modified so that only whole seconds are added to the totalleveltimes
1382 * value; so our total is compatible with the "naive" total of just adding
1383 * the times in seconds shown for each level. Also means our total time
1384 * will agree with Compet-n.
1386 wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35));
1388 gamestate = GS_INTERMISSION;
1389 automapmode &= ~am_active;
1391 if (statcopy)
1392 memcpy (statcopy, &wminfo, sizeof(wminfo));
1394 WI_Start (&wminfo);
1399 // G_WorldDone
1402 void G_WorldDone (void)
1404 gameaction = ga_worlddone;
1406 if (secretexit)
1407 players[consoleplayer].didsecret = true;
1409 if (gamemode == commercial)
1411 switch (gamemap)
1413 case 15:
1414 case 31:
1415 if (!secretexit)
1416 break;
1417 case 6:
1418 case 11:
1419 case 20:
1420 case 30:
1421 F_StartFinale ();
1422 break;
1425 else if (gamemap == 8)
1426 gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff
1429 void G_DoWorldDone (void)
1431 idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded
1432 gamestate = GS_LEVEL;
1433 gamemap = wminfo.next+1;
1434 G_DoLoadLevel();
1435 gameaction = ga_nothing;
1436 AM_clearMarks(); //jff 4/12/98 clear any marks on the automap
1439 // killough 2/28/98: A ridiculously large number
1440 // of players, the most you'll ever need in a demo
1441 // or savegame. This is used to prevent problems, in
1442 // case more players in a game are supported later.
1444 #define MIN_MAXPLAYERS 32
1446 extern boolean setsizeneeded;
1447 void R_ExecuteSetViewSize(void);
1449 //CPhipps - savename variable redundant
1451 /* killough 12/98:
1452 * This function returns a signature for the current wad.
1453 * It is used to distinguish between wads, for the purposes
1454 * of savegame compatibility warnings, and options lookups.
1457 static uint_64_t G_UpdateSignature(uint_64_t s, const char *name)
1459 int i, lump = W_CheckNumForName(name);
1460 if (lump != -1 && (i = lump+10) < numlumps)
1463 int size = W_LumpLength(i);
1464 const byte *p = W_CacheLumpNum(i);
1465 while (size--)
1466 s <<= 1, s += *p++;
1467 W_UnlockLumpNum(i);
1469 while (--i > lump);
1470 return s;
1473 static uint_64_t G_Signature(void)
1475 static uint_64_t s = 0;
1476 static boolean computed = false;
1477 char name[9];
1478 int episode, map;
1480 if (!computed) {
1481 computed = true;
1482 if (gamemode == commercial)
1483 for (map = haswolflevels ? 32 : 30; map; map--)
1484 snprintf(name, sizeof(name), "map%02d", map), s = G_UpdateSignature(s, name);
1485 else
1486 for (episode = gamemode==retail ? 4 :
1487 gamemode==shareware ? 1 : 3; episode; episode--)
1488 for (map = 9; map; map--)
1489 snprintf(name, sizeof(name), "E%dM%d", episode, map), s = G_UpdateSignature(s, name);
1491 return s;
1495 // killough 5/15/98: add forced loadgames, which allow user to override checks
1498 void G_ForcedLoadGame(void)
1500 // CPhipps - net loadgames are always forced, so we only reach here
1501 // in single player
1502 gameaction = ga_loadgame;
1503 forced_loadgame = true;
1506 // killough 3/16/98: add slot info
1507 // killough 5/15/98: add command-line
1508 void G_LoadGame(int slot, boolean command)
1510 if (!demoplayback && !command) {
1511 // CPhipps - handle savegame filename in G_DoLoadGame
1512 // - Delay load so it can be communicated in net game
1513 // - store info in special_event
1514 special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) |
1515 ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1516 forced_loadgame = netgame; // CPhipps - always force load netgames
1517 } else {
1518 // Do the old thing, immediate load
1519 gameaction = ga_loadgame;
1520 forced_loadgame = false;
1521 savegameslot = slot;
1522 demoplayback = false;
1524 command_loadgame = command;
1527 // killough 5/15/98:
1528 // Consistency Error when attempting to load savegame.
1530 static void G_LoadGameErr(const char *msg)
1532 (void) msg; // Need to fix, but right now we're ignoring a forced load
1533 Z_Free(savebuffer); // Free the savegame buffer
1534 // M_ForcedLoadGame(msg); // Print message asking for 'Y' to force
1535 if (command_loadgame) // If this was a command-line -loadgame
1537 D_StartTitle(); // Start the title screen
1538 gamestate = GS_DEMOSCREEN; // And set the game state accordingly
1542 // CPhipps - size of version header
1543 #define VERSIONSIZE 16
1545 const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] =
1546 { "doom v1.2", "demo", "doom", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+",
1547 "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1",
1548 "Current PrBoom" };
1550 static const struct {
1551 unsigned int comp_level;
1552 const char* ver_printf;
1553 int version;
1554 } version_headers[] = {
1555 { prboom_1_compatibility, "PrBoom %d", 260},
1556 /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since
1557 * the file format is unchanged. */
1558 { prboom_3_compatibility, "PrBoom %d", 210}
1561 static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]);
1563 void G_DoLoadGame(void)
1565 int i;
1566 // CPhipps - do savegame filename stuff here
1567 char name[100+1]; // killough 3/22/98
1568 int savegame_compatibility = -1;
1570 G_SaveGameName(name,sizeof(name),savegameslot, demoplayback);
1572 gameaction = ga_nothing;
1574 M_ReadFile(name, &savebuffer);
1575 save_p = savebuffer + SAVESTRINGSIZE;
1577 // CPhipps - read the description field, compare with supported ones
1578 for (i=0; (size_t)i<num_version_headers; i++) {
1579 char vcheck[VERSIONSIZE];
1580 // killough 2/22/98: "proprietary" version string :-)
1581 snprintf (vcheck,sizeof(vcheck), version_headers[i].ver_printf, version_headers[i].version);
1583 if (!strncmp(save_p, vcheck, VERSIONSIZE)) {
1584 savegame_compatibility = version_headers[i].comp_level;
1585 i = num_version_headers;
1588 if (savegame_compatibility == -1) {
1589 if (forced_loadgame) {
1590 savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1;
1591 } else {
1592 G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) ");
1593 return;
1597 save_p += VERSIONSIZE;
1599 // CPhipps - always check savegames even when forced,
1600 // only print a warning if forced
1601 { // killough 3/16/98: check lump name checksum (independent of order)
1602 uint_64_t checksum = 0;
1604 checksum = G_Signature();
1606 if (memcmp(&checksum, save_p, sizeof checksum)) {
1607 if (!forced_loadgame) {
1608 char *msg = malloc(strlen(save_p + sizeof checksum) + 128);
1609 strcpy(msg,"Incompatible Savegame!!!\n");
1610 if (save_p[sizeof checksum])
1611 strcat(strcat(msg,"Wads expected:\n\n"), save_p + sizeof checksum);
1612 strcat(msg, "\nAre you sure?");
1613 G_LoadGameErr(msg);
1614 free(msg);
1615 return;
1616 } else
1617 printf("G_DoLoadGame: Incompatible savegame\n");
1619 save_p += sizeof checksum;
1622 save_p += strlen(save_p)+1;
1624 /* cph - FIXME - compatibility flag? */
1625 compatibility_level = savegame_compatibility;
1626 save_p++;
1628 gameskill = *save_p++;
1629 gameepisode = *save_p++;
1630 gamemap = *save_p++;
1632 for (i=0 ; i<MAXPLAYERS ; i++)
1633 playeringame[i] = *save_p++;
1634 save_p += MIN_MAXPLAYERS-MAXPLAYERS; // killough 2/28/98
1636 idmusnum = *save_p++; // jff 3/17/98 restore idmus music
1637 if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte
1639 /* killough 3/1/98: Read game options
1640 * killough 11/98: move down to here
1642 save_p = (char*)G_ReadOptions(save_p);
1644 // load a base level
1645 G_InitNew (gameskill, gameepisode, gamemap);
1647 /* get the times - killough 11/98: save entire word */
1648 memcpy(&leveltime, save_p, sizeof leveltime);
1649 save_p += sizeof leveltime;
1651 /* cph - total episode time */
1652 if (compatibility_level >= prboom_2_compatibility) {
1653 memcpy(&totalleveltimes, save_p, sizeof totalleveltimes);
1654 save_p += sizeof totalleveltimes;
1656 else totalleveltimes = 0;
1658 // killough 11/98: load revenant tracer state
1659 basetic = gametic - *save_p++;
1661 // dearchive all the modifications
1662 P_UnArchivePlayers ();
1663 P_UnArchiveWorld ();
1664 P_UnArchiveThinkers ();
1665 P_UnArchiveSpecials ();
1666 P_UnArchiveRNG (); // killough 1/18/98: load RNG information
1667 P_UnArchiveMap (); // killough 1/22/98: load automap information
1669 if (*save_p != 0xe6)
1670 I_Error ("G_DoLoadGame: Bad savegame");
1672 // done
1673 Z_Free (savebuffer);
1675 if (setsizeneeded)
1676 R_ExecuteSetViewSize ();
1678 // draw the pattern into the back screen
1679 R_FillBackScreen ();
1681 /* killough 12/98: support -recordfrom and -loadgame -playdemo */
1682 if (!command_loadgame)
1683 singledemo = false; /* Clear singledemo flag if loading from menu */
1684 else
1685 if (singledemo) {
1686 gameaction = ga_loadgame; /* Mark that we're loading a game before demo */
1687 G_DoPlayDemo(); /* This will detect it and won't reinit level */
1688 } else /* Command line + record means it's a recordfrom */
1689 if (demorecording)
1690 G_BeginRecording();
1694 // G_SaveGame
1695 // Called by the menu task.
1696 // Description is a 24 byte text string
1699 void G_SaveGame(int slot, char *description)
1701 strcpy(savedescription, description);
1702 if (demoplayback) {
1703 /* cph - We're doing a user-initiated save game while a demo is
1704 * running so, go outside normal mechanisms
1706 savegameslot = slot;
1707 G_DoSaveGame(true);
1709 // CPhipps - store info in special_event
1710 special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) |
1711 ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK);
1712 #ifdef HAVE_NET
1713 D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription);
1714 #endif
1717 // Check for overrun and realloc if necessary -- Lee Killough 1/22/98
1718 void CheckSaveGame(size_t size)
1720 size_t pos = save_p - savebuffer;
1721 size += 1024; // breathing room
1722 if (pos+size > savegamesize)
1723 save_p = (savebuffer = realloc(savebuffer,
1724 savegamesize += (size+1023) & ~1023)) + pos;
1727 /* killough 3/22/98: form savegame name in one location
1728 * (previously code was scattered around in multiple places)
1729 * cph - Avoid possible buffer overflow problems by passing
1730 * size to this function and using snprintf */
1732 void G_SaveGameName(char *name, size_t size, int slot, boolean demoplayback)
1734 const char* sgn = demoplayback ? "demosav" : SAVEGAMENAME;
1735 snprintf (name, size, "%s%d.dsg", sgn, slot);
1738 static void G_DoSaveGame (boolean menu)
1740 char name[100+1];
1741 char name2[VERSIONSIZE];
1742 char *description;
1743 int length, i;
1745 gameaction = ga_nothing; // cph - cancel savegame at top of this function,
1746 // in case later problems cause a premature exit
1748 G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu);
1750 description = savedescription;
1752 save_p = savebuffer = malloc(savegamesize);
1754 CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(unsigned long));
1755 memcpy (save_p, description, SAVESTRINGSIZE);
1756 save_p += SAVESTRINGSIZE;
1757 memset (name2,0,sizeof(name2));
1759 // CPhipps - scan for the version header
1760 for (i=0; (size_t)i<num_version_headers; i++)
1761 if (version_headers[i].comp_level == compatibility_level) {
1762 // killough 2/22/98: "proprietary" version string :-)
1763 snprintf (name2,sizeof(name2),version_headers[i].ver_printf,version_headers[i].version);
1764 memcpy (save_p, name2, VERSIONSIZE);
1765 i = num_version_headers+1;
1768 if ((size_t)i == num_version_headers) {
1769 doom_printf("No savegame signature known for\nthis compatibility level\n"
1770 "%d/%d, %d registered", compatibility_level,
1771 MAX_COMPATIBILITY_LEVEL, (signed)num_version_headers);
1772 free(savebuffer); // cph - free data
1773 return;
1776 save_p += VERSIONSIZE;
1778 { /* killough 3/16/98, 12/98: store lump name checksum */
1779 uint_64_t checksum = G_Signature();
1780 memcpy(save_p, &checksum, sizeof checksum);
1781 save_p += sizeof checksum;
1784 // killough 3/16/98: store pwad filenames in savegame
1786 // CPhipps - changed for new wadfiles handling
1787 int i = 0;
1788 for (*save_p = 0; (size_t)i<numwadfiles; i++)
1790 const char *const w = wadfiles[i].name;
1791 CheckSaveGame(strlen(w)+2);
1792 strcat(strcat(save_p, w), "\n");
1794 save_p += strlen(save_p)+1;
1797 CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+10);
1799 /* cph - FIXME? - Save compatibility level */
1800 *save_p++ = 0;
1802 *save_p++ = gameskill;
1803 *save_p++ = gameepisode;
1804 *save_p++ = gamemap;
1806 for (i=0 ; i<MAXPLAYERS ; i++)
1807 *save_p++ = playeringame[i];
1809 for (;i<MIN_MAXPLAYERS;i++) // killough 2/28/98
1810 *save_p++ = 0;
1812 *save_p++ = idmusnum; // jff 3/17/98 save idmus state
1814 save_p = G_WriteOptions(save_p); // killough 3/1/98: save game options
1816 /* cph - FIXME - endianness? */
1817 /* killough 11/98: save entire word */
1818 memcpy(save_p, &leveltime, sizeof leveltime);
1819 save_p += sizeof leveltime;
1821 /* cph - total episode time */
1822 if (compatibility_level >= prboom_2_compatibility) {
1823 memcpy(save_p, &totalleveltimes, sizeof totalleveltimes);
1824 save_p += sizeof totalleveltimes;
1826 else totalleveltimes = 0;
1828 // killough 11/98: save revenant tracer state
1829 *save_p++ = (gametic-basetic) & 255;
1831 // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
1832 Z_CheckHeap();
1833 P_ArchivePlayers();
1834 Z_CheckHeap();
1836 // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the
1837 // indices can be used by P_ArchiveWorld when the sectors are saved.
1838 // This is so we can save the index of the mobj_t of the thinker that
1839 // caused a sound, referenced by sector_t->soundtarget.
1840 P_ThinkerToIndex();
1842 P_ArchiveWorld();
1843 Z_CheckHeap();
1844 P_ArchiveThinkers();
1846 // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply
1847 // for symmetry with the P_ThinkerToIndex call above.
1849 P_IndexToThinker();
1851 Z_CheckHeap();
1852 P_ArchiveSpecials();
1853 P_ArchiveRNG(); // killough 1/18/98: save RNG information
1854 Z_CheckHeap();
1855 P_ArchiveMap(); // killough 1/22/98: save automap information
1857 *save_p++ = 0xe6; // consistancy marker
1859 length = save_p - savebuffer;
1861 Z_CheckHeap();
1862 doom_printf( "%s", M_WriteFile(name, savebuffer, length)
1863 ? GGSAVED /* Ty - externalised */
1864 : "Game save failed!"); // CPhipps - not externalised
1866 free(savebuffer); // killough
1867 savebuffer = save_p = NULL;
1869 savedescription[0] = 0;
1872 static skill_t d_skill;
1873 static int d_episode;
1874 static int d_map;
1876 void G_DeferedInitNew(skill_t skill, int episode, int map)
1878 d_skill = skill;
1879 d_episode = episode;
1880 d_map = map;
1881 gameaction = ga_newgame;
1884 extern int variable_friction;
1885 extern int default_variable_friction; // ice & mud
1887 extern int weapon_recoil, default_weapon_recoil; // weapon recoil
1889 extern int allow_pushers;
1890 extern int default_allow_pushers; // MT_PUSH Things
1892 extern int player_bobbing;
1893 extern int default_player_bobbing; // whether player bobs or not
1895 extern int monsters_remember, default_monsters_remember;
1897 /* cph -
1898 * G_Compatibility
1900 * Initialises the comp[] array based on the compatibility_level
1901 * For reference, MBF did:
1902 * for (i=0; i < COMP_TOTAL; i++)
1903 * comp[i] = compatibility;
1905 * Instead, we have a lookup table showing at what version a fix was
1906 * introduced.
1909 void G_Compatibility(void)
1911 static const complevel_t fix_levels[COMP_NUM] = {
1912 mbf_compatibility, /* comp_telefrag - monsters used to telefrag only
1913 * on MAP30, now they do it for spawners only */
1914 mbf_compatibility, /* comp_dropoff - MBF encourages things to drop
1915 * off of overhangs */
1916 boom_compatibility,/* comp_vile - original Doom archville bugs like
1917 * ghosts */
1918 boom_compatibility,/* comp_pain - original Doom limits Pain Elements
1919 * from spawning too many skulls */
1920 boom_compatibility,/* comp_skull - original Doom let skulls be spit
1921 * through walls by Pain Elementals */
1922 boom_compatibility,/* comp_blazing - original Doom duplicated
1923 * blazing door sound */
1924 mbf_compatibility, /* comp_doorlight - MBF made door lighting changes
1925 * more gradual */
1926 boom_compatibility,/* comp_model - improvements to the game physics */
1927 boom_compatibility,/* comp_god - fixes to God mode */
1928 mbf_compatibility, /* comp_falloff - MBF encourages things to drop
1929 * off of overhangs */
1930 boom_compatibility_compatibility,
1931 /* comp_floors - fixes for moving floors bugs */
1932 boom_compatibility,/* comp_skymap */
1933 mbf_compatibility, /* comp_pursuit - MBF AI change, limited pursuit? */
1934 boom_compatibility,/* comp_doorstuck - monsters stuck in doors fix */
1935 mbf_compatibility, /* comp_staylift - MBF AI change, monsters try
1936 * to stay on lifts */
1937 lxdoom_1_compatibility, /* comp_zombie - prevent dead players
1938 * triggering stuff */
1939 boom_compatibility_compatibility, /* comp_stairs - see p_floor.c */
1940 mbf_compatibility, /* comp_infcheat - FIXME */
1941 boom_compatibility,/* comp_zerotags - allow zero tags in wads */
1942 lxdoom_1_compatibility, /* comp_moveblock - enables keygrab and
1943 * mancubi shots going thru walls */
1944 prboom_2_compatibility, /* comp_respawn - objects which aren't on the map
1945 * at game start respawn at (0,0) */
1946 boom_compatibility_compatibility, /* comp_sound - see s_sound.c */
1948 int i;
1949 for (i=0; i<COMP_NUM; i++)
1950 comp[i] = compatibility_level < fix_levels[i];
1951 for (; i<COMP_TOTAL; i++) comp[i] = 1;
1954 #ifdef DOGS
1955 /* killough 7/19/98: Marine's best friend :) */
1956 static int G_GetHelpers(void)
1958 int j = M_CheckParm ("-dog");
1960 if (!j)
1961 j = M_CheckParm ("-dogs");
1962 return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs;
1964 #endif
1967 // killough 3/1/98: function to reload all the default parameter
1968 // settings before a new game begins
1970 void G_ReloadDefaults(void)
1972 // killough 3/1/98: Initialize options based on config file
1973 // (allows functions above to load different values for demos
1974 // and savegames without messing up defaults).
1976 weapon_recoil = default_weapon_recoil; // weapon recoil
1978 player_bobbing = default_player_bobbing; // whether player bobs or not
1980 variable_friction = allow_pushers = true;
1982 monsters_remember = default_monsters_remember; // remember former enemies
1984 monster_infighting = default_monster_infighting; // killough 7/19/98
1986 #ifdef DOGS
1987 dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98
1988 dog_jumping = default_dog_jumping;
1989 #endif
1991 distfriend = default_distfriend; // killough 8/8/98
1993 monster_backing = default_monster_backing; // killough 9/8/98
1995 monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98
1997 monster_friction = default_monster_friction; // killough 10/98
1999 help_friends = default_help_friends; // killough 9/9/98
2001 monkeys = default_monkeys;
2003 // jff 1/24/98 reset play mode to command line spec'd version
2004 // killough 3/1/98: moved to here
2005 // respawnparm = clrespawnparm;
2006 // fastparm = clfastparm;
2007 // nomonsters = clnomonsters;
2009 //jff 3/24/98 set startskill from defaultskill in config file, unless
2010 // it has already been set by a -skill parameter
2011 if (startskill==sk_none)
2012 startskill = (skill_t)(defaultskill-1);
2014 demoplayback = false;
2015 singledemo = false; // killough 9/29/98: don't stop after 1 demo
2016 netdemo = false;
2018 // killough 2/21/98:
2019 memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1));
2021 consoleplayer = 0;
2023 compatibility_level = default_compatibility_level;
2025 int i = M_CheckParm("-complevel");
2026 if (i && (1+i) < myargc) compatibility_level = atoi(myargv[i+1]);
2028 if (compatibility_level == (complevel_t)-1)
2029 compatibility_level = MAX_COMPATIBILITY_LEVEL-1;
2031 if (mbf_features)
2032 memcpy(comp, default_comp, sizeof comp);
2033 else
2034 G_Compatibility();
2036 // killough 3/31/98, 4/5/98: demo sync insurance
2037 demo_insurance = default_demo_insurance == 1;
2039 rngseed += 1 + gametic; // CPhipps
2040 // rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps
2043 void G_DoNewGame (void)
2045 G_ReloadDefaults(); // killough 3/1/98
2046 netgame = false; // killough 3/1/98
2047 deathmatch = false;
2048 G_InitNew (d_skill, d_episode, d_map);
2049 gameaction = ga_nothing;
2051 //jff 4/26/98 wake up the status bar in case were coming out of a DM demo
2052 ST_Start();
2055 // killough 4/10/98: New function to fix bug which caused Doom
2056 // lockups when idclev was used in conjunction with -fast.
2058 void G_SetFastParms(int fast_pending)
2060 static int fast = 0; // remembers fast state
2061 int i;
2062 if (fast != fast_pending) { /* only change if necessary */
2063 if ((fast = fast_pending))
2065 for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2066 if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98
2067 states[i].tics >>= 1; // don't change 1->0 since it causes cycles
2068 mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
2069 mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
2070 mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
2072 else
2074 for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++)
2075 states[i].tics <<= 1;
2076 mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
2077 mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
2078 mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
2083 // The sky texture to be used instead of the F_SKY1 dummy.
2084 extern int skytexture;
2087 // G_InitNew
2088 // Can be called by the startup code or the menu task,
2089 // consoleplayer, displayplayer, playeringame[] should be set.
2092 void G_InitNew(skill_t skill, int episode, int map)
2094 int i;
2096 if (paused)
2098 paused = false;
2099 S_ResumeSound();
2102 if (skill > sk_nightmare)
2103 skill = sk_nightmare;
2105 if (episode < 1)
2106 episode = 1;
2108 if (gamemode == retail)
2110 if (episode > 4)
2111 episode = 4;
2113 else
2114 if (gamemode == shareware)
2116 if (episode > 1)
2117 episode = 1; // only start episode 1 on shareware
2119 else
2120 if (episode > 3)
2121 episode = 3;
2123 if (map < 1)
2124 map = 1;
2125 if (map > 9 && gamemode != commercial)
2126 map = 9;
2128 G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98
2130 M_ClearRandom();
2132 respawnmonsters = skill == sk_nightmare || respawnparm;
2134 // force players to be initialized upon first level load
2135 for (i=0 ; i<MAXPLAYERS ; i++)
2136 players[i].playerstate = PST_REBORN;
2138 usergame = true; // will be set false if a demo
2139 paused = false;
2140 automapmode &= ~am_active;
2141 gameepisode = episode;
2142 gamemap = map;
2143 gameskill = skill;
2145 totalleveltimes = 0; // cph
2147 //jff 4/16/98 force marks on automap cleared every new level start
2148 AM_clearMarks();
2150 G_DoLoadLevel ();
2155 // DEMO RECORDING
2158 unsigned char DEMOMARKER=0x80;
2160 void G_ReadDemoTiccmd (ticcmd_t* cmd)
2162 if (*demo_p == DEMOMARKER)
2163 G_CheckDemoStatus(); // end of demo data stream
2164 else
2166 cmd->forwardmove = ((signed char)*demo_p++);
2167 cmd->sidemove = ((signed char)*demo_p++);
2168 if (!longtics) {
2169 cmd->angleturn = ((unsigned char)*demo_p++)<<8;
2170 } else {
2171 unsigned int lowbyte = (unsigned char)*demo_p++;
2172 cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte;
2174 cmd->buttons = (unsigned char)*demo_p++;
2178 /* Demo limits removed -- killough
2179 * cph - record straight to file
2181 void G_WriteDemoTiccmd (ticcmd_t* cmd)
2183 char buf[5];
2184 char *p = buf;
2186 *p++ = cmd->forwardmove;
2187 *p++ = cmd->sidemove;
2188 if (!longtics) {
2189 *p++ = (cmd->angleturn+128)>>8;
2190 } else {
2191 signed short a = cmd->angleturn;
2192 *p++ = a & 0xff;
2193 *p++ = (a >> 8) & 0xff;
2195 *p++ = cmd->buttons;
2196 if (write(demofd, buf, p-buf) != p-buf)
2197 I_Error("G_WriteDemoTiccmd: error writing demo");
2199 /* cph - alias demo_p to it so we can read it back */
2200 demo_p = buf;
2201 G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
2205 // G_RecordDemo
2208 void G_RecordDemo (const char* name)
2210 char demoname[100];
2211 usergame = false;
2212 AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough
2213 demorecording = true;
2214 /* cph - Record demos straight to file
2215 * If file already exists, try to continue existing demo
2217 if (fileexists(demoname)) {
2218 demofd = open(demoname, O_WRONLY | O_APPEND);
2219 } else {
2220 demofd = open(demoname, O_WRONLY | O_RDONLY);
2221 if (demofd) {
2222 int slot = -1;
2223 int rc;
2225 byte buf[200];
2226 size_t len;
2227 read(demofd, buf, sizeof(buf));
2229 len = G_ReadDemoHeader(buf) - buf;
2230 lseek(demofd, len, SEEK_SET);
2232 do {
2233 byte buf[4];
2234 rc = read(demofd, buf, sizeof(buf));
2235 if (buf[0] == DEMOMARKER) break;
2236 if (buf[3] & BT_SPECIAL)
2237 if ((buf[3] & BT_SPECIALMASK) == BTS_SAVEGAME)
2238 slot = (buf[3] & BTS_SAVEMASK)>>BTS_SAVESHIFT;
2239 } while (rc == /* sizeof(buf) is out of scope here */ 4 );
2240 if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue");
2241 lseek(demofd, -rc, SEEK_CUR);
2242 G_LoadGame(slot, false);
2243 autostart = false;
2246 if (!demofd) I_Error("G_RecordDemo: failed to open %s", name);
2249 // These functions are used to read and write game-specific options in demos
2250 // and savegames so that demo sync is preserved and savegame restoration is
2251 // complete. Not all options (for example "compatibility"), however, should
2252 // be loaded and saved here. It is extremely important to use the same
2253 // positions as before for the variables, so if one becomes obsolete, the
2254 // byte(s) should still be skipped over or padded with 0's.
2255 // Lee Killough 3/1/98
2257 extern boolean forceOldBsp;
2259 byte *G_WriteOptions(byte *demo_p)
2261 byte *target = demo_p + GAME_OPTION_SIZE;
2263 *demo_p++ = monsters_remember; // part of monster AI
2265 *demo_p++ = variable_friction; // ice & mud
2267 *demo_p++ = weapon_recoil; // weapon recoil
2269 *demo_p++ = allow_pushers; // MT_PUSH Things
2271 *demo_p++ = 0;
2273 *demo_p++ = player_bobbing; // whether player bobs or not
2275 // killough 3/6/98: add parameters to savegame, move around some in demos
2276 *demo_p++ = respawnparm;
2277 *demo_p++ = fastparm;
2278 *demo_p++ = nomonsters;
2280 *demo_p++ = demo_insurance; // killough 3/31/98
2282 // killough 3/26/98: Added rngseed. 3/31/98: moved here
2283 *demo_p++ = (byte)((rngseed >> 24) & 0xff);
2284 *demo_p++ = (byte)((rngseed >> 16) & 0xff);
2285 *demo_p++ = (byte)((rngseed >> 8) & 0xff);
2286 *demo_p++ = (byte)( rngseed & 0xff);
2288 // Options new to v2.03 begin here
2290 *demo_p++ = monster_infighting; // killough 7/19/98
2292 #ifdef DOGS
2293 *demo_p++ = dogs; // killough 7/19/98
2294 #else
2295 *demo_p++ = 0;
2296 #endif
2298 *demo_p++ = 0;
2299 *demo_p++ = 0;
2301 *demo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98
2302 *demo_p++ = distfriend & 0xff; // killough 8/8/98
2304 *demo_p++ = monster_backing; // killough 9/8/98
2306 *demo_p++ = monster_avoid_hazards; // killough 9/9/98
2308 *demo_p++ = monster_friction; // killough 10/98
2310 *demo_p++ = help_friends; // killough 9/9/98
2312 #ifdef DOGS
2313 *demo_p++ = dog_jumping;
2314 #else
2315 *demo_p++ = 0;
2316 #endif
2318 *demo_p++ = monkeys;
2320 { // killough 10/98: a compatibility vector now
2321 int i;
2322 for (i=0; i < COMP_TOTAL; i++)
2323 *demo_p++ = comp[i] != 0;
2326 *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20
2328 //----------------
2329 // Padding at end
2330 //----------------
2331 while (demo_p < target)
2332 *demo_p++ = 0;
2334 if (demo_p != target)
2335 I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small");
2337 return target;
2340 /* Same, but read instead of write
2341 * cph - const byte*'s
2344 const byte *G_ReadOptions(const byte *demo_p)
2346 const byte *target = demo_p + GAME_OPTION_SIZE;
2348 monsters_remember = *demo_p++;
2350 variable_friction = *demo_p; // ice & mud
2351 demo_p++;
2353 weapon_recoil = *demo_p; // weapon recoil
2354 demo_p++;
2356 allow_pushers = *demo_p; // MT_PUSH Things
2357 demo_p++;
2359 demo_p++;
2361 player_bobbing = *demo_p; // whether player bobs or not
2362 demo_p++;
2364 // killough 3/6/98: add parameters to savegame, move from demo
2365 respawnparm = *demo_p++;
2366 fastparm = *demo_p++;
2367 nomonsters = *demo_p++;
2369 demo_insurance = *demo_p++; // killough 3/31/98
2371 // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here
2373 rngseed = *demo_p++ & 0xff;
2374 rngseed <<= 8;
2375 rngseed += *demo_p++ & 0xff;
2376 rngseed <<= 8;
2377 rngseed += *demo_p++ & 0xff;
2378 rngseed <<= 8;
2379 rngseed += *demo_p++ & 0xff;
2381 // Options new to v2.03
2382 if (mbf_features)
2384 monster_infighting = *demo_p++; // killough 7/19/98
2386 #ifdef DOGS
2387 dogs = *demo_p++; // killough 7/19/98
2388 #else
2389 demo_p++;
2390 #endif
2392 demo_p += 2;
2394 distfriend = *demo_p++ << 8; // killough 8/8/98
2395 distfriend+= *demo_p++;
2397 monster_backing = *demo_p++; // killough 9/8/98
2399 monster_avoid_hazards = *demo_p++; // killough 9/9/98
2401 monster_friction = *demo_p++; // killough 10/98
2403 help_friends = *demo_p++; // killough 9/9/98
2405 #ifdef DOGS
2406 dog_jumping = *demo_p++; // killough 10/98
2407 #else
2408 demo_p++;
2409 #endif
2411 monkeys = *demo_p++;
2413 { // killough 10/98: a compatibility vector now
2414 int i;
2415 for (i=0; i < COMP_TOTAL; i++)
2416 comp[i] = *demo_p++;
2419 forceOldBsp = *demo_p++; // cph 2002/07/20
2421 else /* defaults for versions <= 2.02 */
2423 /* cph - comp[] has already been set up right by G_Compatibility */
2425 monster_infighting = 1; // killough 7/19/98
2427 monster_backing = 0; // killough 9/8/98
2429 monster_avoid_hazards = 0; // killough 9/9/98
2431 monster_friction = 0; // killough 10/98
2433 help_friends = 0; // killough 9/9/98
2435 #ifdef DOGS
2436 dogs = 0; // killough 7/19/98
2437 dog_jumping = 0; // killough 10/98
2438 #endif
2440 monkeys = 0;
2443 return target;
2446 void G_BeginRecording (void)
2448 int i;
2449 byte *demostart, *demo_p;
2450 demostart = demo_p = malloc(1000);
2452 /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */
2453 if (mbf_features) {
2454 { /* Write version code into demo */
2455 unsigned char v=0;
2456 switch(compatibility_level) {
2457 case doom_12_compatibility:
2458 case doom_demo_compatibility:
2459 case doom_compatibility:
2460 case boom_compatibility_compatibility:
2461 case boom_201_compatibility:
2462 case boom_202_compatibility:
2463 case lxdoom_1_compatibility:
2464 case prboom_1_compatibility:
2465 case MAX_COMPATIBILITY_LEVEL:
2466 case mbf_compatibility: v = 204; break;
2467 case prboom_2_compatibility: v = 210; break;
2468 case prboom_3_compatibility: v = 211; break;
2470 *demo_p++ = v;
2473 // signature
2474 *demo_p++ = 0x1d;
2475 *demo_p++ = 'M';
2476 *demo_p++ = 'B';
2477 *demo_p++ = 'F';
2478 *demo_p++ = 0xe6;
2479 *demo_p++ = '\0';
2481 /* killough 2/22/98: save compatibility flag in new demos
2482 * cph - FIXME? MBF demos will always be not in compat. mode */
2483 *demo_p++ = 0;
2485 *demo_p++ = gameskill;
2486 *demo_p++ = gameepisode;
2487 *demo_p++ = gamemap;
2488 *demo_p++ = deathmatch;
2489 *demo_p++ = consoleplayer;
2491 demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
2493 for (i=0 ; i<MAXPLAYERS ; i++)
2494 *demo_p++ = playeringame[i];
2496 // killough 2/28/98:
2497 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2498 // support enhancements later w/o losing demo compatibility
2500 for (; i<MIN_MAXPLAYERS; i++)
2501 *demo_p++ = 0;
2503 } else if (compatibility_level > doom_compatibility) {
2504 byte v=0, c=0; /* Nominally, version and compatibility bits */
2505 switch (compatibility_level) {
2506 case boom_compatibility_compatibility: v = 202, c = 1; break;
2507 case boom_201_compatibility: v = 201; c = 0; break;
2508 case boom_202_compatibility: v = 202, c = 0; break;
2509 default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?");
2511 *demo_p++ = v;
2513 // signature
2514 *demo_p++ = 0x1d;
2515 *demo_p++ = 'B';
2516 *demo_p++ = 'o';
2517 *demo_p++ = 'o';
2518 *demo_p++ = 'm';
2519 *demo_p++ = 0xe6;
2521 /* CPhipps - save compatibility level in demos */
2522 *demo_p++ = c;
2524 *demo_p++ = gameskill;
2525 *demo_p++ = gameepisode;
2526 *demo_p++ = gamemap;
2527 *demo_p++ = deathmatch;
2528 *demo_p++ = consoleplayer;
2530 demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options
2532 for (i=0 ; i<MAXPLAYERS ; i++)
2533 *demo_p++ = playeringame[i];
2535 // killough 2/28/98:
2536 // We always store at least MIN_MAXPLAYERS bytes in demo, to
2537 // support enhancements later w/o losing demo compatibility
2539 for (; i<MIN_MAXPLAYERS; i++)
2540 *demo_p++ = 0;
2541 } else { // cph - write old v1.9 demos (might even sync)
2542 longtics = M_CheckParm("-longtics");
2543 *demo_p++ = longtics ? 111 : 109; // v1.9 has best chance of syncing these
2544 *demo_p++ = gameskill;
2545 *demo_p++ = gameepisode;
2546 *demo_p++ = gamemap;
2547 *demo_p++ = deathmatch;
2548 *demo_p++ = respawnparm;
2549 *demo_p++ = fastparm;
2550 *demo_p++ = nomonsters;
2551 *demo_p++ = consoleplayer;
2552 for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
2553 *demo_p++ = playeringame[i];
2556 if (write(demofd, demostart, demo_p-demostart) != (signed)(size_t)(demo_p-demostart))
2557 I_Error("G_BeginRecording: Error writing demo header");
2558 free(demostart);
2563 // G_PlayDemo
2566 static const char *defdemoname;
2568 void G_DeferedPlayDemo (const char* name)
2570 defdemoname = name;
2571 gameaction = ga_playdemo;
2574 static int demolumpnum = -1;
2576 static const byte* G_ReadDemoHeader(const byte *demo_p)
2578 skill_t skill;
2579 int i, episode, map;
2580 int demover;
2582 basetic = gametic; // killough 9/29/98
2584 // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly.
2585 // Old demos turn on demo_compatibility => compatibility; new demos load
2586 // compatibility flag, and other flags as well, as a part of the demo.
2588 demover = *demo_p++;
2590 if (demover < 200) // Autodetect old demos
2592 compatibility_level = doom_demo_compatibility;
2593 if (demover >= 111) longtics = 1;
2595 G_Compatibility();
2597 // killough 3/2/98: force these variables to be 0 in demo_compatibility
2599 variable_friction = 0;
2601 weapon_recoil = 0;
2603 allow_pushers = 0;
2605 monster_infighting = 1; // killough 7/19/98
2607 #ifdef DOGS
2608 dogs = 0; // killough 7/19/98
2609 dog_jumping = 0; // killough 10/98
2610 #endif
2612 monster_backing = 0; // killough 9/8/98
2614 monster_avoid_hazards = 0; // killough 9/9/98
2616 monster_friction = 0; // killough 10/98
2617 help_friends = 0; // killough 9/9/98
2618 monkeys = 0;
2620 // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm,
2621 // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions())
2623 if ((skill=demover) >= 100) // For demos from versions >= 1.4
2625 skill = *demo_p++;
2626 episode = *demo_p++;
2627 map = *demo_p++;
2628 deathmatch = *demo_p++;
2629 respawnparm = *demo_p++;
2630 fastparm = *demo_p++;
2631 nomonsters = *demo_p++;
2632 consoleplayer = *demo_p++;
2634 else
2636 episode = *demo_p++;
2637 map = *demo_p++;
2638 deathmatch = respawnparm = fastparm =
2639 nomonsters = consoleplayer = 0;
2642 else // new versions of demos
2644 demo_p += 6; // skip signature;
2645 switch (demover) {
2646 case 200: /* BOOM */
2647 case 201:
2648 if (!*demo_p++)
2649 compatibility_level = boom_201_compatibility;
2650 else
2651 compatibility_level = boom_compatibility_compatibility;
2652 break;
2653 case 202:
2654 if (!*demo_p++)
2655 compatibility_level = boom_202_compatibility;
2656 else
2657 compatibility_level = boom_compatibility_compatibility;
2658 break;
2659 case 203:
2660 /* LxDoom or MBF - determine from signature
2661 * cph - load compatibility level */
2662 switch (demobuffer[2]) {
2663 case 'B': /* LxDoom */
2664 /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */
2665 compatibility_level = lxdoom_1_compatibility;
2666 break;
2667 case 'M':
2668 compatibility_level = mbf_compatibility;
2669 demo_p++;
2670 break;
2672 break;
2673 case 210:
2674 compatibility_level = prboom_2_compatibility;
2675 demo_p++;
2676 break;
2677 case 211:
2678 compatibility_level = prboom_3_compatibility;
2679 demo_p++;
2680 break;
2682 G_Compatibility();
2683 skill = *demo_p++;
2684 episode = *demo_p++;
2685 map = *demo_p++;
2686 deathmatch = *demo_p++;
2687 consoleplayer = *demo_p++;
2689 demo_p = G_ReadOptions(demo_p); // killough 3/1/98: Read game options
2691 if (demover == 200) // killough 6/3/98: partially fix v2.00 demos
2692 demo_p += 128-GAME_OPTION_SIZE;
2695 // printf( "G_DoPlayDemo: playing demo with %s compatibility\n",
2696 // comp_lev_str[compatibility_level]);
2698 if (demo_compatibility) // only 4 players can exist in old demos
2700 for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough
2701 playeringame[i] = *demo_p++;
2702 for (;i < MAXPLAYERS; i++)
2703 playeringame[i] = 0;
2705 else
2707 for (i=0 ; i < MAXPLAYERS; i++)
2708 playeringame[i] = *demo_p++;
2709 demo_p += MIN_MAXPLAYERS - MAXPLAYERS;
2712 if (playeringame[1])
2714 netgame = true;
2715 netdemo = true;
2718 if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */
2719 G_InitNew(skill, episode, map);
2722 for (i=0; i<MAXPLAYERS;i++) // killough 4/24/98
2723 players[i].cheats = 0;
2725 return demo_p;
2728 void G_DoPlayDemo(void)
2730 char basename[9];
2732 ExtractFileBase(defdemoname,basename); // killough
2733 basename[8] = 0;
2734 demobuffer = demo_p = W_CacheLumpNum(demolumpnum = W_GetNumForName(basename));
2735 /* cph - store lump number for unlocking later */
2737 demo_p = G_ReadDemoHeader(demo_p);
2739 gameaction = ga_nothing;
2740 usergame = false;
2742 demoplayback = true;
2746 // G_TimeDemo
2749 void G_TimeDemo(const char *name) // CPhipps - const char*
2751 timingdemo = true;
2752 singletics = true;
2753 defdemoname = name;
2754 gameaction = ga_playdemo;
2758 /* G_CheckDemoStatus
2760 * Called after a death or level completion to allow demos to be cleaned up
2761 * Returns true if a new demo loop action will take place
2764 boolean G_CheckDemoStatus (void)
2766 if (demorecording)
2768 demorecording = false;
2769 write(demofd, &DEMOMARKER, 1);
2770 close(demofd);
2771 I_Error("G_CheckDemoStatus: Demo recorded");
2772 return false; // killough
2775 if (timingdemo)
2777 // int endtime = I_GetTime_RealTime ();
2778 int endtime = I_GetTime ();
2779 // killough -- added fps information and made it work for longer demos:
2780 unsigned realtics = endtime-starttime;
2781 int fd=open(GAMEBASE "timedemo.txt",O_WRONLY | O_CREAT,0666);
2782 fdprintf (fd,"Timed %d gametics in %d realtics = %d frames per second",
2783 (unsigned) gametic, realtics,
2784 (unsigned) gametic * TICRATE/ realtics);
2785 close(fd);
2786 I_Error ("%d gametics in %d realtics",
2787 (unsigned) gametic,realtics,
2788 (unsigned) gametic * TICRATE / realtics);
2789 return false;
2792 if (demoplayback)
2794 if (singledemo)
2795 I_Error("Done Playing Demo");
2796 return false;
2797 // exit(0); // killough
2799 if (demolumpnum != -1) {
2800 // cph - unlock the demo lump
2801 W_UnlockLumpNum(demolumpnum);
2802 demolumpnum = -1;
2804 G_ReloadDefaults(); // killough 3/1/98
2805 netgame = false; // killough 3/29/98
2806 deathmatch = false;
2807 D_AdvanceDemo ();
2808 return true;
2810 return false;
2813 // killough 1/22/98: this is a "Doom printf" for messages. I've gotten
2814 // tired of using players->message=... and so I've added this dprintf.
2816 // killough 3/6/98: Made limit static to allow z_zone functions to call
2817 // this function, without calling realloc(), which seems to cause problems.
2819 #define MAX_MESSAGE_SIZE 1024
2820 static char msg[MAX_MESSAGE_SIZE];
2822 // CPhipps - renamed to doom_printf to avoid name collision with glibc
2823 void doom_printf(const char *s, ...)
2825 va_list v;
2826 va_start(v,s);
2827 vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */
2828 va_end(v);
2829 players[consoleplayer].message = msg; // set new message