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