Add key bindings for pause, message refresh.
[chocolate-doom.git] / src / g_game.c
blob8255fdd0f3eb149be16ee280ec20503dafba3614
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // Copyright(C) 1993-1996 Id Software, Inc.
5 // Copyright(C) 2005 Simon Howard
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 // 02111-1307, USA.
22 // DESCRIPTION: none
24 //-----------------------------------------------------------------------------
28 #include <string.h>
29 #include <stdlib.h>
30 #include <math.h>
32 #include "doomdef.h"
33 #include "doomstat.h"
35 #include "deh_main.h"
36 #include "deh_misc.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 "i_timer.h"
46 #include "i_video.h"
48 #include "p_setup.h"
49 #include "p_saveg.h"
50 #include "p_tick.h"
52 #include "d_main.h"
54 #include "wi_stuff.h"
55 #include "hu_stuff.h"
56 #include "st_stuff.h"
57 #include "am_map.h"
59 // Needs access to LFB.
60 #include "v_video.h"
62 #include "w_wad.h"
64 #include "p_local.h"
66 #include "s_sound.h"
68 // Data.
69 #include "dstrings.h"
70 #include "sounds.h"
72 // SKY handling - still the wrong place.
73 #include "r_data.h"
74 #include "r_sky.h"
78 #include "g_game.h"
81 #define SAVEGAMESIZE 0x2c000
85 boolean G_CheckDemoStatus (void);
86 void G_ReadDemoTiccmd (ticcmd_t* cmd);
87 void G_WriteDemoTiccmd (ticcmd_t* cmd);
88 void G_PlayerReborn (int player);
89 void G_InitNew (skill_t skill, int episode, int map);
91 void G_DoReborn (int playernum);
93 void G_DoLoadLevel (void);
94 void G_DoNewGame (void);
95 void G_DoLoadGame (void);
96 void G_DoPlayDemo (void);
97 void G_DoCompleted (void);
98 void G_DoVictory (void);
99 void G_DoWorldDone (void);
100 void G_DoSaveGame (void);
102 // Gamestate the last time G_Ticker was called.
104 gamestate_t oldgamestate;
106 gameaction_t gameaction;
107 gamestate_t gamestate;
108 skill_t gameskill;
109 boolean respawnmonsters;
110 int gameepisode;
111 int gamemap;
113 // If non-zero, exit the level after this number of minutes.
115 int timelimit;
117 boolean paused;
118 boolean sendpause; // send a pause event next tic
119 boolean sendsave; // send a save event next tic
120 boolean usergame; // ok to save / end game
122 boolean timingdemo; // if true, exit with report on completion
123 boolean nodrawers; // for comparative timing purposes
124 boolean noblit; // for comparative timing purposes
125 int starttime; // for comparative timing purposes
127 boolean viewactive;
129 boolean deathmatch; // only if started as net death
130 boolean netgame; // only true if packets are broadcast
131 boolean playeringame[MAXPLAYERS];
132 player_t players[MAXPLAYERS];
134 boolean turbodetected[MAXPLAYERS];
136 int consoleplayer; // player taking events and displaying
137 int displayplayer; // view being displayed
138 int gametic;
139 int levelstarttic; // gametic at level start
140 int totalkills, totalitems, totalsecret; // for intermission
142 char demoname[32];
143 boolean demorecording;
144 boolean longtics; // cph's doom 1.91 longtics hack
145 boolean lowres_turn; // low resolution turning for longtics
146 boolean demoplayback;
147 boolean netdemo;
148 byte* demobuffer;
149 byte* demo_p;
150 byte* demoend;
151 boolean singledemo; // quit after playing a demo from cmdline
153 boolean precache = true; // if true, load all graphics at start
155 boolean testcontrols = false; // Invoked by setup to test controls
157 wbstartstruct_t wminfo; // parms for world map / intermission
159 byte consistancy[MAXPLAYERS][BACKUPTICS];
163 // Controls
165 int key_right = KEY_RIGHTARROW;
166 int key_left = KEY_LEFTARROW;
168 int key_up = KEY_UPARROW;
169 int key_down = KEY_DOWNARROW;
170 int key_strafeleft = ',';
171 int key_straferight = '.';
172 int key_fire = KEY_RCTRL;
173 int key_use = ' ';
174 int key_strafe = KEY_RALT;
175 int key_speed = KEY_RSHIFT;
177 int key_weapon1 = '1';
178 int key_weapon2 = '2';
179 int key_weapon3 = '3';
180 int key_weapon4 = '4';
181 int key_weapon5 = '5';
182 int key_weapon6 = '6';
183 int key_weapon7 = '7';
184 int key_weapon8 = '8';
186 int key_pause = KEY_PAUSE;
188 int mousebfire = 0;
189 int mousebstrafe = 1;
190 int mousebforward = 2;
192 int mousebstrafeleft = -1;
193 int mousebstraferight = -1;
194 int mousebbackward = -1;
195 int mousebuse = -1;
197 // Control whether if a mouse button is double clicked, it acts like
198 // "use" has been pressed
200 int dclick_use = 1;
202 int joybfire = 0;
203 int joybstrafe = 1;
204 int joybuse = 3;
205 int joybspeed = 2;
206 int joybstrafeleft = -1;
207 int joybstraferight = -1;
209 // fraggle: Disallow mouse and joystick movement to cause forward/backward
210 // motion. Specified with the '-novert' command line parameter.
211 // This is an int to allow saving to config file
213 int novert = 0;
217 #define MAXPLMOVE (forwardmove[1])
219 #define TURBOTHRESHOLD 0x32
221 fixed_t forwardmove[2] = {0x19, 0x32};
222 fixed_t sidemove[2] = {0x18, 0x28};
223 fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
225 static int *weapon_keys[] = {
226 &key_weapon1,
227 &key_weapon2,
228 &key_weapon3,
229 &key_weapon4,
230 &key_weapon5,
231 &key_weapon6,
232 &key_weapon7,
233 &key_weapon8
236 #define SLOWTURNTICS 6
238 #define NUMKEYS 256
240 static boolean gamekeydown[NUMKEYS];
241 static int turnheld; // for accelerative turning
243 static boolean mousearray[4];
244 static boolean *mousebuttons = &mousearray[1]; // allow [-1]
246 // mouse values are used once
247 int mousex;
248 int mousey;
250 static int dclicktime;
251 static boolean dclickstate;
252 static int dclicks;
253 static int dclicktime2;
254 static boolean dclickstate2;
255 static int dclicks2;
257 #define MAX_JOY_BUTTONS 20
259 // joystick values are repeated
260 static int joyxmove;
261 static int joyymove;
262 static boolean joyarray[MAX_JOY_BUTTONS + 1];
263 static boolean *joybuttons = &joyarray[1]; // allow [-1]
265 static int savegameslot;
266 static char savedescription[32];
268 static int testcontrols_mousespeed;
270 #define BODYQUESIZE 32
272 mobj_t* bodyque[BODYQUESIZE];
273 int bodyqueslot;
275 int vanilla_savegame_limit = 1;
276 int vanilla_demo_limit = 1;
279 #define MOUSE_SPEED_BOX_WIDTH 16
280 #define COLOR_RED 0xb0
281 #define COLOR_BLACK 0x00
282 #define COLOR_WHITE 0x04
283 #define COLOR_YELLOW 0xe7
285 void G_DrawMouseSpeedBox(void)
287 extern int usemouse;
288 int i;
289 int box_x, box_y;
290 int original_speed;
291 int x, y;
292 int redline_x;
293 int linelen;
294 char *lumpname;
295 int color;
297 // If the mouse is turned off or acceleration is turned off, don't
298 // draw the box at all.
300 if (!usemouse || fabs(mouse_acceleration - 1) < 0.01)
302 return;
305 // Calculate box position
307 box_x = SCREENWIDTH - MOUSE_SPEED_BOX_WIDTH * 8;
308 box_y = SCREENHEIGHT - 9;
310 // Draw the box.
312 x = box_x;
314 for (i=0; i<MOUSE_SPEED_BOX_WIDTH; ++i)
316 if (i == 0)
318 lumpname = "M_LSLEFT";
320 else if (i == MOUSE_SPEED_BOX_WIDTH - 1)
322 lumpname = "M_LSRGHT";
324 else
326 lumpname = "M_LSCNTR";
329 V_DrawPatchDirect(x, box_y, 0, W_CacheLumpName(DEH_String(lumpname),
330 PU_CACHE));
331 x += 8;
334 // Calculate the position of the red line. This is 1/3 of the way
335 // along the box.
337 redline_x = (MOUSE_SPEED_BOX_WIDTH / 3) * 8;
339 // Undo acceleration and get back the original mouse speed
341 if (testcontrols_mousespeed < mouse_threshold)
343 original_speed = testcontrols_mousespeed;
345 else
347 original_speed = testcontrols_mousespeed - mouse_threshold;
348 original_speed = (int) (original_speed / mouse_acceleration);
349 original_speed += mouse_threshold;
352 // Calculate line length
354 linelen = (original_speed * redline_x) / mouse_threshold;
356 // Draw horizontal "thermometer"
358 for (x=0; x<(MOUSE_SPEED_BOX_WIDTH - 1) * 8; ++x)
360 if (x < linelen)
362 if (x < redline_x)
364 color = COLOR_WHITE;
366 else
368 color = COLOR_YELLOW;
371 else
373 color = COLOR_BLACK;
376 screens[0][(box_y - 4) * SCREENWIDTH + box_x + x + 1] = color;
379 // Draw red line
381 for (y=box_y - 8; y<box_y; ++y)
383 screens[0][y * SCREENWIDTH + box_x + redline_x] = COLOR_RED;
387 int G_CmdChecksum (ticcmd_t* cmd)
389 size_t i;
390 int sum = 0;
392 for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++)
393 sum += ((int *)cmd)[i];
395 return sum;
400 // G_BuildTiccmd
401 // Builds a ticcmd from all of the available inputs
402 // or reads it from the demo buffer.
403 // If recording a demo, write it out
405 void G_BuildTiccmd (ticcmd_t* cmd)
407 int i;
408 boolean strafe;
409 boolean bstrafe;
410 int speed;
411 int tspeed;
412 int forward;
413 int side;
415 memset(cmd, 0, sizeof(ticcmd_t));
417 cmd->consistancy =
418 consistancy[consoleplayer][maketic%BACKUPTICS];
420 strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
421 || joybuttons[joybstrafe];
423 // fraggle: support the old "joyb_speed = 31" hack which
424 // allowed an autorun effect
426 speed = key_speed >= NUMKEYS
427 || joybspeed >= MAX_JOY_BUTTONS
428 || gamekeydown[key_speed]
429 || joybuttons[joybspeed];
431 forward = side = 0;
433 // use two stage accelerative turning
434 // on the keyboard and joystick
435 if (joyxmove < 0
436 || joyxmove > 0
437 || gamekeydown[key_right]
438 || gamekeydown[key_left])
439 turnheld += ticdup;
440 else
441 turnheld = 0;
443 if (turnheld < SLOWTURNTICS)
444 tspeed = 2; // slow turn
445 else
446 tspeed = speed;
448 // let movement keys cancel each other out
449 if (strafe)
451 if (gamekeydown[key_right])
453 // fprintf(stderr, "strafe right\n");
454 side += sidemove[speed];
456 if (gamekeydown[key_left])
458 // fprintf(stderr, "strafe left\n");
459 side -= sidemove[speed];
461 if (joyxmove > 0)
462 side += sidemove[speed];
463 if (joyxmove < 0)
464 side -= sidemove[speed];
467 else
469 if (gamekeydown[key_right])
470 cmd->angleturn -= angleturn[tspeed];
471 if (gamekeydown[key_left])
472 cmd->angleturn += angleturn[tspeed];
473 if (joyxmove > 0)
474 cmd->angleturn -= angleturn[tspeed];
475 if (joyxmove < 0)
476 cmd->angleturn += angleturn[tspeed];
479 if (gamekeydown[key_up])
481 // fprintf(stderr, "up\n");
482 forward += forwardmove[speed];
484 if (gamekeydown[key_down])
486 // fprintf(stderr, "down\n");
487 forward -= forwardmove[speed];
490 if (joyymove < 0)
491 forward += forwardmove[speed];
492 if (joyymove > 0)
493 forward -= forwardmove[speed];
495 if (gamekeydown[key_strafeleft]
496 || joybuttons[joybstrafeleft]
497 || mousebuttons[mousebstrafeleft])
499 side -= sidemove[speed];
502 if (gamekeydown[key_straferight]
503 || joybuttons[joybstraferight]
504 || mousebuttons[mousebstraferight])
506 side += sidemove[speed];
509 // buttons
510 cmd->chatchar = HU_dequeueChatChar();
512 if (gamekeydown[key_fire] || mousebuttons[mousebfire]
513 || joybuttons[joybfire])
514 cmd->buttons |= BT_ATTACK;
516 if (gamekeydown[key_use]
517 || joybuttons[joybuse]
518 || mousebuttons[mousebuse])
520 cmd->buttons |= BT_USE;
521 // clear double clicks if hit use button
522 dclicks = 0;
525 // chainsaw overrides
527 for (i=0; i<arrlen(weapon_keys); ++i)
529 int key = *weapon_keys[i];
531 if (gamekeydown[key])
533 cmd->buttons |= BT_CHANGE;
534 cmd->buttons |= i<<BT_WEAPONSHIFT;
535 break;
539 // mouse
540 if (mousebuttons[mousebforward])
542 forward += forwardmove[speed];
544 if (mousebuttons[mousebbackward])
546 forward -= forwardmove[speed];
549 if (dclick_use)
551 // forward double click
552 if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
554 dclickstate = mousebuttons[mousebforward];
555 if (dclickstate)
556 dclicks++;
557 if (dclicks == 2)
559 cmd->buttons |= BT_USE;
560 dclicks = 0;
562 else
563 dclicktime = 0;
565 else
567 dclicktime += ticdup;
568 if (dclicktime > 20)
570 dclicks = 0;
571 dclickstate = 0;
575 // strafe double click
576 bstrafe =
577 mousebuttons[mousebstrafe]
578 || joybuttons[joybstrafe];
579 if (bstrafe != dclickstate2 && dclicktime2 > 1 )
581 dclickstate2 = bstrafe;
582 if (dclickstate2)
583 dclicks2++;
584 if (dclicks2 == 2)
586 cmd->buttons |= BT_USE;
587 dclicks2 = 0;
589 else
590 dclicktime2 = 0;
592 else
594 dclicktime2 += ticdup;
595 if (dclicktime2 > 20)
597 dclicks2 = 0;
598 dclickstate2 = 0;
603 // fraggle: allow disabling mouse y movement
605 if (!novert)
607 forward += mousey;
610 if (strafe)
611 side += mousex*2;
612 else
613 cmd->angleturn -= mousex*0x8;
615 if (mousex == 0)
617 // No movement in the previous frame
619 testcontrols_mousespeed = 0;
622 mousex = mousey = 0;
624 if (forward > MAXPLMOVE)
625 forward = MAXPLMOVE;
626 else if (forward < -MAXPLMOVE)
627 forward = -MAXPLMOVE;
628 if (side > MAXPLMOVE)
629 side = MAXPLMOVE;
630 else if (side < -MAXPLMOVE)
631 side = -MAXPLMOVE;
633 cmd->forwardmove += forward;
634 cmd->sidemove += side;
636 // special buttons
637 if (sendpause)
639 sendpause = false;
640 cmd->buttons = BT_SPECIAL | BTS_PAUSE;
643 if (sendsave)
645 sendsave = false;
646 cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
649 // low-res turning
651 if (lowres_turn)
653 // round angleturn to the nearest 256 boundary
654 // for recording demos with single byte values for turn
656 cmd->angleturn = (cmd->angleturn + 128) & 0xff00;
662 // G_DoLoadLevel
664 extern gamestate_t wipegamestate;
666 void G_DoLoadLevel (void)
668 int i;
670 // Set the sky map.
671 // First thing, we have a dummy sky texture name,
672 // a flat. The data is in the WAD only because
673 // we look for an actual index, instead of simply
674 // setting one.
676 skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME));
678 levelstarttic = gametic; // for time calculation
680 if (wipegamestate == GS_LEVEL)
681 wipegamestate = -1; // force a wipe
683 gamestate = GS_LEVEL;
685 for (i=0 ; i<MAXPLAYERS ; i++)
687 turbodetected[i] = false;
688 if (playeringame[i] && players[i].playerstate == PST_DEAD)
689 players[i].playerstate = PST_REBORN;
690 memset (players[i].frags,0,sizeof(players[i].frags));
693 P_SetupLevel (gameepisode, gamemap, 0, gameskill);
694 displayplayer = consoleplayer; // view the guy you are playing
695 gameaction = ga_nothing;
696 Z_CheckHeap ();
698 // clear cmd building stuff
700 memset (gamekeydown, 0, sizeof(gamekeydown));
701 joyxmove = joyymove = 0;
702 mousex = mousey = 0;
703 sendpause = sendsave = paused = false;
704 memset (mousebuttons, 0, sizeof(mousebuttons));
705 memset (joybuttons, 0, sizeof(joybuttons));
707 if (testcontrols)
709 players[consoleplayer].message = "Press escape to quit.";
714 static void SetJoyButtons(unsigned int buttons_mask)
716 int i;
718 for (i=0; i<MAX_JOY_BUTTONS; ++i)
720 joybuttons[i] = (buttons_mask & (1 << i)) != 0;
725 // G_Responder
726 // Get info needed to make ticcmd_ts for the players.
728 boolean G_Responder (event_t* ev)
730 // allow spy mode changes even during the demo
731 if (gamestate == GS_LEVEL && ev->type == ev_keydown
732 && ev->data1 == KEY_F12 && (singledemo || !deathmatch) )
734 // spy mode
737 displayplayer++;
738 if (displayplayer == MAXPLAYERS)
739 displayplayer = 0;
740 } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
741 return true;
744 // any other key pops up menu if in demos
745 if (gameaction == ga_nothing && !singledemo &&
746 (demoplayback || gamestate == GS_DEMOSCREEN)
749 if (ev->type == ev_keydown ||
750 (ev->type == ev_mouse && ev->data1) ||
751 (ev->type == ev_joystick && ev->data1) )
753 M_StartControlPanel ();
754 return true;
756 return false;
759 if (gamestate == GS_LEVEL)
761 #if 0
762 if (devparm && ev->type == ev_keydown && ev->data1 == ';')
764 G_DeathMatchSpawnPlayer (0);
765 return true;
767 #endif
768 if (HU_Responder (ev))
769 return true; // chat ate the event
770 if (ST_Responder (ev))
771 return true; // status window ate it
772 if (AM_Responder (ev))
773 return true; // automap ate it
776 if (gamestate == GS_FINALE)
778 if (F_Responder (ev))
779 return true; // finale ate the event
782 if (testcontrols && ev->type == ev_mouse)
784 // If we are invoked by setup to test the controls, save the
785 // mouse speed so that we can display it on-screen.
786 // Perform a low pass filter on this so that the thermometer
787 // appears to move smoothly.
789 testcontrols_mousespeed = abs(ev->data2);
792 switch (ev->type)
794 case ev_keydown:
795 if (ev->data1 == key_pause)
797 sendpause = true;
799 else if (ev->data1 <NUMKEYS)
801 gamekeydown[ev->data1] = true;
804 return true; // eat key down events
806 case ev_keyup:
807 if (ev->data1 <NUMKEYS)
808 gamekeydown[ev->data1] = false;
809 return false; // always let key up events filter down
811 case ev_mouse:
812 mousebuttons[0] = ev->data1 & 1;
813 mousebuttons[1] = ev->data1 & 2;
814 mousebuttons[2] = ev->data1 & 4;
815 mousex = ev->data2*(mouseSensitivity+5)/10;
816 mousey = ev->data3*(mouseSensitivity+5)/10;
817 return true; // eat events
819 case ev_joystick:
820 SetJoyButtons(ev->data1);
821 joyxmove = ev->data2;
822 joyymove = ev->data3;
823 return true; // eat events
825 default:
826 break;
829 return false;
835 // G_Ticker
836 // Make ticcmd_ts for the players.
838 void G_Ticker (void)
840 int i;
841 int buf;
842 ticcmd_t* cmd;
844 // do player reborns if needed
845 for (i=0 ; i<MAXPLAYERS ; i++)
846 if (playeringame[i] && players[i].playerstate == PST_REBORN)
847 G_DoReborn (i);
849 // do things to change the game state
850 while (gameaction != ga_nothing)
852 switch (gameaction)
854 case ga_loadlevel:
855 G_DoLoadLevel ();
856 break;
857 case ga_newgame:
858 G_DoNewGame ();
859 break;
860 case ga_loadgame:
861 G_DoLoadGame ();
862 break;
863 case ga_savegame:
864 G_DoSaveGame ();
865 break;
866 case ga_playdemo:
867 G_DoPlayDemo ();
868 break;
869 case ga_completed:
870 G_DoCompleted ();
871 break;
872 case ga_victory:
873 F_StartFinale ();
874 break;
875 case ga_worlddone:
876 G_DoWorldDone ();
877 break;
878 case ga_screenshot:
879 V_ScreenShot ();
880 players[consoleplayer].message = DEH_String("screen shot");
881 gameaction = ga_nothing;
882 break;
883 case ga_nothing:
884 break;
888 // get commands, check consistancy,
889 // and build new consistancy check
890 buf = (gametic/ticdup)%BACKUPTICS;
892 for (i=0 ; i<MAXPLAYERS ; i++)
894 if (playeringame[i])
896 cmd = &players[i].cmd;
898 memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
900 if (demoplayback)
901 G_ReadDemoTiccmd (cmd);
902 if (demorecording)
903 G_WriteDemoTiccmd (cmd);
905 // check for turbo cheats
907 // check ~ 4 seconds whether to display the turbo message.
908 // store if the turbo threshold was exceeded in any tics
909 // over the past 4 seconds. offset the checking period
910 // for each player so messages are not displayed at the
911 // same time.
913 if (cmd->forwardmove > TURBOTHRESHOLD)
915 turbodetected[i] = true;
918 if ((gametic & 31) == 0
919 && ((gametic >> 5) % MAXPLAYERS) == i
920 && turbodetected[i])
922 static char turbomessage[80];
923 extern char *player_names[4];
924 sprintf (turbomessage, "%s is turbo!",player_names[i]);
925 players[consoleplayer].message = turbomessage;
926 turbodetected[i] = false;
929 if (netgame && !netdemo && !(gametic%ticdup) )
931 if (gametic > BACKUPTICS
932 && consistancy[i][buf] != cmd->consistancy)
934 I_Error ("consistency failure (%i should be %i)",
935 cmd->consistancy, consistancy[i][buf]);
937 if (players[i].mo)
938 consistancy[i][buf] = players[i].mo->x;
939 else
940 consistancy[i][buf] = rndindex;
945 // check for special buttons
946 for (i=0 ; i<MAXPLAYERS ; i++)
948 if (playeringame[i])
950 if (players[i].cmd.buttons & BT_SPECIAL)
952 switch (players[i].cmd.buttons & BT_SPECIALMASK)
954 case BTS_PAUSE:
955 paused ^= 1;
956 if (paused)
957 S_PauseSound ();
958 else
959 S_ResumeSound ();
960 break;
962 case BTS_SAVEGAME:
963 if (!savedescription[0])
964 strcpy (savedescription, "NET GAME");
965 savegameslot =
966 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
967 gameaction = ga_savegame;
968 break;
974 // Have we just finished displaying an intermission screen?
976 if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION)
978 WI_End();
981 oldgamestate = gamestate;
983 // do main actions
984 switch (gamestate)
986 case GS_LEVEL:
987 P_Ticker ();
988 ST_Ticker ();
989 AM_Ticker ();
990 HU_Ticker ();
991 break;
993 case GS_INTERMISSION:
994 WI_Ticker ();
995 break;
997 case GS_FINALE:
998 F_Ticker ();
999 break;
1001 case GS_DEMOSCREEN:
1002 D_PageTicker ();
1003 break;
1009 // PLAYER STRUCTURE FUNCTIONS
1010 // also see P_SpawnPlayer in P_Things
1014 // G_InitPlayer
1015 // Called at the start.
1016 // Called by the game initialization functions.
1018 void G_InitPlayer (int player)
1020 player_t* p;
1022 // set up the saved info
1023 p = &players[player];
1025 // clear everything else to defaults
1026 G_PlayerReborn (player);
1033 // G_PlayerFinishLevel
1034 // Can when a player completes a level.
1036 void G_PlayerFinishLevel (int player)
1038 player_t* p;
1040 p = &players[player];
1042 memset (p->powers, 0, sizeof (p->powers));
1043 memset (p->cards, 0, sizeof (p->cards));
1044 p->mo->flags &= ~MF_SHADOW; // cancel invisibility
1045 p->extralight = 0; // cancel gun flashes
1046 p->fixedcolormap = 0; // cancel ir gogles
1047 p->damagecount = 0; // no palette changes
1048 p->bonuscount = 0;
1053 // G_PlayerReborn
1054 // Called after a player dies
1055 // almost everything is cleared and initialized
1057 void G_PlayerReborn (int player)
1059 player_t* p;
1060 int i;
1061 int frags[MAXPLAYERS];
1062 int killcount;
1063 int itemcount;
1064 int secretcount;
1066 memcpy (frags,players[player].frags,sizeof(frags));
1067 killcount = players[player].killcount;
1068 itemcount = players[player].itemcount;
1069 secretcount = players[player].secretcount;
1071 p = &players[player];
1072 memset (p, 0, sizeof(*p));
1074 memcpy (players[player].frags, frags, sizeof(players[player].frags));
1075 players[player].killcount = killcount;
1076 players[player].itemcount = itemcount;
1077 players[player].secretcount = secretcount;
1079 p->usedown = p->attackdown = true; // don't do anything immediately
1080 p->playerstate = PST_LIVE;
1081 p->health = deh_initial_health; // Use dehacked value
1082 p->readyweapon = p->pendingweapon = wp_pistol;
1083 p->weaponowned[wp_fist] = true;
1084 p->weaponowned[wp_pistol] = true;
1085 p->ammo[am_clip] = deh_initial_bullets;
1087 for (i=0 ; i<NUMAMMO ; i++)
1088 p->maxammo[i] = maxammo[i];
1093 // G_CheckSpot
1094 // Returns false if the player cannot be respawned
1095 // at the given mapthing_t spot
1096 // because something is occupying it
1098 void P_SpawnPlayer (mapthing_t* mthing);
1100 boolean
1101 G_CheckSpot
1102 ( int playernum,
1103 mapthing_t* mthing )
1105 fixed_t x;
1106 fixed_t y;
1107 subsector_t* ss;
1108 unsigned an;
1109 mobj_t* mo;
1110 int i;
1112 if (!players[playernum].mo)
1114 // first spawn of level, before corpses
1115 for (i=0 ; i<playernum ; i++)
1116 if (players[i].mo->x == mthing->x << FRACBITS
1117 && players[i].mo->y == mthing->y << FRACBITS)
1118 return false;
1119 return true;
1122 x = mthing->x << FRACBITS;
1123 y = mthing->y << FRACBITS;
1125 if (!P_CheckPosition (players[playernum].mo, x, y) )
1126 return false;
1128 // flush an old corpse if needed
1129 if (bodyqueslot >= BODYQUESIZE)
1130 P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
1131 bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo;
1132 bodyqueslot++;
1134 // spawn a teleport fog
1135 ss = R_PointInSubsector (x,y);
1136 an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) >> ANGLETOFINESHIFT;
1138 mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
1139 , ss->sector->floorheight
1140 , MT_TFOG);
1142 if (players[consoleplayer].viewz != 1)
1143 S_StartSound (mo, sfx_telept); // don't start sound on first frame
1145 return true;
1150 // G_DeathMatchSpawnPlayer
1151 // Spawns a player at one of the random death match spots
1152 // called at level load and each death
1154 void G_DeathMatchSpawnPlayer (int playernum)
1156 int i,j;
1157 int selections;
1159 selections = deathmatch_p - deathmatchstarts;
1160 if (selections < 4)
1161 I_Error ("Only %i deathmatch spots, 4 required", selections);
1163 for (j=0 ; j<20 ; j++)
1165 i = P_Random() % selections;
1166 if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1168 deathmatchstarts[i].type = playernum+1;
1169 P_SpawnPlayer (&deathmatchstarts[i]);
1170 return;
1174 // no good spot, so the player will probably get stuck
1175 P_SpawnPlayer (&playerstarts[playernum]);
1179 // G_DoReborn
1181 void G_DoReborn (int playernum)
1183 int i;
1185 if (!netgame)
1187 // reload the level from scratch
1188 gameaction = ga_loadlevel;
1190 else
1192 // respawn at the start
1194 // first dissasociate the corpse
1195 players[playernum].mo->player = NULL;
1197 // spawn at random spot if in death match
1198 if (deathmatch)
1200 G_DeathMatchSpawnPlayer (playernum);
1201 return;
1204 if (G_CheckSpot (playernum, &playerstarts[playernum]) )
1206 P_SpawnPlayer (&playerstarts[playernum]);
1207 return;
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
1218 return;
1220 // he's going to be inside something. Too bad.
1222 P_SpawnPlayer (&playerstarts[playernum]);
1227 void G_ScreenShot (void)
1229 gameaction = ga_screenshot;
1234 // DOOM Par Times
1235 int pars[4][10] =
1237 {0},
1238 {0,30,75,120,90,165,180,180,30,165},
1239 {0,90,90,90,120,90,360,240,30,170},
1240 {0,90,45,90,150,90,90,165,30,135}
1243 // DOOM II Par Times
1244 int cpars[32] =
1246 30,90,120,120,90,150,120,120,270,90, // 1-10
1247 210,150,150,150,210,150,420,150,210,150, // 11-20
1248 240,150,180,150,150,300,330,420,300,180, // 21-30
1249 120,30 // 31-32
1254 // G_DoCompleted
1256 boolean secretexit;
1257 extern char* pagename;
1259 void G_ExitLevel (void)
1261 secretexit = false;
1262 gameaction = ga_completed;
1265 // Here's for the german edition.
1266 void G_SecretExitLevel (void)
1268 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1269 if ( (gamemode == commercial)
1270 && (W_CheckNumForName("map31")<0))
1271 secretexit = false;
1272 else
1273 secretexit = true;
1274 gameaction = ga_completed;
1277 void G_DoCompleted (void)
1279 int i;
1281 gameaction = ga_nothing;
1283 for (i=0 ; i<MAXPLAYERS ; i++)
1284 if (playeringame[i])
1285 G_PlayerFinishLevel (i); // take away cards and stuff
1287 if (automapactive)
1288 AM_Stop ();
1290 if (gamemode != commercial)
1292 // Chex Quest ends after 5 levels, rather than 8.
1294 if (gameversion == exe_chex)
1296 if (gamemap == 5)
1298 gameaction = ga_victory;
1299 return;
1302 else
1304 switch(gamemap)
1306 case 8:
1307 gameaction = ga_victory;
1308 return;
1309 case 9:
1310 for (i=0 ; i<MAXPLAYERS ; i++)
1311 players[i].didsecret = true;
1312 break;
1317 //#if 0 Hmmm - why?
1318 if ( (gamemap == 8)
1319 && (gamemode != commercial) )
1321 // victory
1322 gameaction = ga_victory;
1323 return;
1326 if ( (gamemap == 9)
1327 && (gamemode != commercial) )
1329 // exit secret level
1330 for (i=0 ; i<MAXPLAYERS ; i++)
1331 players[i].didsecret = true;
1333 //#endif
1336 wminfo.didsecret = players[consoleplayer].didsecret;
1337 wminfo.epsd = gameepisode -1;
1338 wminfo.last = gamemap -1;
1340 // wminfo.next is 0 biased, unlike gamemap
1341 if ( gamemode == commercial)
1343 if (secretexit)
1344 switch(gamemap)
1346 case 15: wminfo.next = 30; break;
1347 case 31: wminfo.next = 31; break;
1349 else
1350 switch(gamemap)
1352 case 31:
1353 case 32: wminfo.next = 15; break;
1354 default: wminfo.next = gamemap;
1357 else
1359 if (secretexit)
1360 wminfo.next = 8; // go to secret level
1361 else if (gamemap == 9)
1363 // returning from secret level
1364 switch (gameepisode)
1366 case 1:
1367 wminfo.next = 3;
1368 break;
1369 case 2:
1370 wminfo.next = 5;
1371 break;
1372 case 3:
1373 wminfo.next = 6;
1374 break;
1375 case 4:
1376 wminfo.next = 2;
1377 break;
1380 else
1381 wminfo.next = gamemap; // go to next level
1384 wminfo.maxkills = totalkills;
1385 wminfo.maxitems = totalitems;
1386 wminfo.maxsecret = totalsecret;
1387 wminfo.maxfrags = 0;
1388 if ( gamemode == commercial )
1389 wminfo.partime = TICRATE*cpars[gamemap-1];
1390 else
1391 wminfo.partime = TICRATE*pars[gameepisode][gamemap];
1392 wminfo.pnum = consoleplayer;
1394 for (i=0 ; i<MAXPLAYERS ; i++)
1396 wminfo.plyr[i].in = playeringame[i];
1397 wminfo.plyr[i].skills = players[i].killcount;
1398 wminfo.plyr[i].sitems = players[i].itemcount;
1399 wminfo.plyr[i].ssecret = players[i].secretcount;
1400 wminfo.plyr[i].stime = leveltime;
1401 memcpy (wminfo.plyr[i].frags, players[i].frags
1402 , sizeof(wminfo.plyr[i].frags));
1405 gamestate = GS_INTERMISSION;
1406 viewactive = false;
1407 automapactive = false;
1409 WI_Start (&wminfo);
1414 // G_WorldDone
1416 void G_WorldDone (void)
1418 gameaction = ga_worlddone;
1420 if (secretexit)
1421 players[consoleplayer].didsecret = true;
1423 if ( gamemode == commercial )
1425 switch (gamemap)
1427 case 15:
1428 case 31:
1429 if (!secretexit)
1430 break;
1431 case 6:
1432 case 11:
1433 case 20:
1434 case 30:
1435 F_StartFinale ();
1436 break;
1441 void G_DoWorldDone (void)
1443 gamestate = GS_LEVEL;
1444 gamemap = wminfo.next+1;
1445 G_DoLoadLevel ();
1446 gameaction = ga_nothing;
1447 viewactive = true;
1453 // G_InitFromSavegame
1454 // Can be called by the startup code or the menu task.
1456 extern boolean setsizeneeded;
1457 void R_ExecuteSetViewSize (void);
1459 char savename[256];
1461 void G_LoadGame (char* name)
1463 strcpy (savename, name);
1464 gameaction = ga_loadgame;
1467 #define VERSIONSIZE 16
1470 void G_DoLoadGame (void)
1472 int savedleveltime;
1474 gameaction = ga_nothing;
1476 save_stream = fopen(savename, "rb");
1478 if (save_stream == NULL)
1480 return;
1483 if (!P_ReadSaveGameHeader())
1485 fclose(save_stream);
1486 return;
1489 savedleveltime = leveltime;
1491 // load a base level
1492 G_InitNew (gameskill, gameepisode, gamemap);
1494 leveltime = savedleveltime;
1496 // dearchive all the modifications
1497 P_UnArchivePlayers ();
1498 P_UnArchiveWorld ();
1499 P_UnArchiveThinkers ();
1500 P_UnArchiveSpecials ();
1502 if (!P_ReadSaveGameEOF())
1503 I_Error ("Bad savegame");
1505 fclose(save_stream);
1507 if (setsizeneeded)
1508 R_ExecuteSetViewSize ();
1510 // draw the pattern into the back screen
1511 R_FillBackScreen ();
1516 // G_SaveGame
1517 // Called by the menu task.
1518 // Description is a 24 byte text string
1520 void
1521 G_SaveGame
1522 ( int slot,
1523 char* description )
1525 savegameslot = slot;
1526 strcpy (savedescription, description);
1527 sendsave = true;
1530 void G_DoSaveGame (void)
1532 char *savegame_file;
1533 char *temp_savegame_file;
1535 temp_savegame_file = P_TempSaveGameFile();
1536 savegame_file = P_SaveGameFile(savegameslot);
1538 // Open the savegame file for writing. We write to a temporary file
1539 // and then rename it at the end if it was successfully written.
1540 // This prevents an existing savegame from being overwritten by
1541 // a corrupted one, or if a savegame buffer overrun occurs.
1543 save_stream = fopen(temp_savegame_file, "wb");
1545 if (save_stream == NULL)
1547 return;
1550 P_WriteSaveGameHeader(savedescription);
1552 P_ArchivePlayers ();
1553 P_ArchiveWorld ();
1554 P_ArchiveThinkers ();
1555 P_ArchiveSpecials ();
1557 P_WriteSaveGameEOF();
1559 // Enforce the same savegame size limit as in Vanilla Doom,
1560 // except if the vanilla_savegame_limit setting is turned off.
1562 if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE)
1564 I_Error ("Savegame buffer overrun");
1567 // Finish up, close the savegame file.
1569 fclose(save_stream);
1571 // Now rename the temporary savegame file to the actual savegame
1572 // file, overwriting the old savegame if there was one there.
1574 remove(savegame_file);
1575 rename(temp_savegame_file, savegame_file);
1577 gameaction = ga_nothing;
1578 strcpy(savedescription, "");
1580 players[consoleplayer].message = DEH_String(GGSAVED);
1582 // draw the pattern into the back screen
1583 R_FillBackScreen ();
1588 // G_InitNew
1589 // Can be called by the startup code or the menu task,
1590 // consoleplayer, displayplayer, playeringame[] should be set.
1592 skill_t d_skill;
1593 int d_episode;
1594 int d_map;
1596 void
1597 G_DeferedInitNew
1598 ( skill_t skill,
1599 int episode,
1600 int map)
1602 d_skill = skill;
1603 d_episode = episode;
1604 d_map = map;
1605 gameaction = ga_newgame;
1609 void G_DoNewGame (void)
1611 demoplayback = false;
1612 netdemo = false;
1613 netgame = false;
1614 deathmatch = false;
1615 playeringame[1] = playeringame[2] = playeringame[3] = 0;
1616 respawnparm = false;
1617 fastparm = false;
1618 nomonsters = false;
1619 consoleplayer = 0;
1620 G_InitNew (d_skill, d_episode, d_map);
1621 gameaction = ga_nothing;
1624 // The sky texture to be used instead of the F_SKY1 dummy.
1625 extern int skytexture;
1628 void
1629 G_InitNew
1630 ( skill_t skill,
1631 int episode,
1632 int map )
1634 char *skytexturename;
1635 int i;
1637 if (paused)
1639 paused = false;
1640 S_ResumeSound ();
1644 if (skill > sk_nightmare)
1645 skill = sk_nightmare;
1648 // This was quite messy with SPECIAL and commented parts.
1649 // Supposedly hacks to make the latest edition work.
1650 // It might not work properly.
1651 if (episode < 1)
1652 episode = 1;
1654 if ( gamemode == retail )
1656 if (episode > 4)
1657 episode = 4;
1659 else if ( gamemode == shareware )
1661 if (episode > 1)
1662 episode = 1; // only start episode 1 on shareware
1664 else
1666 if (episode > 3)
1667 episode = 3;
1672 if (map < 1)
1673 map = 1;
1675 if ( (map > 9)
1676 && ( gamemode != commercial) )
1677 map = 9;
1679 M_ClearRandom ();
1681 if (skill == sk_nightmare || respawnparm )
1682 respawnmonsters = true;
1683 else
1684 respawnmonsters = false;
1686 if (fastparm || (skill == sk_nightmare && gameskill != sk_nightmare) )
1688 for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
1689 states[i].tics >>= 1;
1690 mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
1691 mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
1692 mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
1694 else if (skill != sk_nightmare && gameskill == sk_nightmare)
1696 for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
1697 states[i].tics <<= 1;
1698 mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
1699 mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
1700 mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
1704 // force players to be initialized upon first level load
1705 for (i=0 ; i<MAXPLAYERS ; i++)
1706 players[i].playerstate = PST_REBORN;
1708 usergame = true; // will be set false if a demo
1709 paused = false;
1710 demoplayback = false;
1711 automapactive = false;
1712 viewactive = true;
1713 gameepisode = episode;
1714 gamemap = map;
1715 gameskill = skill;
1717 viewactive = true;
1719 // Set the sky to use.
1721 // Note: This IS broken, but it is how Vanilla Doom behaves.
1722 // See http://doom.wikia.com/wiki/Sky_never_changes_in_Doom_II.
1724 // Because we set the sky here at the start of a game, not at the
1725 // start of a level, the sky texture never changes unless we
1726 // restore from a saved game. This was fixed before the Doom
1727 // source release, but this IS the way Vanilla DOS Doom behaves.
1729 if (gamemode == commercial)
1731 if (gamemap < 12)
1732 skytexturename = "SKY1";
1733 else if (gamemap < 21)
1734 skytexturename = "SKY2";
1735 else
1736 skytexturename = "SKY3";
1738 else
1740 switch (gameepisode)
1742 default:
1743 case 1:
1744 skytexturename = "SKY1";
1745 break;
1746 case 2:
1747 skytexturename = "SKY2";
1748 break;
1749 case 3:
1750 skytexturename = "SKY3";
1751 break;
1752 case 4: // Special Edition sky
1753 skytexturename = "SKY4";
1754 break;
1758 skytexturename = DEH_String(skytexturename);
1760 skytexture = R_TextureNumForName(skytexturename);
1763 G_DoLoadLevel ();
1768 // DEMO RECORDING
1770 #define DEMOMARKER 0x80
1773 void G_ReadDemoTiccmd (ticcmd_t* cmd)
1775 if (*demo_p == DEMOMARKER)
1777 // end of demo data stream
1778 G_CheckDemoStatus ();
1779 return;
1781 cmd->forwardmove = ((signed char)*demo_p++);
1782 cmd->sidemove = ((signed char)*demo_p++);
1784 // If this is a longtics demo, read back in higher resolution
1786 if (longtics)
1788 cmd->angleturn = *demo_p++;
1789 cmd->angleturn |= (*demo_p++) << 8;
1791 else
1793 cmd->angleturn = ((unsigned char) *demo_p++)<<8;
1796 cmd->buttons = (unsigned char)*demo_p++;
1799 // Increase the size of the demo buffer to allow unlimited demos
1801 static void IncreaseDemoBuffer(void)
1803 int current_length;
1804 byte *new_demobuffer;
1805 byte *new_demop;
1806 int new_length;
1808 // Find the current size
1810 current_length = demoend - demobuffer;
1812 // Generate a new buffer twice the size
1813 new_length = current_length * 2;
1815 new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0);
1816 new_demop = new_demobuffer + (demo_p - demobuffer);
1818 // Copy over the old data
1820 memcpy(new_demobuffer, demobuffer, current_length);
1822 // Free the old buffer and point the demo pointers at the new buffer.
1824 Z_Free(demobuffer);
1826 demobuffer = new_demobuffer;
1827 demo_p = new_demop;
1828 demoend = demobuffer + new_length;
1831 void G_WriteDemoTiccmd (ticcmd_t* cmd)
1833 byte *demo_start;
1835 if (gamekeydown['q']) // press q to end demo recording
1836 G_CheckDemoStatus ();
1838 demo_start = demo_p;
1840 *demo_p++ = cmd->forwardmove;
1841 *demo_p++ = cmd->sidemove;
1843 // If this is a longtics demo, record in higher resolution
1845 if (longtics)
1847 *demo_p++ = (cmd->angleturn & 0xff);
1848 *demo_p++ = (cmd->angleturn >> 8) & 0xff;
1850 else
1852 *demo_p++ = cmd->angleturn >> 8;
1855 *demo_p++ = cmd->buttons;
1857 // reset demo pointer back
1858 demo_p = demo_start;
1860 if (demo_p > demoend - 16)
1862 if (vanilla_demo_limit)
1864 // no more space
1865 G_CheckDemoStatus ();
1866 return;
1868 else
1870 // Vanilla demo limit disabled: unlimited
1871 // demo lengths!
1873 IncreaseDemoBuffer();
1877 G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
1883 // G_RecordDemo
1885 void G_RecordDemo (char* name)
1887 int i;
1888 int maxsize;
1890 usergame = false;
1891 strcpy (demoname, name);
1892 strcat (demoname, ".lmp");
1893 maxsize = 0x20000;
1896 // @arg <size>
1897 // @category demo
1898 // @vanilla
1900 // Specify the demo buffer size (KiB)
1903 i = M_CheckParm ("-maxdemo");
1904 if (i && i<myargc-1)
1905 maxsize = atoi(myargv[i+1])*1024;
1906 demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL);
1907 demoend = demobuffer + maxsize;
1909 demorecording = true;
1913 void G_BeginRecording (void)
1915 int i;
1918 // @category demo
1920 // Record a high resolution "Doom 1.91" demo.
1923 longtics = M_CheckParm("-longtics") != 0;
1925 // If not recording a longtics demo, record in low res
1927 lowres_turn = !longtics;
1929 demo_p = demobuffer;
1931 // Save the right version code for this demo
1933 if (longtics)
1935 *demo_p++ = DOOM_191_VERSION;
1937 else
1939 *demo_p++ = DOOM_VERSION;
1942 *demo_p++ = gameskill;
1943 *demo_p++ = gameepisode;
1944 *demo_p++ = gamemap;
1945 *demo_p++ = deathmatch;
1946 *demo_p++ = respawnparm;
1947 *demo_p++ = fastparm;
1948 *demo_p++ = nomonsters;
1949 *demo_p++ = consoleplayer;
1951 for (i=0 ; i<MAXPLAYERS ; i++)
1952 *demo_p++ = playeringame[i];
1957 // G_PlayDemo
1960 char* defdemoname;
1962 void G_DeferedPlayDemo (char* name)
1964 defdemoname = name;
1965 gameaction = ga_playdemo;
1968 // Generate a string describing a demo version
1970 static char *DemoVersionDescription(int version)
1972 static char resultbuf[16];
1974 switch (version)
1976 case 104:
1977 return "v1.4";
1978 case 105:
1979 return "v1.5";
1980 case 106:
1981 return "v1.6/v1.666";
1982 case 107:
1983 return "v1.7/v1.7a";
1984 case 108:
1985 return "v1.8";
1986 case 109:
1987 return "v1.9";
1988 default:
1989 break;
1992 // Unknown version. Perhaps this is a pre-v1.4 IWAD? If the version
1993 // byte is in the range 0-4 then it can be a v1.0-v1.2 demo.
1995 if (version >= 0 && version <= 4)
1997 return "v1.0/v1.1/v1.2";
1999 else
2001 sprintf(resultbuf, "%i.%i (unknown)", version / 100, version % 100);
2002 return resultbuf;
2006 void G_DoPlayDemo (void)
2008 skill_t skill;
2009 int i, episode, map;
2010 int demoversion;
2012 gameaction = ga_nothing;
2013 demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
2015 demoversion = *demo_p++;
2017 if (demoversion == DOOM_VERSION)
2019 longtics = false;
2021 else if (demoversion == DOOM_191_VERSION)
2023 // demo recorded with cph's modified "v1.91" doom exe
2024 longtics = true;
2026 else
2028 char *message = "Demo is from a different game version!\n"
2029 "(read %i, should be %i)\n"
2030 "\n"
2031 "*** You may need to upgrade your version "
2032 "of Doom to v1.9. ***\n"
2033 " See: http://doomworld.com/files/patches.shtml\n"
2034 " This appears to be %s.";
2036 I_Error(message, demoversion, DOOM_VERSION,
2037 DemoVersionDescription(demoversion));
2040 skill = *demo_p++;
2041 episode = *demo_p++;
2042 map = *demo_p++;
2043 deathmatch = *demo_p++;
2044 respawnparm = *demo_p++;
2045 fastparm = *demo_p++;
2046 nomonsters = *demo_p++;
2047 consoleplayer = *demo_p++;
2049 for (i=0 ; i<MAXPLAYERS ; i++)
2050 playeringame[i] = *demo_p++;
2053 // @category demo
2055 // Play back a demo recorded in a netgame with a single player.
2058 if (playeringame[1] || M_CheckParm("-netdemo") > 0)
2060 netgame = true;
2061 netdemo = true;
2064 // don't spend a lot of time in loadlevel
2065 precache = false;
2066 G_InitNew (skill, episode, map);
2067 precache = true;
2068 starttime = I_GetTime ();
2070 usergame = false;
2071 demoplayback = true;
2075 // G_TimeDemo
2077 void G_TimeDemo (char* name)
2080 // @vanilla
2082 // Disable rendering the screen entirely.
2085 nodrawers = M_CheckParm ("-nodraw");
2088 // @vanilla
2090 // Disable blitting the screen.
2093 noblit = M_CheckParm ("-noblit");
2094 timingdemo = true;
2095 singletics = true;
2097 defdemoname = name;
2098 gameaction = ga_playdemo;
2103 ===================
2105 = G_CheckDemoStatus
2107 = Called after a death or level completion to allow demos to be cleaned up
2108 = Returns true if a new demo loop action will take place
2109 ===================
2112 boolean G_CheckDemoStatus (void)
2114 int endtime;
2116 if (timingdemo)
2118 float fps;
2119 int realtics;
2121 endtime = I_GetTime ();
2122 realtics = endtime - starttime;
2123 fps = ((float) gametic * TICRATE) / realtics;
2125 // Prevent recursive calls
2126 timingdemo = false;
2127 demoplayback = false;
2129 I_Error ("timed %i gametics in %i realtics (%f fps)",
2130 gametic, realtics, fps);
2133 if (demoplayback)
2135 W_ReleaseLumpName(defdemoname);
2136 demoplayback = false;
2137 netdemo = false;
2138 netgame = false;
2139 deathmatch = false;
2140 playeringame[1] = playeringame[2] = playeringame[3] = 0;
2141 respawnparm = false;
2142 fastparm = false;
2143 nomonsters = false;
2144 consoleplayer = 0;
2146 if (singledemo)
2147 I_Quit ();
2148 else
2149 D_AdvanceDemo ();
2151 return true;
2154 if (demorecording)
2156 *demo_p++ = DEMOMARKER;
2157 M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
2158 Z_Free (demobuffer);
2159 demorecording = false;
2160 I_Error ("Demo %s recorded",demoname);
2163 return false;