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