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