]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/g_game.c
Initial revision
[theoddone33/hhexen.git] / base / g_game.c
1
2 //**************************************************************************
3 //**
4 //** g_game.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 #include <string.h>
14 #include "h2def.h"
15 #include "p_local.h"
16 #include "soundst.h"
17
18 #define AM_STARTKEY     9
19
20 // External functions
21
22 extern void R_InitSky(int map);
23 extern void P_PlayerNextArtifact(player_t *player);
24
25 // Functions
26
27 boolean G_CheckDemoStatus (void);
28 void G_ReadDemoTiccmd (ticcmd_t *cmd);
29 void G_WriteDemoTiccmd (ticcmd_t *cmd);
30 void G_InitNew (skill_t skill, int episode, int map);
31
32 void G_DoReborn (int playernum);
33
34 void G_DoLoadLevel(void);
35 void G_DoInitNew(void);
36 void G_DoNewGame(void);
37 void G_DoLoadGame(void);
38 void G_DoPlayDemo(void);
39 void G_DoTeleportNewMap(void);
40 void G_DoCompleted(void);
41 void G_DoVictory(void);
42 void G_DoWorldDone(void);
43 void G_DoSaveGame(void);
44 void G_DoSingleReborn(void);
45
46 void H2_PageTicker(void);
47 void H2_AdvanceDemo(void);
48
49 extern boolean mn_SuicideConsole;
50
51 gameaction_t    gameaction;
52 gamestate_t     gamestate;
53 skill_t         gameskill;
54 //boolean         respawnmonsters;
55 int             gameepisode;
56 int             gamemap;
57 int                              prevmap;
58
59 boolean         paused;
60 boolean         sendpause;              // send a pause event next tic
61 boolean         sendsave;               // send a save event next tic
62 boolean         usergame;               // ok to save / end game
63
64 boolean         timingdemo;             // if true, exit with report on completion
65 int             starttime;              // for comparative timing purposes      
66
67 boolean         viewactive;
68
69 boolean         deathmatch;             // only if started as net death
70 boolean         netgame;                // only true if packets are broadcast
71 boolean         playeringame[MAXPLAYERS];
72 player_t        players[MAXPLAYERS];
73 pclass_t                PlayerClass[MAXPLAYERS];
74
75 // Position indicator for cooperative net-play reborn
76 int RebornPosition;
77
78 int             consoleplayer;          // player taking events and displaying
79 int             displayplayer;          // view being displayed
80 int             gametic;
81 int             levelstarttic;          // gametic at level start
82
83 char            demoname[32];
84 boolean         demorecording;
85 boolean         demoplayback;
86 byte            *demobuffer, *demo_p;
87 boolean         singledemo;             // quit after playing a demo from cmdline
88
89 boolean         precache = true;        // if true, load all graphics at start
90
91 short            consistancy[MAXPLAYERS][BACKUPTICS];
92
93 //
94 // controls (have defaults)
95 //
96 int key_right, key_left, key_up, key_down;
97 int key_strafeleft, key_straferight, key_jump;
98 int key_fire, key_use, key_strafe, key_speed;
99 int     key_flyup, key_flydown, key_flycenter;
100 int     key_lookup, key_lookdown, key_lookcenter;
101 int     key_invleft, key_invright, key_useartifact;
102
103 int mouselook;
104 boolean alwaysrun;
105
106 int mousebfire;
107 int mousebstrafe;
108 int mousebforward;
109 int mousebjump;
110
111 int joybfire;
112 int joybstrafe;
113 int joybuse;
114 int joybspeed;
115 int joybjump;
116
117 int LeaveMap;
118 static int LeavePosition;
119
120 //#define MAXPLMOVE       0x32 // Old Heretic Max move
121
122 fixed_t MaxPlayerMove[NUMCLASSES] = { 0x3C, 0x32, 0x2D,
123                                         0x3D,
124                                         0x31 };
125 fixed_t forwardmove[NUMCLASSES][2] = 
126 {
127         { 0x1D, 0x3C },
128         { 0x19, 0x32 },
129         { 0x16, 0x2E },
130         { 0x17, 0x3D },
131         { 0x18, 0x31 }
132 };
133         
134 fixed_t sidemove[NUMCLASSES][2] = 
135 {
136         { 0x1B, 0x3B },
137         { 0x18, 0x28 },
138         { 0x15, 0x25 },
139         { 0x16, 0x3C },
140         { 0x17, 0x27 }
141 };
142
143 fixed_t angleturn[3] = {640, 1280, 320};     // + slow turn
144 #define SLOWTURNTICS    6
145
146 #define NUMKEYS 256
147 boolean         gamekeydown[NUMKEYS];
148 int             turnheld;                   // for accelerative turning
149 int                              lookheld;
150
151
152 boolean         mousearray[4];
153 boolean         *mousebuttons = &mousearray[1];
154
155         // allow [-1]
156 int             mousex, mousey;             // mouse values are used once
157 int             dclicktime, dclickstate, dclicks;
158 int             dclicktime2, dclickstate2, dclicks2;
159
160 int             joyxmove, joyymove;         // joystick values are repeated
161 boolean         joyarray[5];
162 boolean         *joybuttons = &joyarray[1];     // allow [-1]
163
164 int     savegameslot;
165 char    savedescription[32];
166
167 int inventoryTics;
168
169
170 static skill_t TempSkill;
171 static int TempEpisode;
172 static int TempMap;
173
174 //=============================================================================
175 /*
176 ====================
177 =
178 = G_BuildTiccmd
179 =
180 = Builds a ticcmd from all of the available inputs or reads it from the
181 = demo buffer.
182 = If recording a demo, write it out
183 ====================
184 */
185
186 extern boolean inventory;
187 extern int curpos;
188 extern int inv_ptr;
189
190 extern  int             isCyberPresent;     // is CyberMan present?
191 boolean usearti = true;
192 void I_ReadCyberCmd (ticcmd_t *cmd);
193
194 void G_BuildTiccmd (ticcmd_t *cmd)
195 {
196         int             i;
197         boolean         strafe, bstrafe;
198         int             speed, tspeed, lspeed;
199         int             forward, side;
200         int look, arti;
201         int flyheight;
202         int pClass;
203
204         extern boolean artiskip;
205
206
207         pClass = players[consoleplayer].class;
208         memset (cmd,0,sizeof(*cmd));
209
210 //      cmd->consistancy =
211 //              consistancy[consoleplayer][(maketic*ticdup)%BACKUPTICS];
212
213         cmd->consistancy =
214                 consistancy[consoleplayer][maketic%BACKUPTICS];
215         if (isCyberPresent)
216                 I_ReadCyberCmd (cmd);
217
218 //printf ("cons: %i\n",cmd->consistancy);
219         strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
220                 || joybuttons[joybstrafe];
221
222         speed = gamekeydown[key_speed] || joybuttons[joybspeed]
223                 || joybuttons[joybspeed];
224         if(alwaysrun && !demoplayback && !demorecording)
225         speed = !speed;
226         forward = side = look = arti = flyheight = 0;
227         
228 //
229 // use two stage accelerative turning on the keyboard and joystick
230 //
231         if (joyxmove < 0 || joyxmove > 0 
232         || gamekeydown[key_right] || gamekeydown[key_left])
233                 turnheld += ticdup;
234         else
235                 turnheld = 0;
236         if (turnheld < SLOWTURNTICS)
237                 tspeed = 2;             // slow turn
238         else
239                 tspeed = speed;
240
241         if(gamekeydown[key_lookdown] || gamekeydown[key_lookup])
242         {
243                 lookheld += ticdup;
244         }
245         else
246         {
247                 lookheld = 0;
248         }
249         if(lookheld < SLOWTURNTICS)
250         {
251                 lspeed = 1; // 3;
252         }
253         else
254         {
255                 lspeed = 2; // 5;
256         }
257
258 //
259 // let movement keys cancel each other out
260 //
261         if(strafe)
262         {
263                 if (gamekeydown[key_right])
264                 {
265                         side += sidemove[pClass][speed];
266                 }
267                 if (gamekeydown[key_left])
268                 {
269                         side -= sidemove[pClass][speed];
270                 }
271                 if (joyxmove > 0)
272                 {
273                         side += sidemove[pClass][speed];
274                 }
275                 if (joyxmove < 0)
276                 {
277                         side -= sidemove[pClass][speed];
278                 }
279         }
280         else
281         {
282                 if (gamekeydown[key_right])
283                         cmd->angleturn -= angleturn[tspeed];
284                 if (gamekeydown[key_left])
285                         cmd->angleturn += angleturn[tspeed];
286                 if (joyxmove > 0)
287                         cmd->angleturn -= angleturn[tspeed];
288                 if (joyxmove < 0)
289                         cmd->angleturn += angleturn[tspeed];
290         }
291
292         if (gamekeydown[key_up])
293         {
294                 forward += forwardmove[pClass][speed];
295         }
296         if (gamekeydown[key_down])
297         {
298                 forward -= forwardmove[pClass][speed];
299         }
300         if (joyymove < 0)
301         {
302                 forward += forwardmove[pClass][speed];
303         }
304         if (joyymove > 0)
305         {
306                 forward -= forwardmove[pClass][speed];
307         }
308         if (gamekeydown[key_straferight])
309         {
310                 side += sidemove[pClass][speed];
311         }
312         if (gamekeydown[key_strafeleft])
313         {
314                 side -= sidemove[pClass][speed];
315         }
316
317         // Look up/down/center keys
318         if(gamekeydown[key_lookup])
319         {
320                 look = lspeed;
321         }
322         if(gamekeydown[key_lookdown])
323         {
324                 look = -lspeed;
325         } 
326         if(gamekeydown[key_lookcenter])
327         {
328                 look = TOCENTER;
329         }
330
331         // Fly up/down/drop keys
332         if(gamekeydown[key_flyup])
333         {
334                 flyheight = 5; // note that the actual flyheight will be twice this
335         }
336         if(gamekeydown[key_flydown])
337         {
338                 flyheight = -5;
339         }
340         if(gamekeydown[key_flycenter])
341         {
342                 flyheight = TOCENTER; 
343                 look = TOCENTER; 
344         }
345         // Use artifact key
346         if(gamekeydown[key_useartifact])
347         {
348                 if(gamekeydown[key_speed] && artiskip)
349                 {
350                         if(players[consoleplayer].inventory[inv_ptr].type != arti_none)
351                         { // Skip an artifact
352                                 gamekeydown[key_useartifact] = false;
353                                 P_PlayerNextArtifact(&players[consoleplayer]);                  
354                         }
355                 }
356                 else
357                 {
358                         if(inventory)
359                         {
360                                 players[consoleplayer].readyArtifact =
361                                         players[consoleplayer].inventory[inv_ptr].type;
362                                 inventory = false;
363                                 cmd->arti = 0;
364                                 usearti = false;
365                         }
366                         else if(usearti)
367                         {
368                                 cmd->arti |= 
369                                         players[consoleplayer].inventory[inv_ptr].type&AFLAG_MASK;
370                                 usearti = false;
371                         }
372                 }
373         }
374         if(gamekeydown[key_jump] || mousebuttons[mousebjump]
375                 || joybuttons[joybjump])
376         {
377                 cmd->arti |= AFLAG_JUMP;
378         }
379         if(mn_SuicideConsole)
380         {
381                 cmd->arti |= AFLAG_SUICIDE;
382                 mn_SuicideConsole = false;
383         }
384
385         // Artifact hot keys
386         if(gamekeydown[KEY_BACKSPACE] && !cmd->arti)
387         {
388                 gamekeydown[KEY_BACKSPACE] = false;     // Use one of each artifact
389                 cmd->arti = NUMARTIFACTS;
390         }
391         else if(gamekeydown[KEY_BACKSLASH] && !cmd->arti 
392         && (players[consoleplayer].mo->health < MAXHEALTH))
393         {
394                 gamekeydown[KEY_BACKSLASH] = false;
395                 cmd->arti = arti_health;                                                
396         }
397         else if(gamekeydown[KEY_ZERO] && !cmd->arti)
398         {
399         gamekeydown[KEY_ZERO] = false;
400                 cmd->arti = arti_poisonbag;                                             
401         }
402         else if(gamekeydown[KEY_NINE] && !cmd->arti)
403         {
404                 gamekeydown[KEY_NINE] = false;
405                 cmd->arti = arti_blastradius;                                   
406         }
407         else if(gamekeydown[KEY_EIGHT] && !cmd->arti)
408         {
409                 gamekeydown[KEY_EIGHT] = false;
410                 cmd->arti = arti_teleport;                                              
411         }
412         else if(gamekeydown[KEY_SEVEN] && !cmd->arti)
413         {
414                 gamekeydown[KEY_SEVEN] = false;
415                 cmd->arti = arti_teleportother;                                         
416         }
417         else if(gamekeydown[KEY_SIX] && !cmd->arti)
418         {
419                 gamekeydown[KEY_SIX] = false;
420                 cmd->arti = arti_egg;                                           
421         }
422         else if(gamekeydown[KEY_FIVE] && !cmd->arti
423         && !players[consoleplayer].powers[pw_invulnerability])
424         {
425                 gamekeydown[KEY_FIVE] = false;
426                 cmd->arti = arti_invulnerability;                               
427         }
428
429 //
430 // buttons
431 //
432         cmd->chatchar = CT_dequeueChatChar();
433         if (gamekeydown[key_fire] || mousebuttons[mousebfire]
434                 || joybuttons[joybfire])
435                 cmd->buttons |= BT_ATTACK;
436
437         if (gamekeydown[key_use] || joybuttons[joybuse] )
438         {
439                 cmd->buttons |= BT_USE;
440                 dclicks = 0;                    // clear double clicks if hit use button
441         }
442         
443         for(i = 0; i < NUMWEAPONS; i++)
444         {
445                 if(gamekeydown['1'+i])
446                 {
447                         cmd->buttons |= BT_CHANGE;
448                         cmd->buttons |= i<<BT_WEAPONSHIFT;
449                         break;
450                 }
451         }
452
453 //
454 // mouse
455 //
456 #if 0
457     printf( "%d %d %d %d <%d %d>\n",
458             mousebuttons[mousebfire], mousebuttons[mousebforward],
459             mousebuttons[mousebjump], mousebuttons[mousebstrafe],
460             mousex, mousey );
461 #endif
462         if (mousebuttons[mousebforward])
463         {
464                 forward += forwardmove[pClass][speed];
465         }
466                 
467 //
468 // forward double click
469 //
470         if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
471         {
472                 dclickstate = mousebuttons[mousebforward];
473                 if (dclickstate)
474                         dclicks++;
475                 if (dclicks == 2)
476                 {
477                         cmd->buttons |= BT_USE;
478                         dclicks = 0;
479                 }
480                 else
481                         dclicktime = 0;
482         }
483         else
484         {
485                 dclicktime += ticdup;
486                 if (dclicktime > 20)
487                 {
488                         dclicks = 0;
489                         dclickstate = 0;
490                 }
491         }
492         
493 //
494 // strafe double click
495 //
496         bstrafe = mousebuttons[mousebstrafe]
497 || joybuttons[joybstrafe];
498         if (bstrafe != dclickstate2 && dclicktime2 > 1 )
499         {
500                 dclickstate2 = bstrafe;
501                 if (dclickstate2)
502                         dclicks2++;
503                 if (dclicks2 == 2)
504                 {
505                         cmd->buttons |= BT_USE;
506                         dclicks2 = 0;
507                 }
508                 else
509                         dclicktime2 = 0;
510         }
511         else
512         {
513                 dclicktime2 += ticdup;
514                 if (dclicktime2 > 20)
515                 {
516                         dclicks2 = 0;
517                         dclickstate2 = 0;
518                 }
519         }
520         if (strafe)
521         {
522                 side += mousex*2;
523         }
524         else
525         {
526                 cmd->angleturn -= mousex*0x8;
527         }       
528
529     if( demorecording || demoplayback || (mouselook == 0) )
530     {
531         forward += mousey;
532     }
533     else if( mousey )
534     {
535         // We'll directly change the viewing pitch of the console player.
536         float adj = ((mousey*0x4)<<16) / (float) ANGLE_180*180*110.0/85.0;
537         float newlookdir = 0; /* jim initialiser added to prevent warning */
538
539 #ifndef RENDER3D
540         adj *= 2;       //Speed up the X11 mlook a little.
541 #endif
542
543         if(mouselook == 1)
544                 newlookdir = players[consoleplayer].lookdir + adj;
545         else if(mouselook == 2)
546                 newlookdir = players[consoleplayer].lookdir - adj;
547
548         // vertical view angle taken from p_user.c line 249.
549         if( newlookdir > 90 )
550             newlookdir = 90;
551         if( newlookdir < -110 )
552             newlookdir = -110;
553
554         players[consoleplayer].lookdir = newlookdir;
555     }
556
557         mousex = mousey = 0;
558         
559         if (forward > MaxPlayerMove[pClass])
560         {
561                 forward = MaxPlayerMove[pClass];
562         }
563         else if (forward < -MaxPlayerMove[pClass])
564         {
565                 forward = -MaxPlayerMove[pClass];
566         }
567         if (side > MaxPlayerMove[pClass])
568         {
569                 side = MaxPlayerMove[pClass];
570         }
571         else if (side < -MaxPlayerMove[pClass])
572         {
573                 side = -MaxPlayerMove[pClass];
574         }
575         if(players[consoleplayer].powers[pw_speed]
576                 && !players[consoleplayer].morphTics)
577         { // Adjust for a player with a speed artifact
578                 forward = (3*forward)>>1;
579                 side = (3*side)>>1;
580         }
581         cmd->forwardmove += forward;
582         cmd->sidemove += side;
583         if(players[consoleplayer].playerstate == PST_LIVE)
584         {
585                 if(look < 0)
586                 {
587                         look += 16;
588                 }
589                 cmd->lookfly = look;
590         }
591         if(flyheight < 0)
592         {
593                 flyheight += 16;
594         }
595         cmd->lookfly |= flyheight<<4;
596
597 //
598 // special buttons
599 //
600         if (sendpause)
601         {
602                 sendpause = false;
603                 cmd->buttons = BT_SPECIAL | BTS_PAUSE;
604         }
605
606         if (sendsave)
607         {
608                 sendsave = false;
609                 cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
610         }
611 }
612
613
614 /*
615 ==============
616 =
617 = G_DoLoadLevel
618 =
619 ==============
620 */
621
622 void G_DoLoadLevel (void)
623 {
624         int             i;
625         
626         levelstarttic = gametic;        // for time calculation 
627         gamestate = GS_LEVEL;
628         for (i=0 ; i<MAXPLAYERS ; i++)
629         {
630                 if (playeringame[i] && players[i].playerstate == PST_DEAD)
631                         players[i].playerstate = PST_REBORN;
632                 memset (players[i].frags,0,sizeof(players[i].frags));
633         }
634
635         SN_StopAllSequences();  
636         P_SetupLevel (gameepisode, gamemap, 0, gameskill);   
637         displayplayer = consoleplayer;      // view the guy you are playing   
638         starttime = I_GetTime ();
639         gameaction = ga_nothing;
640         Z_CheckHeap ();
641
642 //
643 // clear cmd building stuff
644 // 
645
646         memset (gamekeydown, 0, sizeof(gamekeydown));
647         joyxmove = joyymove = 0;
648         mousex = mousey = 0;
649         sendpause = sendsave = paused = false;
650         memset (mousebuttons, 0, sizeof(mousebuttons));
651         memset (joybuttons, 0, sizeof(joybuttons));
652 }
653
654
655 /*
656 ===============================================================================
657 =
658 = G_Responder 
659 =
660 = get info needed to make ticcmd_ts for the players
661 =
662 ===============================================================================
663 */
664
665 boolean G_Responder(event_t *ev)
666 {
667         player_t *plr;
668         extern boolean MenuActive;
669
670         plr = &players[consoleplayer];
671         if(ev->type == ev_keyup && ev->data1 == key_useartifact)
672         { // flag to denote that it's okay to use an artifact
673                 if(!inventory)
674                 {
675                         plr->readyArtifact = plr->inventory[inv_ptr].type;
676                 }
677                 usearti = true;
678         }
679
680         // Check for spy mode player cycle
681         if(gamestate == GS_LEVEL && ev->type == ev_keydown
682                 && ev->data1 == KEY_F12 && !deathmatch)
683         { // Cycle the display player
684                 do
685                 {
686                         displayplayer++;
687                         if(displayplayer == MAXPLAYERS)
688                         {
689                                 displayplayer = 0;
690                         }
691                 } while(!playeringame[displayplayer]
692                         && displayplayer != consoleplayer);
693                 return(true);
694         }
695
696         if(CT_Responder(ev))
697         { // Chat ate the event
698                 return(true);
699         }
700         if(gamestate == GS_LEVEL)
701         {
702                 if(SB_Responder(ev))
703                 { // Status bar ate the event
704                         return(true);
705                 }
706                 if(AM_Responder(ev))
707                 { // Automap ate the event
708                         return(true);
709                 }
710         }
711
712         switch(ev->type)
713         {
714                 case ev_keydown:
715                         if(ev->data1 == key_invleft)
716                         {
717                                 inventoryTics = 5*35;
718                                 if(!inventory)
719                                 {
720                                         inventory = true;
721                                         break;
722                                 }
723                                 inv_ptr--;
724                                 if(inv_ptr < 0)
725                                 {
726                                         inv_ptr = 0;
727                                 }
728                                 else
729                                 {
730                                         curpos--;
731                                         if(curpos < 0)
732                                         {
733                                                 curpos = 0;
734                                         }
735                                 }
736                                 return(true);
737                         }
738                         if(ev->data1 == key_invright)
739                         {
740                                 inventoryTics = 5*35;
741                                 if(!inventory)
742                                 {
743                                         inventory = true;
744                                         break;
745                                 }
746                                 inv_ptr++;
747                                 if(inv_ptr >= plr->inventorySlotNum)
748                                 {
749                                         inv_ptr--;
750                                         if(inv_ptr < 0)
751                                                 inv_ptr = 0;
752                                 }
753                                 else
754                                 {
755                                         curpos++;
756                                         if(curpos > 6)
757                                         {
758                                                 curpos = 6;
759                                         }
760                                 }
761                                 return(true);
762                         }
763                         if(ev->data1 == KEY_PAUSE && !MenuActive)
764                         {
765                                 sendpause = true;
766                                 return(true);
767                         }
768                         if(ev->data1 < NUMKEYS)
769                         {
770                                 gamekeydown[ev->data1] = true;
771                         }
772                         return(true); // eat key down events
773
774                 case ev_keyup:
775                         if(ev->data1 < NUMKEYS)
776                         {
777                                 gamekeydown[ev->data1] = false;
778                         }
779                         return(false); // always let key up events filter down
780
781                 case ev_mouse:
782
783                         mousebuttons[0] = ev->data1&1;
784                         mousebuttons[1] = ev->data1&2;
785                         mousebuttons[2] = ev->data1&4;
786                         mousex = ev->data2*(mouseSensitivity+5)/10;
787                         mousey = ev->data3*(mouseSensitivity+5)/10;
788                         return(true); // eat events
789
790                 case ev_joystick:
791                         joybuttons[0] = ev->data1&1;
792                         joybuttons[1] = ev->data1&2;
793                         joybuttons[2] = ev->data1&4;
794                         joybuttons[3] = ev->data1&8;
795                         joyxmove = ev->data2;
796                         joyymove = ev->data3;
797                         return(true); // eat events
798
799                 default:
800                         break;
801         }
802         return(false);
803 }
804
805
806 //==========================================================================
807 //
808 // G_Ticker
809 //
810 //==========================================================================
811
812 void G_Ticker(void)
813 {
814         int i, buf;
815         ticcmd_t *cmd=NULL;
816
817 //
818 // do player reborns if needed
819 //
820         for (i=0 ; i<MAXPLAYERS ; i++)
821                 if (playeringame[i] && players[i].playerstate == PST_REBORN)
822                         G_DoReborn (i);
823
824 //
825 // do things to change the game state
826 //
827         while (gameaction != ga_nothing)
828         {
829                 switch (gameaction)
830                 {
831                         case ga_loadlevel:
832                                 G_DoLoadLevel();
833                                 break;
834                         case ga_initnew:
835                                 G_DoInitNew();
836                                 break;
837                         case ga_newgame:
838                                 G_DoNewGame();
839                                 break;
840                         case ga_loadgame:
841                                 Draw_LoadIcon();
842                                 G_DoLoadGame();
843                                 break;
844                         case ga_savegame:
845                                 Draw_SaveIcon();
846                                 G_DoSaveGame();
847                                 break;
848                         case ga_singlereborn:
849                                 G_DoSingleReborn();
850                                 break;
851                         case ga_playdemo:
852                                 G_DoPlayDemo();
853                                 break;
854                         case ga_screenshot:
855                                 M_ScreenShot();
856                                 gameaction = ga_nothing;
857                                 break;
858                         case ga_leavemap:
859                                 Draw_TeleportIcon();
860                                 G_DoTeleportNewMap();
861                                 break;
862                         case ga_completed:
863                                 G_DoCompleted();
864                                 break;
865                         case ga_worlddone:
866                                 G_DoWorldDone();
867                                 break;
868                         case ga_victory:
869                                 F_StartFinale();
870                                 break;
871                         default:
872                                 break;
873                 }
874         }
875         
876                         
877 //
878 // get commands, check consistancy, and build new consistancy check
879 //
880         //buf = gametic%BACKUPTICS;
881
882
883         buf = (gametic/ticdup)%BACKUPTICS;
884
885         for (i=0 ; i<MAXPLAYERS ; i++)
886                 if (playeringame[i])
887                 {
888                         cmd = &players[i].cmd;
889
890                         memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
891
892                         if (demoplayback)
893                                 G_ReadDemoTiccmd (cmd);
894                         if (demorecording)
895                                 G_WriteDemoTiccmd (cmd);
896
897                         if (netgame && !(gametic%ticdup) )
898                         {
899                                 if (gametic > BACKUPTICS
900                                 && consistancy[i][buf] != cmd->consistancy)
901                                 {
902                                         I_Error ("consistency failure (%i should be %i)",cmd->consistancy, consistancy[i][buf]);
903                                 }
904                                 if (players[i].mo)
905                                         consistancy[i][buf] = players[i].mo->x;
906                                 else
907                                         consistancy[i][buf] = rndindex;
908                         }
909                 }
910
911 //
912 // check for special buttons
913 //
914         for (i=0 ; i<MAXPLAYERS ; i++)
915                 if (playeringame[i])
916                 {
917                         if (players[i].cmd.buttons & BT_SPECIAL)
918                         {
919                                 switch (players[i].cmd.buttons & BT_SPECIALMASK)
920                                 {
921                                 case BTS_PAUSE:
922                                         paused ^= 1;
923                                         if(paused)
924                                         {
925                                                 S_PauseSound();
926                                         }
927                                         else
928                                         {
929                                                 S_ResumeSound();
930                                         }
931                                         break;
932                                         
933                                 case BTS_SAVEGAME:
934                                         if (!savedescription[0])
935                                         {
936                                                 if(netgame)
937                                                 {
938                                                         strcpy (savedescription, "NET GAME");
939                                                 }
940                                                 else
941                                                 {
942                                                         strcpy(savedescription, "SAVE GAME");
943                                                 }
944                                         }
945                                         savegameslot = 
946                                                 (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
947                                         gameaction = ga_savegame;
948                                         break;
949                                 }
950                         }
951                 }
952         
953 // turn inventory off after a certain amount of time
954         if(inventory && !(--inventoryTics))
955         {
956                 players[consoleplayer].readyArtifact =
957                         players[consoleplayer].inventory[inv_ptr].type;
958                 inventory = false;
959                 cmd->arti = 0;
960         }
961 //
962 // do main actions
963 //
964 //
965 // do main actions
966 //
967         switch (gamestate)
968         {
969                 case GS_LEVEL:
970                         P_Ticker ();
971                         SB_Ticker ();
972                         AM_Ticker ();
973                         CT_Ticker();
974                         break;
975                 case GS_INTERMISSION:
976                         IN_Ticker ();
977                         break;
978                 case GS_FINALE:
979                         F_Ticker();
980                         break;
981                 case GS_DEMOSCREEN:
982                         H2_PageTicker ();
983                         break;
984         }       
985 }
986
987
988 /*
989 ==============================================================================
990
991                                                 PLAYER STRUCTURE FUNCTIONS
992
993 also see P_SpawnPlayer in P_Things
994 ==============================================================================
995 */
996
997 //==========================================================================
998 //
999 // G_PlayerExitMap
1000 //
1001 // Called when the player leaves a map.
1002 //
1003 //==========================================================================
1004
1005 void G_PlayerExitMap(int playerNumber)
1006 {
1007         int i;
1008         player_t *player;
1009         int flightPower;
1010
1011         player = &players[playerNumber];
1012
1013 //      if(deathmatch)
1014 //      {
1015 //              // Strip all but one of each type of artifact
1016 //              for(i = 0; i < player->inventorySlotNum; i++)
1017 //              {
1018 //                      player->inventory[i].count = 1;
1019 //              }
1020 //              player->artifactCount = player->inventorySlotNum;
1021 //      }
1022 //      else
1023
1024         // Strip all current powers (retain flight)
1025         flightPower = player->powers[pw_flight];
1026         memset(player->powers, 0, sizeof(player->powers));
1027         player->powers[pw_flight] = flightPower;
1028
1029         if(deathmatch)
1030         {
1031                 player->powers[pw_flight] = 0;
1032         }
1033         else
1034         {
1035                 if(P_GetMapCluster(gamemap) != P_GetMapCluster(LeaveMap))
1036                 { // Entering new cluster
1037                         // Strip all keys
1038                         player->keys = 0;
1039
1040                         // Strip flight artifact
1041                         for(i = 0; i < 25; i++)
1042                         {
1043                                 player->powers[pw_flight] = 0;
1044                                 P_PlayerUseArtifact(player, arti_fly);
1045                         }
1046                         player->powers[pw_flight] = 0;
1047                 }
1048         }
1049
1050         if(player->morphTics)
1051         {
1052                 player->readyweapon = player->mo->special1; // Restore weapon
1053                 player->morphTics = 0;
1054         }
1055         player->messageTics = 0;
1056         player->lookdir = 0;
1057         player->mo->flags &= ~MF_SHADOW; // Remove invisibility
1058         player->extralight = 0; // Remove weapon flashes
1059         player->fixedcolormap = 0; // Remove torch
1060         player->damagecount = 0; // No palette changes
1061         player->bonuscount = 0;
1062         player->poisoncount = 0;
1063         if(player == &players[consoleplayer])
1064         {
1065                 SB_state = -1; // refresh the status bar
1066                 viewangleoffset = 0;
1067         }
1068 }
1069
1070 //==========================================================================
1071 //
1072 // G_PlayerReborn
1073 //
1074 // Called after a player dies.  Almost everything is cleared and
1075 // initialized.
1076 //
1077 //==========================================================================
1078
1079 void G_PlayerReborn(int player)
1080 {
1081         player_t *p;
1082         int frags[MAXPLAYERS];
1083         int killcount, itemcount, secretcount;
1084         uint worldTimer;
1085
1086         memcpy(frags, players[player].frags, sizeof(frags));
1087         killcount = players[player].killcount;
1088         itemcount = players[player].itemcount;
1089         secretcount = players[player].secretcount;
1090         worldTimer = players[player].worldTimer;
1091
1092         p = &players[player];
1093         memset(p, 0, sizeof(*p));
1094
1095         memcpy(players[player].frags, frags, sizeof(players[player].frags));
1096         players[player].killcount = killcount;
1097         players[player].itemcount = itemcount;
1098         players[player].secretcount = secretcount;
1099         players[player].worldTimer = worldTimer;
1100         players[player].class = PlayerClass[player];
1101
1102         p->usedown = p->attackdown = true; // don't do anything immediately
1103         p->playerstate = PST_LIVE;
1104         p->health = MAXHEALTH;
1105         p->readyweapon = p->pendingweapon = WP_FIRST;
1106         p->weaponowned[WP_FIRST] = true;
1107         p->messageTics = 0;
1108         p->lookdir = 0;
1109         localQuakeHappening[player] = false;
1110         if(p == &players[consoleplayer])
1111         {
1112                 SB_state = -1; // refresh the status bar
1113                 inv_ptr = 0; // reset the inventory pointer
1114                 curpos = 0;
1115                 viewangleoffset = 0;
1116         }
1117 }
1118
1119 /*
1120 ====================
1121 =
1122 = G_CheckSpot 
1123 =
1124 = Returns false if the player cannot be respawned at the given mapthing_t spot 
1125 = because something is occupying it
1126 ====================
1127 */
1128
1129 void P_SpawnPlayer (mapthing_t *mthing);
1130
1131 boolean G_CheckSpot (int playernum, mapthing_t *mthing)
1132 {
1133         fixed_t         x,y;
1134         subsector_t *ss;
1135         unsigned        an;
1136         mobj_t      *mo;
1137         
1138         x = mthing->x << FRACBITS;
1139         y = mthing->y << FRACBITS;
1140
1141         players[playernum].mo->flags2 &= ~MF2_PASSMOBJ;
1142         if (!P_CheckPosition (players[playernum].mo, x, y) )
1143         {
1144                 players[playernum].mo->flags2 |= MF2_PASSMOBJ;
1145                 return false;
1146         }
1147         players[playernum].mo->flags2 |= MF2_PASSMOBJ;
1148
1149 // spawn a teleport fog
1150         ss = R_PointInSubsector (x,y);
1151         an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT;
1152
1153         mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an],
1154                 ss->sector->floorheight+TELEFOGHEIGHT, MT_TFOG);
1155
1156         if (players[consoleplayer].viewz != 1)
1157                 S_StartSound (mo, SFX_TELEPORT);  // don't start sound on first frame
1158
1159         return true;
1160 }
1161
1162 /*
1163 ====================
1164 =
1165 = G_DeathMatchSpawnPlayer
1166 =
1167 = Spawns a player at one of the random death match spots
1168 = called at level load and each death
1169 ====================
1170 */
1171
1172 void G_DeathMatchSpawnPlayer (int playernum)
1173 {
1174         int             i,j;
1175         int             selections;
1176         
1177         selections = deathmatch_p - deathmatchstarts;
1178
1179         // This check has been moved to p_setup.c:P_LoadThings()
1180         //if (selections < 8)
1181         //      I_Error ("Only %i deathmatch spots, 8 required", selections);
1182
1183         for (j=0 ; j<20 ; j++)
1184         {
1185                 i = P_Random() % selections;
1186                 if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
1187                 {
1188                         deathmatchstarts[i].type = playernum+1;
1189                         P_SpawnPlayer (&deathmatchstarts[i]);
1190                         return;
1191                 }
1192         }
1193
1194 // no good spot, so the player will probably get stuck
1195         P_SpawnPlayer (&playerstarts[0][playernum]);
1196 }
1197
1198 //==========================================================================
1199 //
1200 // G_DoReborn
1201 //
1202 //==========================================================================
1203
1204 void G_DoReborn(int playernum)
1205 {
1206         int i;
1207         boolean oldWeaponowned[NUMWEAPONS];
1208         int oldKeys;
1209         int oldPieces;
1210         boolean foundSpot;
1211         int bestWeapon;
1212
1213         if(G_CheckDemoStatus())
1214         {
1215                 return;
1216         }
1217         if(!netgame)
1218         {
1219                 if(SV_RebornSlotAvailable())
1220                 { // Use the reborn code if the slot is available
1221                         gameaction = ga_singlereborn;
1222                 }
1223                 else
1224                 { // Start a new game if there's no reborn info
1225                         gameaction = ga_newgame;
1226                 }
1227         }
1228         else
1229         { // Net-game
1230                 players[playernum].mo->player = NULL; // Dissassociate the corpse
1231
1232                 if(deathmatch)
1233                 { // Spawn at random spot if in death match
1234                         G_DeathMatchSpawnPlayer(playernum);
1235                         return;
1236                 }
1237
1238                 // Cooperative net-play, retain keys and weapons
1239                 oldKeys = players[playernum].keys;
1240                 oldPieces = players[playernum].pieces;
1241                 for(i = 0; i < NUMWEAPONS; i++)
1242                 {
1243                         oldWeaponowned[i] = players[playernum].weaponowned[i];
1244                 }
1245
1246                 foundSpot = false;
1247                 if(G_CheckSpot(playernum,
1248                         &playerstarts[RebornPosition][playernum]))
1249                 { // Appropriate player start spot is open
1250                         P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
1251                         foundSpot = true;
1252                 }
1253                 else
1254                 {
1255                         // Try to spawn at one of the other player start spots
1256                         for(i = 0; i < MAXPLAYERS; i++)
1257                         {
1258                                 if(G_CheckSpot(playernum, &playerstarts[RebornPosition][i]))
1259                                 { // Found an open start spot
1260
1261                                         // Fake as other player
1262                                         playerstarts[RebornPosition][i].type = playernum+1;
1263                                         P_SpawnPlayer(&playerstarts[RebornPosition][i]);
1264
1265                                         // Restore proper player type
1266                                         playerstarts[RebornPosition][i].type = i+1;
1267         
1268                                         foundSpot = true;
1269                                         break;
1270                                 }
1271                         }
1272                 }
1273
1274                 if(foundSpot == false)
1275                 { // Player's going to be inside something
1276                         P_SpawnPlayer(&playerstarts[RebornPosition][playernum]);
1277                 }
1278
1279                 // Restore keys and weapons
1280                 players[playernum].keys = oldKeys;
1281                 players[playernum].pieces = oldPieces;
1282                 for(bestWeapon = 0, i = 0; i < NUMWEAPONS; i++)
1283                 {
1284                         if(oldWeaponowned[i])
1285                         {
1286                                 bestWeapon = i;
1287                                 players[playernum].weaponowned[i] = true;
1288                         }
1289                 }
1290                 players[playernum].mana[MANA_1] = 25;
1291                 players[playernum].mana[MANA_2] = 25;
1292                 if(bestWeapon)
1293                 { // Bring up the best weapon
1294                         players[playernum].pendingweapon = bestWeapon;
1295                 }
1296         }
1297 }
1298
1299 void G_ScreenShot (void)
1300 {
1301         gameaction = ga_screenshot;
1302 }
1303
1304 //==========================================================================
1305 //
1306 // G_StartNewInit
1307 //
1308 //==========================================================================
1309
1310 void G_StartNewInit(void)
1311 {
1312         SV_InitBaseSlot();
1313         SV_ClearRebornSlot();
1314         P_ACSInitNewGame();
1315         // Default the player start spot group to 0
1316         RebornPosition = 0;
1317 }
1318
1319 //==========================================================================
1320 //
1321 // G_StartNewGame
1322 //
1323 //==========================================================================
1324
1325 void G_StartNewGame(skill_t skill)
1326 {
1327         int realMap;
1328
1329         G_StartNewInit();
1330         realMap = P_TranslateMap(1);
1331         if(realMap == -1)
1332         {
1333                 realMap = 1;
1334         }
1335         G_InitNew(TempSkill, 1, realMap);
1336 }
1337
1338 //==========================================================================
1339 //
1340 // G_TeleportNewMap
1341 //
1342 // Only called by the warp cheat code.  Works just like normal map to map
1343 // teleporting, but doesn't do any interlude stuff.
1344 //
1345 //==========================================================================
1346
1347 void G_TeleportNewMap(int map, int position)
1348 {
1349         gameaction = ga_leavemap;
1350         LeaveMap = map;
1351         LeavePosition = position;
1352 }
1353
1354 //==========================================================================
1355 //
1356 // G_DoTeleportNewMap
1357 //
1358 //==========================================================================
1359
1360 void G_DoTeleportNewMap(void)
1361 {
1362         SV_MapTeleport(LeaveMap, LeavePosition);
1363         gamestate = GS_LEVEL;
1364         gameaction = ga_nothing;
1365         RebornPosition = LeavePosition;
1366 }
1367
1368 /*
1369 boolean secretexit;
1370 void G_ExitLevel (void)
1371 {
1372         secretexit = false;
1373         gameaction = ga_completed;
1374 }
1375 void G_SecretExitLevel (void)
1376 {
1377         secretexit = true;
1378         gameaction = ga_completed;
1379 }
1380 */
1381
1382 //==========================================================================
1383 //
1384 // G_Completed
1385 //
1386 // Starts intermission routine, which is used only during hub exits,
1387 // and DeathMatch games.
1388 //==========================================================================
1389
1390 void G_Completed(int map, int position)
1391 {
1392         gameaction = ga_completed;
1393         LeaveMap = map;
1394         LeavePosition = position;
1395 }
1396
1397 void G_DoCompleted(void)
1398 {
1399         int i;
1400
1401         gameaction = ga_nothing;
1402         if(G_CheckDemoStatus())
1403         {
1404                 return;
1405         }
1406         for(i = 0; i < MAXPLAYERS; i++)
1407         {
1408                 if(playeringame[i])
1409                 {
1410                         G_PlayerExitMap(i);
1411                 }
1412         }
1413         if(LeaveMap == -1 && LeavePosition == -1)
1414         {
1415                 gameaction = ga_victory;
1416                 return;
1417         }
1418         else
1419         {               
1420                 gamestate = GS_INTERMISSION;
1421                 IN_Start();
1422         }
1423
1424 /*
1425         int i;
1426         static int afterSecret[3] = { 7, 5, 5 };
1427
1428         gameaction = ga_nothing;
1429         if(G_CheckDemoStatus())
1430         {
1431                 return;
1432         }
1433         for(i = 0; i < MAXPLAYERS; i++)
1434         {
1435                 if(playeringame[i])
1436                 {
1437                         G_PlayerFinishLevel(i);
1438                 }
1439         }
1440         prevmap = gamemap;
1441         if(secretexit == true)
1442         {
1443                 gamemap = 9;
1444         }
1445         else if(gamemap == 9)
1446         { // Finished secret level
1447                 gamemap = afterSecret[gameepisode-1];
1448         }
1449         else if(gamemap == 8)
1450         {
1451                 gameaction = ga_victory;
1452                 return;
1453         }
1454         else
1455         {
1456                 gamemap++;
1457         }
1458         gamestate = GS_INTERMISSION;
1459         IN_Start();
1460 */
1461 }
1462
1463 //============================================================================
1464 //
1465 // G_WorldDone
1466 //
1467 //============================================================================
1468
1469 void G_WorldDone(void)
1470 {
1471         gameaction = ga_worlddone;
1472 }
1473
1474 //============================================================================
1475 //
1476 // G_DoWorldDone
1477 //
1478 //============================================================================
1479
1480 void G_DoWorldDone(void)
1481 {
1482         gamestate = GS_LEVEL;
1483         G_DoLoadLevel();
1484         gameaction = ga_nothing;
1485         viewactive = true;
1486 }
1487
1488 //==========================================================================
1489 //
1490 // G_DoSingleReborn
1491 //
1492 // Called by G_Ticker based on gameaction.  Loads a game from the reborn
1493 // save slot.
1494 //
1495 //==========================================================================
1496
1497 void G_DoSingleReborn(void)
1498 {
1499         gameaction = ga_nothing;
1500         SV_LoadGame(SV_GetRebornSlot());
1501         SB_SetClassData();
1502 }
1503
1504 //==========================================================================
1505 //
1506 // G_LoadGame
1507 //
1508 // Can be called by the startup code or the menu task.
1509 //
1510 //==========================================================================
1511
1512 static int GameLoadSlot;
1513
1514 void G_LoadGame(int slot)
1515 {
1516         GameLoadSlot = slot;
1517         gameaction = ga_loadgame;
1518 }
1519
1520 //==========================================================================
1521 //
1522 // G_DoLoadGame
1523 //
1524 // Called by G_Ticker based on gameaction.
1525 //
1526 //==========================================================================
1527
1528 void G_DoLoadGame(void)
1529 {
1530         gameaction = ga_nothing;
1531         SV_LoadGame(GameLoadSlot);
1532         if(!netgame)
1533         { // Copy the base slot to the reborn slot
1534                 SV_UpdateRebornSlot();
1535         }
1536         SB_SetClassData();
1537 }
1538
1539 //==========================================================================
1540 //
1541 // G_SaveGame
1542 //
1543 // Called by the menu task.  <description> is a 24 byte text string.
1544 //
1545 //==========================================================================
1546
1547 void G_SaveGame(int slot, char *description)
1548 {
1549         savegameslot = slot;
1550         strcpy(savedescription, description);
1551         sendsave = true;
1552 }
1553
1554 //==========================================================================
1555 //
1556 // G_DoSaveGame
1557 //
1558 // Called by G_Ticker based on gameaction.
1559 //
1560 //==========================================================================
1561
1562 void G_DoSaveGame(void)
1563 {
1564         SV_SaveGame(savegameslot, savedescription);
1565         gameaction = ga_nothing;
1566         savedescription[0] = 0;
1567         P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
1568 }
1569
1570 //==========================================================================
1571 //
1572 // G_DeferredNewGame
1573 //
1574 //==========================================================================
1575
1576 void G_DeferredNewGame(skill_t skill)
1577 {
1578         TempSkill = skill;
1579         gameaction = ga_newgame;
1580 }
1581
1582 //==========================================================================
1583 //
1584 // G_DoNewGame
1585 //
1586 //==========================================================================
1587
1588 void G_DoNewGame(void)
1589 {
1590         G_StartNewGame(TempSkill);
1591         gameaction = ga_nothing;
1592 }
1593
1594 /*
1595 ====================
1596 =
1597 = G_InitNew
1598 =
1599 = Can be called by the startup code or the menu task
1600 = consoleplayer, displayplayer, playeringame[] should be set
1601 ====================
1602 */
1603
1604 void G_DeferedInitNew(skill_t skill, int episode, int map)
1605 {
1606         TempSkill = skill;
1607         TempEpisode = episode;
1608         TempMap = map;
1609         gameaction = ga_initnew;
1610 }
1611
1612 void G_DoInitNew(void)
1613 {
1614         SV_InitBaseSlot();
1615         G_InitNew(TempSkill, TempEpisode, TempMap);
1616         gameaction = ga_nothing;
1617 }
1618
1619 void G_InitNew(skill_t skill, int episode, int map)
1620 {
1621         int i;
1622
1623         if(paused)
1624         {
1625                 paused = false;
1626                 S_ResumeSound();
1627         }
1628         if(skill < sk_baby)
1629         {
1630                 skill = sk_baby;
1631         }
1632         if(skill > sk_nightmare)
1633         {
1634                 skill = sk_nightmare;
1635         }
1636         if(map < 1)
1637         {
1638                 map = 1;
1639         }
1640         if(map > 99)
1641         {
1642                 map = 99;
1643         }
1644         M_ClearRandom();
1645         // Force players to be initialized upon first level load
1646         for(i = 0; i < MAXPLAYERS; i++)
1647         {
1648                 players[i].playerstate = PST_REBORN;
1649                 players[i].worldTimer = 0;
1650         }
1651
1652         // Set up a bunch of globals
1653         usergame = true; // will be set false if a demo
1654         paused = false;
1655         demorecording = false;
1656         demoplayback = false;
1657         viewactive = true;
1658         gameepisode = episode;
1659         gamemap = map;
1660         gameskill = skill;
1661         BorderNeedRefresh = true;
1662
1663         // Initialize the sky
1664         R_InitSky(map);
1665
1666         // Give one null ticcmd_t
1667         //gametic = 0;
1668         //maketic = 1;
1669         //for (i=0 ; i<MAXPLAYERS ; i++)
1670         //      nettics[i] = 1; // one null event for this gametic
1671         //memset (localcmds,0,sizeof(localcmds));
1672         //memset (netcmds,0,sizeof(netcmds));
1673
1674         G_DoLoadLevel();
1675 }
1676
1677 /*
1678 ===============================================================================
1679
1680                                                         DEMO RECORDING
1681
1682 ===============================================================================
1683 */
1684
1685 #define DEMOMARKER      0x80
1686
1687 void G_ReadDemoTiccmd (ticcmd_t *cmd)
1688 {
1689         if (*demo_p == DEMOMARKER)
1690         {       // end of demo data stream
1691                 G_CheckDemoStatus ();
1692                 return;
1693         }
1694         cmd->forwardmove = ((signed char)*demo_p++);
1695         cmd->sidemove = ((signed char)*demo_p++);
1696         cmd->angleturn = ((unsigned char)*demo_p++)<<8;
1697         cmd->buttons = (unsigned char)*demo_p++;
1698         cmd->lookfly = (unsigned char)*demo_p++;
1699         cmd->arti = (unsigned char)*demo_p++;
1700 }
1701
1702 void G_WriteDemoTiccmd (ticcmd_t *cmd)
1703 {
1704         if (gamekeydown['q'])           // press q to end demo recording
1705                 G_CheckDemoStatus ();
1706         *demo_p++ = cmd->forwardmove;
1707         *demo_p++ = cmd->sidemove;
1708         *demo_p++ = cmd->angleturn>>8;
1709         *demo_p++ = cmd->buttons;
1710         *demo_p++ = cmd->lookfly;
1711         *demo_p++ = cmd->arti;
1712         demo_p -= 6;
1713         G_ReadDemoTiccmd (cmd);         // make SURE it is exactly the same
1714 }
1715
1716
1717
1718 /*
1719 ===================
1720 =
1721 = G_RecordDemo
1722 =
1723 ===================
1724 */
1725
1726 void G_RecordDemo (skill_t skill, int numplayers, int episode, int map, char *name)
1727 {
1728         int             i;
1729         
1730         G_InitNew (skill, episode, map);
1731         usergame = false;
1732         strcpy (demoname, name);
1733         strcat (demoname, ".lmp");
1734         demobuffer = demo_p = Z_Malloc (0x20000,PU_STATIC,NULL);
1735         *demo_p++ = skill;
1736         *demo_p++ = episode;
1737         *demo_p++ = map;
1738         
1739         for (i=0 ; i<MAXPLAYERS ; i++)
1740         {
1741                 *demo_p++ = playeringame[i];
1742                 *demo_p++ = PlayerClass[i];
1743         }               
1744         demorecording = true;
1745 }
1746
1747
1748 /*
1749 ===================
1750 =
1751 = G_PlayDemo
1752 =
1753 ===================
1754 */
1755
1756 char    *defdemoname;
1757
1758 void G_DeferedPlayDemo (char *name)
1759 {
1760         defdemoname = name;
1761         gameaction = ga_playdemo;
1762 }
1763
1764 void G_DoPlayDemo (void)
1765 {
1766         skill_t skill;
1767         int             i, episode, map;
1768         
1769         gameaction = ga_nothing;
1770         demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
1771         skill = *demo_p++;
1772         episode = *demo_p++;
1773         map = *demo_p++;
1774
1775         for (i=0 ; i<MAXPLAYERS ; i++)
1776         {
1777                 playeringame[i] = *demo_p++;
1778                 PlayerClass[i] = *demo_p++;
1779         }
1780
1781         // Initialize world info, etc.
1782         G_StartNewInit();
1783
1784         precache = false;               // don't spend a lot of time in loadlevel
1785         G_InitNew (skill, episode, map);
1786         precache = true;
1787         usergame = false;
1788         demoplayback = true;
1789 }
1790
1791
1792 /*
1793 ===================
1794 =
1795 = G_TimeDemo
1796 =
1797 ===================
1798 */
1799
1800 void G_TimeDemo (char *name)
1801 {
1802         skill_t skill;
1803         int             episode, map;
1804         
1805         demobuffer = demo_p = W_CacheLumpName (name, PU_STATIC);
1806         skill = *demo_p++;
1807         episode = *demo_p++;
1808         map = *demo_p++;
1809         G_InitNew (skill, episode, map);
1810         usergame = false;
1811         demoplayback = true;
1812         timingdemo = true;
1813         singletics = true;
1814 }
1815
1816
1817 /*
1818 ===================
1819 =
1820 = G_CheckDemoStatus
1821 =
1822 = Called after a death or level completion to allow demos to be cleaned up
1823 = Returns true if a new demo loop action will take place
1824 ===================
1825 */
1826
1827 boolean G_CheckDemoStatus (void)
1828 {
1829         int             endtime;
1830         
1831         if (timingdemo)
1832         {
1833                 endtime = I_GetTime ();
1834                 I_Error ("timed %i gametics in %i realtics",gametic
1835                 , endtime-starttime);
1836         }
1837         
1838         if (demoplayback)
1839         {
1840                 if (singledemo)
1841                         I_Quit ();
1842                         
1843                 Z_ChangeTag (demobuffer, PU_CACHE);
1844                 demoplayback = false;
1845                 H2_AdvanceDemo();
1846                 return true;
1847         }
1848
1849         if (demorecording)
1850         {
1851                 *demo_p++ = DEMOMARKER;
1852                 M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
1853                 Z_Free (demobuffer);
1854                 demorecording = false;
1855                 I_Error ("Demo %s recorded",demoname);
1856         }
1857
1858         return false;
1859 }