|
|
1.1.1.4 root 1: // Emacs style mode select -*- C++ -*-
2: //-----------------------------------------------------------------------------
1.1.1.2 root 3: //
1.1.1.4 root 4: // $Id:$
1.1.1.2 root 5: //
1.1.1.4 root 6: // Copyright (C) 1993-1996 by id Software, Inc.
1.1.1.2 root 7: //
1.1.1.5 ! root 8: // This program is free software; you can redistribute it and/or
! 9: // modify it under the terms of the GNU General Public License
! 10: // as published by the Free Software Foundation; either version 2
! 11: // of the License, or (at your option) any later version.
1.1.1.2 root 12: //
1.1.1.5 ! root 13: // This program is distributed in the hope that it will be useful,
1.1.1.4 root 14: // but WITHOUT ANY WARRANTY; without even the implied warranty of
1.1.1.5 ! root 15: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 16: // GNU General Public License for more details.
1.1.1.2 root 17: //
1.1.1.4 root 18: // $Log:$
1.1.1.2 root 19: //
1.1.1.4 root 20: // DESCRIPTION: none
1.1.1.2 root 21: //
1.1.1.4 root 22: //-----------------------------------------------------------------------------
1.1.1.2 root 23:
24:
1.1.1.4 root 25: static const char
26: rcsid[] = "$Id: g_game.c,v 1.8 1997/02/03 22:45:09 b1 Exp $";
1.1.1.2 root 27:
1.1.1.4 root 28: #include <string.h>
29: #include <stdlib.h>
1.1 root 30:
1.1.1.4 root 31: #include "doomdef.h"
32: #include "doomstat.h"
1.1 root 33:
1.1.1.4 root 34: #include "z_zone.h"
35: #include "f_finale.h"
36: #include "m_argv.h"
37: #include "m_misc.h"
38: #include "m_menu.h"
39: #include "m_random.h"
40: #include "i_system.h"
41:
42: #include "p_setup.h"
43: #include "p_saveg.h"
44: #include "p_tick.h"
45:
46: #include "d_main.h"
47:
48: #include "wi_stuff.h"
49: #include "hu_stuff.h"
50: #include "st_stuff.h"
51: #include "am_map.h"
52:
53: // Needs access to LFB.
54: #include "v_video.h"
55:
56: #include "w_wad.h"
57:
58: #include "p_local.h"
59:
60: #include "s_sound.h"
61:
62: // Data.
63: #include "dstrings.h"
64: #include "sounds.h"
65:
66: // SKY handling - still the wrong place.
67: #include "r_data.h"
68: #include "r_sky.h"
69:
70:
71:
72: #include "g_game.h"
73:
74:
75: #define SAVEGAMESIZE 0x2c000
76: #define SAVESTRINGSIZE 24
77:
78:
79:
80: boolean G_CheckDemoStatus (void);
81: void G_ReadDemoTiccmd (ticcmd_t* cmd);
82: void G_WriteDemoTiccmd (ticcmd_t* cmd);
83: void G_PlayerReborn (int player);
84: void G_InitNew (skill_t skill, int episode, int map);
85:
86: void G_DoReborn (int playernum);
87:
88: void G_DoLoadLevel (void);
89: void G_DoNewGame (void);
90: void G_DoLoadGame (void);
91: void G_DoPlayDemo (void);
92: void G_DoCompleted (void);
93: void G_DoVictory (void);
94: void G_DoWorldDone (void);
95: void G_DoSaveGame (void);
96:
97:
98: gameaction_t gameaction;
99: gamestate_t gamestate;
100: skill_t gameskill;
101: boolean respawnmonsters;
102: int gameepisode;
103: int gamemap;
104:
105: boolean paused;
106: boolean sendpause; // send a pause event next tic
107: boolean sendsave; // send a save event next tic
108: boolean usergame; // ok to save / end game
109:
110: boolean timingdemo; // if true, exit with report on completion
111: boolean nodrawers; // for comparative timing purposes
112: boolean noblit; // for comparative timing purposes
113: int starttime; // for comparative timing purposes
114:
115: boolean viewactive;
116:
117: boolean deathmatch; // only if started as net death
118: boolean netgame; // only true if packets are broadcast
119: boolean playeringame[MAXPLAYERS];
120: player_t players[MAXPLAYERS];
121:
122: int consoleplayer; // player taking events and displaying
123: int displayplayer; // view being displayed
124: int gametic;
125: int levelstarttic; // gametic at level start
126: int totalkills, totalitems, totalsecret; // for intermission
127:
128: char demoname[32];
129: boolean demorecording;
130: boolean demoplayback;
131: boolean netdemo;
132: byte* demobuffer;
133: byte* demo_p;
134: byte* demoend;
135: boolean singledemo; // quit after playing a demo from cmdline
136:
137: boolean precache = true; // if true, load all graphics at start
138:
139: wbstartstruct_t wminfo; // parms for world map / intermission
140:
141: short consistancy[MAXPLAYERS][BACKUPTICS];
142:
143: byte* savebuffer;
144:
145:
146: //
147: // controls (have defaults)
148: //
149: int key_right;
150: int key_left;
1.1 root 151:
1.1.1.4 root 152: int key_up;
153: int key_down;
154: int key_strafeleft;
155: int key_straferight;
156: int key_fire;
157: int key_use;
158: int key_strafe;
159: int key_speed;
160:
161: int mousebfire;
162: int mousebstrafe;
163: int mousebforward;
164:
165: int joybfire;
166: int joybstrafe;
167: int joybuse;
168: int joybspeed;
169:
170:
171:
172: #define MAXPLMOVE (forwardmove[1])
173:
174: #define TURBOTHRESHOLD 0x32
175:
176: fixed_t forwardmove[2] = {0x19, 0x32};
177: fixed_t sidemove[2] = {0x18, 0x28};
178: fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
179:
180: #define SLOWTURNTICS 6
181:
182: #define NUMKEYS 256
183:
184: boolean gamekeydown[NUMKEYS];
185: int turnheld; // for accelerative turning
186:
187: boolean mousearray[4];
188: boolean* mousebuttons = &mousearray[1]; // allow [-1]
189:
190: // mouse values are used once
191: int mousex;
192: int mousey;
193:
194: int dclicktime;
195: int dclickstate;
196: int dclicks;
197: int dclicktime2;
198: int dclickstate2;
199: int dclicks2;
200:
201: // joystick values are repeated
202: int joyxmove;
203: int joyymove;
204: boolean joyarray[5];
205: boolean* joybuttons = &joyarray[1]; // allow [-1]
206:
207: int savegameslot;
208: char savedescription[32];
209:
210:
211: #define BODYQUESIZE 32
212:
213: mobj_t* bodyque[BODYQUESIZE];
214: int bodyqueslot;
215:
216: void* statcopy; // for statistics driver
217:
218:
219:
220: int G_CmdChecksum (ticcmd_t* cmd)
221: {
222: int i;
223: int sum = 0;
224:
225: for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++)
226: sum += ((int *)cmd)[i];
227:
228: return sum;
229: }
230:
231:
232: //
233: // G_BuildTiccmd
234: // Builds a ticcmd from all of the available inputs
235: // or reads it from the demo buffer.
236: // If recording a demo, write it out
237: //
238: void G_BuildTiccmd (ticcmd_t* cmd)
239: {
240: int i;
241: boolean strafe;
242: boolean bstrafe;
243: int speed;
244: int tspeed;
245: int forward;
246: int side;
247:
248: ticcmd_t* base;
1.1.1.2 root 249:
1.1.1.4 root 250: base = I_BaseTiccmd (); // empty, or external driver
251: memcpy (cmd,base,sizeof(*cmd));
1.1.1.3 root 252:
1.1.1.4 root 253: cmd->consistancy =
254: consistancy[consoleplayer][maketic%BACKUPTICS];
1.1.1.2 root 255:
1.1.1.4 root 256:
257: strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
258: || joybuttons[joybstrafe];
259: speed = gamekeydown[key_speed] || joybuttons[joybspeed];
260:
261: forward = side = 0;
262:
263: // use two stage accelerative turning
264: // on the keyboard and joystick
265: if (joyxmove < 0
266: || joyxmove > 0
267: || gamekeydown[key_right]
268: || gamekeydown[key_left])
269: turnheld += ticdup;
270: else
271: turnheld = 0;
272:
273: if (turnheld < SLOWTURNTICS)
274: tspeed = 2; // slow turn
275: else
276: tspeed = speed;
277:
278: // let movement keys cancel each other out
279: if (strafe)
280: {
281: if (gamekeydown[key_right])
282: {
283: // fprintf(stderr, "strafe right\n");
284: side += sidemove[speed];
285: }
286: if (gamekeydown[key_left])
287: {
288: // fprintf(stderr, "strafe left\n");
289: side -= sidemove[speed];
290: }
291: if (joyxmove > 0)
292: side += sidemove[speed];
293: if (joyxmove < 0)
294: side -= sidemove[speed];
295:
296: }
297: else
298: {
299: if (gamekeydown[key_right])
300: cmd->angleturn -= angleturn[tspeed];
301: if (gamekeydown[key_left])
302: cmd->angleturn += angleturn[tspeed];
303: if (joyxmove > 0)
304: cmd->angleturn -= angleturn[tspeed];
305: if (joyxmove < 0)
306: cmd->angleturn += angleturn[tspeed];
307: }
308:
309: if (gamekeydown[key_up])
310: {
311: // fprintf(stderr, "up\n");
312: forward += forwardmove[speed];
313: }
314: if (gamekeydown[key_down])
315: {
316: // fprintf(stderr, "down\n");
317: forward -= forwardmove[speed];
318: }
319: if (joyymove < 0)
320: forward += forwardmove[speed];
321: if (joyymove > 0)
322: forward -= forwardmove[speed];
323: if (gamekeydown[key_straferight])
324: side += sidemove[speed];
325: if (gamekeydown[key_strafeleft])
326: side -= sidemove[speed];
327:
328: // buttons
329: cmd->chatchar = HU_dequeueChatChar();
330:
331: if (gamekeydown[key_fire] || mousebuttons[mousebfire]
332: || joybuttons[joybfire])
333: cmd->buttons |= BT_ATTACK;
334:
335: if (gamekeydown[key_use] || joybuttons[joybuse] )
336: {
337: cmd->buttons |= BT_USE;
338: // clear double clicks if hit use button
339: dclicks = 0;
340: }
341:
342: // chainsaw overrides
343: for (i=0 ; i<NUMWEAPONS-1 ; i++)
344: if (gamekeydown['1'+i])
345: {
346: cmd->buttons |= BT_CHANGE;
347: cmd->buttons |= i<<BT_WEAPONSHIFT;
348: break;
349: }
350:
351: // mouse
352: if (mousebuttons[mousebforward])
353: forward += forwardmove[speed];
354:
355: // forward double click
356: if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 )
357: {
358: dclickstate = mousebuttons[mousebforward];
359: if (dclickstate)
360: dclicks++;
361: if (dclicks == 2)
362: {
363: cmd->buttons |= BT_USE;
364: dclicks = 0;
365: }
366: else
367: dclicktime = 0;
368: }
369: else
370: {
371: dclicktime += ticdup;
372: if (dclicktime > 20)
373: {
374: dclicks = 0;
375: dclickstate = 0;
376: }
377: }
378:
379: // strafe double click
380: bstrafe =
381: mousebuttons[mousebstrafe]
382: || joybuttons[joybstrafe];
383: if (bstrafe != dclickstate2 && dclicktime2 > 1 )
384: {
385: dclickstate2 = bstrafe;
386: if (dclickstate2)
387: dclicks2++;
388: if (dclicks2 == 2)
389: {
390: cmd->buttons |= BT_USE;
391: dclicks2 = 0;
392: }
393: else
394: dclicktime2 = 0;
395: }
396: else
397: {
398: dclicktime2 += ticdup;
399: if (dclicktime2 > 20)
400: {
401: dclicks2 = 0;
402: dclickstate2 = 0;
403: }
404: }
405:
406: forward += mousey;
407: if (strafe)
408: side += mousex*2;
409: else
410: cmd->angleturn -= mousex*0x8;
411:
412: mousex = mousey = 0;
413:
414: if (forward > MAXPLMOVE)
415: forward = MAXPLMOVE;
416: else if (forward < -MAXPLMOVE)
417: forward = -MAXPLMOVE;
418: if (side > MAXPLMOVE)
419: side = MAXPLMOVE;
420: else if (side < -MAXPLMOVE)
421: side = -MAXPLMOVE;
422:
423: cmd->forwardmove += forward;
424: cmd->sidemove += side;
425:
426: // special buttons
427: if (sendpause)
428: {
429: sendpause = false;
430: cmd->buttons = BT_SPECIAL | BTS_PAUSE;
431: }
432:
433: if (sendsave)
434: {
435: sendsave = false;
436: cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
437: }
438: }
439:
440:
441: //
442: // G_DoLoadLevel
443: //
444: extern gamestate_t wipegamestate;
445:
446: void G_DoLoadLevel (void)
447: {
448: int i;
449:
450: // Set the sky map.
451: // First thing, we have a dummy sky texture name,
452: // a flat. The data is in the WAD only because
453: // we look for an actual index, instead of simply
454: // setting one.
455: skyflatnum = R_FlatNumForName ( SKYFLATNAME );
456:
457: // DOOM determines the sky texture to be used
458: // depending on the current episode, and the game version.
459: if ( (gamemode == commercial)
460: || ( gamemode == pack_tnt )
461: || ( gamemode == pack_plut ) )
462: {
463: skytexture = R_TextureNumForName ("SKY3");
464: if (gamemap < 12)
465: skytexture = R_TextureNumForName ("SKY1");
466: else
467: if (gamemap < 21)
468: skytexture = R_TextureNumForName ("SKY2");
469: }
470:
471: levelstarttic = gametic; // for time calculation
472:
473: if (wipegamestate == GS_LEVEL)
474: wipegamestate = -1; // force a wipe
475:
476: gamestate = GS_LEVEL;
477:
478: for (i=0 ; i<MAXPLAYERS ; i++)
479: {
480: if (playeringame[i] && players[i].playerstate == PST_DEAD)
481: players[i].playerstate = PST_REBORN;
482: memset (players[i].frags,0,sizeof(players[i].frags));
483: }
484:
485: P_SetupLevel (gameepisode, gamemap, 0, gameskill);
486: displayplayer = consoleplayer; // view the guy you are playing
487: starttime = I_GetTime ();
488: gameaction = ga_nothing;
489: Z_CheckHeap ();
490:
491: // clear cmd building stuff
492: memset (gamekeydown, 0, sizeof(gamekeydown));
493: joyxmove = joyymove = 0;
494: mousex = mousey = 0;
495: sendpause = sendsave = paused = false;
496: memset (mousebuttons, 0, sizeof(mousebuttons));
497: memset (joybuttons, 0, sizeof(joybuttons));
498: }
499:
500:
1.1.1.2 root 501: //
1.1.1.4 root 502: // G_Responder
503: // Get info needed to make ticcmd_ts for the players.
1.1.1.3 root 504: //
1.1.1.4 root 505: boolean G_Responder (event_t* ev)
506: {
507: // allow spy mode changes even during the demo
508: if (gamestate == GS_LEVEL && ev->type == ev_keydown
509: && ev->data1 == KEY_F12 && (singledemo || !deathmatch) )
510: {
511: // spy mode
512: do
513: {
514: displayplayer++;
515: if (displayplayer == MAXPLAYERS)
516: displayplayer = 0;
517: } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
518: return true;
519: }
520:
521: // any other key pops up menu if in demos
522: if (gameaction == ga_nothing && !singledemo &&
523: (demoplayback || gamestate == GS_DEMOSCREEN)
524: )
525: {
526: if (ev->type == ev_keydown ||
527: (ev->type == ev_mouse && ev->data1) ||
528: (ev->type == ev_joystick && ev->data1) )
529: {
530: M_StartControlPanel ();
531: return true;
532: }
533: return false;
534: }
535:
536: if (gamestate == GS_LEVEL)
537: {
538: #if 0
539: if (devparm && ev->type == ev_keydown && ev->data1 == ';')
540: {
541: G_DeathMatchSpawnPlayer (0);
542: return true;
543: }
544: #endif
545: if (HU_Responder (ev))
546: return true; // chat ate the event
547: if (ST_Responder (ev))
548: return true; // status window ate it
549: if (AM_Responder (ev))
550: return true; // automap ate it
551: }
552:
553: if (gamestate == GS_FINALE)
554: {
555: if (F_Responder (ev))
556: return true; // finale ate the event
557: }
558:
559: switch (ev->type)
560: {
561: case ev_keydown:
562: if (ev->data1 == KEY_PAUSE)
563: {
564: sendpause = true;
565: return true;
566: }
567: if (ev->data1 <NUMKEYS)
568: gamekeydown[ev->data1] = true;
569: return true; // eat key down events
570:
571: case ev_keyup:
572: if (ev->data1 <NUMKEYS)
573: gamekeydown[ev->data1] = false;
574: return false; // always let key up events filter down
575:
576: case ev_mouse:
577: mousebuttons[0] = ev->data1 & 1;
578: mousebuttons[1] = ev->data1 & 2;
579: mousebuttons[2] = ev->data1 & 4;
580: mousex = ev->data2*(mouseSensitivity+5)/10;
581: mousey = ev->data3*(mouseSensitivity+5)/10;
582: return true; // eat events
583:
584: case ev_joystick:
585: joybuttons[0] = ev->data1 & 1;
586: joybuttons[1] = ev->data1 & 2;
587: joybuttons[2] = ev->data1 & 4;
588: joybuttons[3] = ev->data1 & 8;
589: joyxmove = ev->data2;
590: joyymove = ev->data3;
591: return true; // eat events
592:
593: default:
594: break;
595: }
596:
597: return false;
598: }
599:
600:
601:
1.1.1.3 root 602: //
603: // G_Ticker
1.1.1.4 root 604: // Make ticcmd_ts for the players.
1.1.1.3 root 605: //
1.1.1.4 root 606: void G_Ticker (void)
607: {
608: int i;
609: int buf;
610: ticcmd_t* cmd;
611:
612: // do player reborns if needed
613: for (i=0 ; i<MAXPLAYERS ; i++)
614: if (playeringame[i] && players[i].playerstate == PST_REBORN)
615: G_DoReborn (i);
616:
617: // do things to change the game state
618: while (gameaction != ga_nothing)
619: {
620: switch (gameaction)
621: {
622: case ga_loadlevel:
623: G_DoLoadLevel ();
624: break;
625: case ga_newgame:
626: G_DoNewGame ();
627: break;
628: case ga_loadgame:
629: G_DoLoadGame ();
630: break;
631: case ga_savegame:
632: G_DoSaveGame ();
633: break;
634: case ga_playdemo:
635: G_DoPlayDemo ();
636: break;
637: case ga_completed:
638: G_DoCompleted ();
639: break;
640: case ga_victory:
641: F_StartFinale ();
642: break;
643: case ga_worlddone:
644: G_DoWorldDone ();
645: break;
646: case ga_screenshot:
647: M_ScreenShot ();
648: gameaction = ga_nothing;
649: break;
650: case ga_nothing:
651: break;
652: }
653: }
654:
655: // get commands, check consistancy,
656: // and build new consistancy check
657: buf = (gametic/ticdup)%BACKUPTICS;
658:
659: for (i=0 ; i<MAXPLAYERS ; i++)
660: {
661: if (playeringame[i])
662: {
663: cmd = &players[i].cmd;
664:
665: memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
666:
667: if (demoplayback)
668: G_ReadDemoTiccmd (cmd);
669: if (demorecording)
670: G_WriteDemoTiccmd (cmd);
671:
672: // check for turbo cheats
673: if (cmd->forwardmove > TURBOTHRESHOLD
674: && !(gametic&31) && ((gametic>>5)&3) == i )
675: {
676: static char turbomessage[80];
677: extern char *player_names[4];
678: sprintf (turbomessage, "%s is turbo!",player_names[i]);
679: players[consoleplayer].message = turbomessage;
680: }
1.1.1.3 root 681:
1.1.1.4 root 682: if (netgame && !netdemo && !(gametic%ticdup) )
683: {
684: if (gametic > BACKUPTICS
685: && consistancy[i][buf] != cmd->consistancy)
686: {
687: I_Error ("consistency failure (%i should be %i)",
688: cmd->consistancy, consistancy[i][buf]);
689: }
690: if (players[i].mo)
691: consistancy[i][buf] = players[i].mo->x;
692: else
693: consistancy[i][buf] = rndindex;
694: }
695: }
696: }
697:
698: // check for special buttons
699: for (i=0 ; i<MAXPLAYERS ; i++)
700: {
701: if (playeringame[i])
702: {
703: if (players[i].cmd.buttons & BT_SPECIAL)
704: {
705: switch (players[i].cmd.buttons & BT_SPECIALMASK)
706: {
707: case BTS_PAUSE:
708: paused ^= 1;
709: if (paused)
710: S_PauseSound ();
711: else
712: S_ResumeSound ();
713: break;
714:
715: case BTS_SAVEGAME:
716: if (!savedescription[0])
717: strcpy (savedescription, "NET GAME");
718: savegameslot =
719: (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
720: gameaction = ga_savegame;
721: break;
722: }
723: }
724: }
725: }
726:
727: // do main actions
728: switch (gamestate)
729: {
730: case GS_LEVEL:
731: P_Ticker ();
732: ST_Ticker ();
733: AM_Ticker ();
734: HU_Ticker ();
735: break;
736:
737: case GS_INTERMISSION:
738: WI_Ticker ();
739: break;
740:
741: case GS_FINALE:
742: F_Ticker ();
743: break;
744:
745: case GS_DEMOSCREEN:
746: D_PageTicker ();
747: break;
748: }
749: }
750:
751:
752: //
753: // PLAYER STRUCTURE FUNCTIONS
754: // also see P_SpawnPlayer in P_Things
755: //
756:
757: //
758: // G_InitPlayer
759: // Called at the start.
760: // Called by the game initialization functions.
761: //
762: void G_InitPlayer (int player)
763: {
764: player_t* p;
765:
766: // set up the saved info
767: p = &players[player];
768:
769: // clear everything else to defaults
770: G_PlayerReborn (player);
771:
772: }
773:
774:
775:
776: //
777: // G_PlayerFinishLevel
778: // Can when a player completes a level.
779: //
780: void G_PlayerFinishLevel (int player)
781: {
782: player_t* p;
783:
784: p = &players[player];
785:
786: memset (p->powers, 0, sizeof (p->powers));
787: memset (p->cards, 0, sizeof (p->cards));
788: p->mo->flags &= ~MF_SHADOW; // cancel invisibility
789: p->extralight = 0; // cancel gun flashes
790: p->fixedcolormap = 0; // cancel ir gogles
791: p->damagecount = 0; // no palette changes
792: p->bonuscount = 0;
793: }
794:
1.1.1.2 root 795:
1.1.1.3 root 796: //
797: // G_PlayerReborn
1.1.1.4 root 798: // Called after a player dies
799: // almost everything is cleared and initialized
1.1.1.3 root 800: //
1.1.1.4 root 801: void G_PlayerReborn (int player)
802: {
803: player_t* p;
804: int i;
805: int frags[MAXPLAYERS];
806: int killcount;
807: int itemcount;
808: int secretcount;
809:
810: memcpy (frags,players[player].frags,sizeof(frags));
811: killcount = players[player].killcount;
812: itemcount = players[player].itemcount;
813: secretcount = players[player].secretcount;
814:
815: p = &players[player];
816: memset (p, 0, sizeof(*p));
817:
818: memcpy (players[player].frags, frags, sizeof(players[player].frags));
819: players[player].killcount = killcount;
820: players[player].itemcount = itemcount;
821: players[player].secretcount = secretcount;
822:
823: p->usedown = p->attackdown = true; // don't do anything immediately
824: p->playerstate = PST_LIVE;
825: p->health = MAXHEALTH;
826: p->readyweapon = p->pendingweapon = wp_pistol;
827: p->weaponowned[wp_fist] = true;
828: p->weaponowned[wp_pistol] = true;
829: p->ammo[am_clip] = 50;
830:
831: for (i=0 ; i<NUMAMMO ; i++)
832: p->maxammo[i] = maxammo[i];
833:
1.1.1.2 root 834: }
835:
1.1.1.4 root 836: //
837: // G_CheckSpot
838: // Returns false if the player cannot be respawned
839: // at the given mapthing_t spot
840: // because something is occupying it
841: //
842: void P_SpawnPlayer (mapthing_t* mthing);
843:
844: boolean
845: G_CheckSpot
846: ( int playernum,
847: mapthing_t* mthing )
848: {
849: fixed_t x;
850: fixed_t y;
851: subsector_t* ss;
852: unsigned an;
853: mobj_t* mo;
854: int i;
1.1.1.3 root 855:
1.1.1.4 root 856: if (!players[playernum].mo)
857: {
858: // first spawn of level, before corpses
859: for (i=0 ; i<playernum ; i++)
860: if (players[i].mo->x == mthing->x << FRACBITS
861: && players[i].mo->y == mthing->y << FRACBITS)
862: return false;
1.1.1.2 root 863: return true;
1.1.1.4 root 864: }
865:
866: x = mthing->x << FRACBITS;
867: y = mthing->y << FRACBITS;
868:
869: if (!P_CheckPosition (players[playernum].mo, x, y) )
870: return false;
871:
872: // flush an old corpse if needed
873: if (bodyqueslot >= BODYQUESIZE)
874: P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
875: bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo;
876: bodyqueslot++;
1.1.1.3 root 877:
1.1.1.4 root 878: // spawn a teleport fog
879: ss = R_PointInSubsector (x,y);
880: an = ( ANG45 * (mthing->angle/45) ) >> ANGLETOFINESHIFT;
881:
882: mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
883: , ss->sector->floorheight
884: , MT_TFOG);
885:
886: if (players[consoleplayer].viewz != 1)
887: S_StartSound (mo, sfx_telept); // don't start sound on first frame
888:
889: return true;
890: }
1.1.1.2 root 891:
892:
1.1.1.3 root 893: //
1.1.1.4 root 894: // G_DeathMatchSpawnPlayer
895: // Spawns a player at one of the random death match spots
896: // called at level load and each death
897: //
898: void G_DeathMatchSpawnPlayer (int playernum)
899: {
900: int i,j;
901: int selections;
902:
903: selections = deathmatch_p - deathmatchstarts;
904: if (selections < 4)
905: I_Error ("Only %i deathmatch spots, 4 required", selections);
906:
907: for (j=0 ; j<20 ; j++)
908: {
909: i = P_Random() % selections;
910: if (G_CheckSpot (playernum, &deathmatchstarts[i]) )
911: {
912: deathmatchstarts[i].type = playernum+1;
913: P_SpawnPlayer (&deathmatchstarts[i]);
914: return;
915: }
916: }
917:
918: // no good spot, so the player will probably get stuck
919: P_SpawnPlayer (&playerstarts[playernum]);
920: }
1.1.1.2 root 921:
1.1.1.4 root 922: //
923: // G_DoReborn
924: //
925: void G_DoReborn (int playernum)
926: {
927: int i;
928:
929: if (!netgame)
930: {
931: // reload the level from scratch
932: gameaction = ga_loadlevel;
933: }
934: else
935: {
936: // respawn at the start
937:
938: // first dissasociate the corpse
939: players[playernum].mo->player = NULL;
940:
941: // spawn at random spot if in death match
942: if (deathmatch)
943: {
944: G_DeathMatchSpawnPlayer (playernum);
945: return;
946: }
947:
948: if (G_CheckSpot (playernum, &playerstarts[playernum]) )
949: {
950: P_SpawnPlayer (&playerstarts[playernum]);
951: return;
1.1.1.3 root 952: }
953:
1.1.1.4 root 954: // try to spawn at one of the other players spots
955: for (i=0 ; i<MAXPLAYERS ; i++)
1.1.1.3 root 956: {
1.1.1.4 root 957: if (G_CheckSpot (playernum, &playerstarts[i]) )
958: {
959: playerstarts[i].type = playernum+1; // fake as other player
960: P_SpawnPlayer (&playerstarts[i]);
961: playerstarts[i].type = i+1; // restore
962: return;
963: }
964: // he's going to be inside something. Too bad.
965: }
966: P_SpawnPlayer (&playerstarts[playernum]);
967: }
968: }
969:
970:
971: void G_ScreenShot (void)
972: {
973: gameaction = ga_screenshot;
974: }
975:
976:
977:
978: // DOOM Par Times
979: int pars[4][10] =
980: {
981: {0},
982: {0,30,75,120,90,165,180,180,30,165},
983: {0,90,90,90,120,90,360,240,30,170},
984: {0,90,45,90,150,90,90,165,30,135}
985: };
986:
987: // DOOM II Par Times
988: int cpars[32] =
989: {
990: 30,90,120,120,90,150,120,120,270,90, // 1-10
991: 210,150,150,150,210,150,420,150,210,150, // 11-20
992: 240,150,180,150,150,300,330,420,300,180, // 21-30
993: 120,30 // 31-32
994: };
995:
1.1.1.3 root 996:
997: //
1.1.1.4 root 998: // G_DoCompleted
1.1.1.3 root 999: //
1.1.1.4 root 1000: boolean secretexit;
1001: extern char* pagename;
1002:
1003: void G_ExitLevel (void)
1004: {
1005: secretexit = false;
1006: gameaction = ga_completed;
1007: }
1008:
1009: // Here's for the german edition.
1010: void G_SecretExitLevel (void)
1011: {
1012: // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1013: if ( (gamemode == commercial)
1014: && (W_CheckNumForName("map31")<0))
1.1.1.2 root 1015: secretexit = false;
1.1.1.4 root 1016: else
1017: secretexit = true;
1018: gameaction = ga_completed;
1019: }
1020:
1021: void G_DoCompleted (void)
1022: {
1023: int i;
1024:
1025: gameaction = ga_nothing;
1026:
1027: for (i=0 ; i<MAXPLAYERS ; i++)
1028: if (playeringame[i])
1029: G_PlayerFinishLevel (i); // take away cards and stuff
1030:
1031: if (automapactive)
1032: AM_Stop ();
1033:
1034: if ( gamemode != commercial)
1035: switch(gamemap)
1.1.1.2 root 1036: {
1.1.1.4 root 1037: case 8:
1038: gameaction = ga_victory;
1039: return;
1040: case 9:
1041: for (i=0 ; i<MAXPLAYERS ; i++)
1042: players[i].didsecret = true;
1043: break;
1.1.1.2 root 1044: }
1.1.1.4 root 1045:
1046: //#if 0 Hmmm - why?
1047: if ( (gamemap == 8)
1048: && (gamemode != commercial) )
1049: {
1050: // victory
1051: gameaction = ga_victory;
1052: return;
1053: }
1054:
1055: if ( (gamemap == 9)
1056: && (gamemode != commercial) )
1057: {
1058: // exit secret level
1059: for (i=0 ; i<MAXPLAYERS ; i++)
1060: players[i].didsecret = true;
1061: }
1062: //#endif
1063:
1064:
1065: wminfo.didsecret = players[consoleplayer].didsecret;
1066: wminfo.epsd = gameepisode -1;
1067: wminfo.last = gamemap -1;
1068:
1069: // wminfo.next is 0 biased, unlike gamemap
1070: if ( gamemode == commercial)
1071: {
1072: if (secretexit)
1073: switch(gamemap)
1074: {
1075: case 15: wminfo.next = 30; break;
1076: case 31: wminfo.next = 31; break;
1077: }
1.1.1.2 root 1078: else
1.1.1.4 root 1079: switch(gamemap)
1080: {
1081: case 31:
1082: case 32: wminfo.next = 15; break;
1083: default: wminfo.next = gamemap;
1084: }
1085: }
1086: else
1087: {
1088: if (secretexit)
1089: wminfo.next = 8; // go to secret level
1090: else if (gamemap == 9)
1091: {
1092: // returning from secret level
1093: switch (gameepisode)
1094: {
1095: case 1:
1096: wminfo.next = 3;
1097: break;
1098: case 2:
1099: wminfo.next = 5;
1100: break;
1101: case 3:
1102: wminfo.next = 6;
1103: break;
1104: case 4:
1105: wminfo.next = 2;
1106: break;
1107: }
1108: }
1109: else
1110: wminfo.next = gamemap; // go to next level
1111: }
1112:
1113: wminfo.maxkills = totalkills;
1114: wminfo.maxitems = totalitems;
1115: wminfo.maxsecret = totalsecret;
1116: wminfo.maxfrags = 0;
1117: if ( gamemode == commercial )
1118: wminfo.partime = 35*cpars[gamemap-1];
1119: else
1120: wminfo.partime = 35*pars[gameepisode][gamemap];
1121: wminfo.pnum = consoleplayer;
1122:
1123: for (i=0 ; i<MAXPLAYERS ; i++)
1124: {
1125: wminfo.plyr[i].in = playeringame[i];
1126: wminfo.plyr[i].skills = players[i].killcount;
1127: wminfo.plyr[i].sitems = players[i].itemcount;
1128: wminfo.plyr[i].ssecret = players[i].secretcount;
1129: wminfo.plyr[i].stime = leveltime;
1130: memcpy (wminfo.plyr[i].frags, players[i].frags
1131: , sizeof(wminfo.plyr[i].frags));
1132: }
1133:
1134: gamestate = GS_INTERMISSION;
1135: viewactive = false;
1136: automapactive = false;
1137:
1138: if (statcopy)
1139: memcpy (statcopy, &wminfo, sizeof(wminfo));
1140:
1141: WI_Start (&wminfo);
1142: }
1.1.1.3 root 1143:
1144:
1.1.1.2 root 1145: //
1.1.1.4 root 1146: // G_WorldDone
1.1.1.2 root 1147: //
1.1.1.4 root 1148: void G_WorldDone (void)
1149: {
1150: gameaction = ga_worlddone;
1151:
1152: if (secretexit)
1153: players[consoleplayer].didsecret = true;
1154:
1155: if ( gamemode == commercial )
1156: {
1157: switch (gamemap)
1158: {
1159: case 15:
1160: case 31:
1161: if (!secretexit)
1162: break;
1163: case 6:
1164: case 11:
1165: case 20:
1166: case 30:
1167: F_StartFinale ();
1168: break;
1169: }
1170: }
1171: }
1172:
1173: void G_DoWorldDone (void)
1174: {
1175: gamestate = GS_LEVEL;
1176: gamemap = wminfo.next+1;
1177: G_DoLoadLevel ();
1178: gameaction = ga_nothing;
1179: viewactive = true;
1180: }
1181:
1182:
1183:
1184: //
1185: // G_InitFromSavegame
1186: // Can be called by the startup code or the menu task.
1187: //
1188: extern boolean setsizeneeded;
1189: void R_ExecuteSetViewSize (void);
1190:
1191: char savename[256];
1192:
1193: void G_LoadGame (char* name)
1194: {
1195: strcpy (savename, name);
1196: gameaction = ga_loadgame;
1197: }
1198:
1199: #define VERSIONSIZE 16
1200:
1201:
1202: void G_DoLoadGame (void)
1203: {
1204: int length;
1205: int i;
1206: int a,b,c;
1207: char vcheck[VERSIONSIZE];
1208:
1209: gameaction = ga_nothing;
1210:
1211: length = M_ReadFile (savename, &savebuffer);
1212: save_p = savebuffer + SAVESTRINGSIZE;
1213:
1214: // skip the description field
1215: memset (vcheck,0,sizeof(vcheck));
1216: sprintf (vcheck,"version %i",VERSION);
1217: if (strcmp (save_p, vcheck))
1218: return; // bad version
1219: save_p += VERSIONSIZE;
1220:
1221: gameskill = *save_p++;
1222: gameepisode = *save_p++;
1223: gamemap = *save_p++;
1224: for (i=0 ; i<MAXPLAYERS ; i++)
1225: playeringame[i] = *save_p++;
1226:
1227: // load a base level
1228: G_InitNew (gameskill, gameepisode, gamemap);
1229:
1230: // get the times
1231: a = *save_p++;
1232: b = *save_p++;
1233: c = *save_p++;
1234: leveltime = (a<<16) + (b<<8) + c;
1235:
1236: // dearchive all the modifications
1237: P_UnArchivePlayers ();
1238: P_UnArchiveWorld ();
1239: P_UnArchiveThinkers ();
1240: P_UnArchiveSpecials ();
1241:
1242: if (*save_p != 0x1d)
1243: I_Error ("Bad savegame");
1244:
1245: // done
1246: Z_Free (savebuffer);
1247:
1248: if (setsizeneeded)
1249: R_ExecuteSetViewSize ();
1250:
1251: // draw the pattern into the back screen
1252: R_FillBackScreen ();
1253: }
1254:
1.1.1.2 root 1255:
1.1.1.3 root 1256: //
1257: // G_SaveGame
1.1.1.4 root 1258: // Called by the menu task.
1259: // Description is a 24 byte text string
1.1.1.3 root 1260: //
1.1.1.4 root 1261: void
1262: G_SaveGame
1263: ( int slot,
1264: char* description )
1265: {
1266: savegameslot = slot;
1267: strcpy (savedescription, description);
1268: sendsave = true;
1269: }
1270:
1271: void G_DoSaveGame (void)
1272: {
1273: char name[100];
1274: char name2[VERSIONSIZE];
1275: char* description;
1276: int length;
1277: int i;
1278:
1279: if (M_CheckParm("-cdrom"))
1280: sprintf(name,"c:\\doomdata\\"SAVEGAMENAME"%d.dsg",savegameslot);
1281: else
1282: sprintf (name,SAVEGAMENAME"%d.dsg",savegameslot);
1283: description = savedescription;
1284:
1285: save_p = savebuffer = screens[1]+0x4000;
1286:
1287: memcpy (save_p, description, SAVESTRINGSIZE);
1288: save_p += SAVESTRINGSIZE;
1289: memset (name2,0,sizeof(name2));
1290: sprintf (name2,"version %i",VERSION);
1291: memcpy (save_p, name2, VERSIONSIZE);
1292: save_p += VERSIONSIZE;
1293:
1294: *save_p++ = gameskill;
1295: *save_p++ = gameepisode;
1296: *save_p++ = gamemap;
1297: for (i=0 ; i<MAXPLAYERS ; i++)
1298: *save_p++ = playeringame[i];
1299: *save_p++ = leveltime>>16;
1300: *save_p++ = leveltime>>8;
1301: *save_p++ = leveltime;
1302:
1303: P_ArchivePlayers ();
1304: P_ArchiveWorld ();
1305: P_ArchiveThinkers ();
1306: P_ArchiveSpecials ();
1307:
1308: *save_p++ = 0x1d; // consistancy marker
1309:
1310: length = save_p - savebuffer;
1311: if (length > SAVEGAMESIZE)
1312: I_Error ("Savegame buffer overrun");
1313: M_WriteFile (name, savebuffer, length);
1314: gameaction = ga_nothing;
1315: savedescription[0] = 0;
1316:
1317: players[consoleplayer].message = GGSAVED;
1318:
1319: // draw the pattern into the back screen
1320: R_FillBackScreen ();
1321: }
1322:
1323:
1324: //
1325: // G_InitNew
1326: // Can be called by the startup code or the menu task,
1327: // consoleplayer, displayplayer, playeringame[] should be set.
1328: //
1329: skill_t d_skill;
1330: int d_episode;
1331: int d_map;
1332:
1333: void
1334: G_DeferedInitNew
1335: ( skill_t skill,
1336: int episode,
1337: int map)
1338: {
1339: d_skill = skill;
1340: d_episode = episode;
1341: d_map = map;
1342: gameaction = ga_newgame;
1343: }
1344:
1345:
1346: void G_DoNewGame (void)
1347: {
1348: demoplayback = false;
1349: netdemo = false;
1350: netgame = false;
1351: deathmatch = false;
1352: playeringame[1] = playeringame[2] = playeringame[3] = 0;
1353: respawnparm = false;
1354: fastparm = false;
1355: nomonsters = false;
1356: consoleplayer = 0;
1357: G_InitNew (d_skill, d_episode, d_map);
1358: gameaction = ga_nothing;
1359: }
1360:
1361: // The sky texture to be used instead of the F_SKY1 dummy.
1362: extern int skytexture;
1363:
1364:
1365: void
1366: G_InitNew
1367: ( skill_t skill,
1368: int episode,
1369: int map )
1370: {
1371: int i;
1372:
1373: if (paused)
1374: {
1375: paused = false;
1376: S_ResumeSound ();
1377: }
1378:
1.1.1.2 root 1379:
1.1.1.4 root 1380: if (skill > sk_nightmare)
1381: skill = sk_nightmare;
1.1.1.2 root 1382:
1383:
1.1.1.4 root 1384: // This was quite messy with SPECIAL and commented parts.
1385: // Supposedly hacks to make the latest edition work.
1386: // It might not work properly.
1387: if (episode < 1)
1388: episode = 1;
1389:
1390: if ( gamemode == retail )
1391: {
1392: if (episode > 4)
1393: episode = 4;
1394: }
1395: else if ( gamemode == shareware )
1396: {
1397: if (episode > 1)
1398: episode = 1; // only start episode 1 on shareware
1399: }
1400: else
1401: {
1402: if (episode > 3)
1403: episode = 3;
1404: }
1405:
1406:
1407:
1408: if (map < 1)
1409: map = 1;
1410:
1411: if ( (map > 9)
1412: && ( gamemode != commercial) )
1413: map = 9;
1414:
1415: M_ClearRandom ();
1416:
1417: if (skill == sk_nightmare || respawnparm )
1418: respawnmonsters = true;
1419: else
1420: respawnmonsters = false;
1421:
1422: if (fastparm || (skill == sk_nightmare && gameskill != sk_nightmare) )
1423: {
1424: for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
1425: states[i].tics >>= 1;
1426: mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT;
1427: mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT;
1428: mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT;
1429: }
1430: else if (skill != sk_nightmare && gameskill == sk_nightmare)
1431: {
1432: for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++)
1433: states[i].tics <<= 1;
1434: mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT;
1435: mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT;
1436: mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT;
1437: }
1438:
1439:
1440: // force players to be initialized upon first level load
1441: for (i=0 ; i<MAXPLAYERS ; i++)
1442: players[i].playerstate = PST_REBORN;
1443:
1444: usergame = true; // will be set false if a demo
1445: paused = false;
1446: demoplayback = false;
1447: automapactive = false;
1448: viewactive = true;
1449: gameepisode = episode;
1450: gamemap = map;
1451: gameskill = skill;
1452:
1453: viewactive = true;
1454:
1455: // set the sky map for the episode
1456: if ( gamemode == commercial)
1457: {
1458: skytexture = R_TextureNumForName ("SKY3");
1459: if (gamemap < 12)
1460: skytexture = R_TextureNumForName ("SKY1");
1461: else
1462: if (gamemap < 21)
1463: skytexture = R_TextureNumForName ("SKY2");
1464: }
1465: else
1466: switch (episode)
1467: {
1468: case 1:
1469: skytexture = R_TextureNumForName ("SKY1");
1470: break;
1471: case 2:
1472: skytexture = R_TextureNumForName ("SKY2");
1473: break;
1474: case 3:
1475: skytexture = R_TextureNumForName ("SKY3");
1476: break;
1477: case 4: // Special Edition sky
1478: skytexture = R_TextureNumForName ("SKY4");
1479: break;
1480: }
1481:
1482: G_DoLoadLevel ();
1483: }
1484:
1.1.1.2 root 1485:
1.1.1.3 root 1486: //
1.1.1.4 root 1487: // DEMO RECORDING
1488: //
1489: #define DEMOMARKER 0x80
1.1.1.2 root 1490:
1491:
1.1.1.4 root 1492: void G_ReadDemoTiccmd (ticcmd_t* cmd)
1493: {
1494: if (*demo_p == DEMOMARKER)
1495: {
1496: // end of demo data stream
1497: G_CheckDemoStatus ();
1498: return;
1499: }
1500: cmd->forwardmove = ((signed char)*demo_p++);
1501: cmd->sidemove = ((signed char)*demo_p++);
1502: cmd->angleturn = ((unsigned char)*demo_p++)<<8;
1503: cmd->buttons = (unsigned char)*demo_p++;
1504: }
1505:
1506:
1507: void G_WriteDemoTiccmd (ticcmd_t* cmd)
1508: {
1509: if (gamekeydown['q']) // press q to end demo recording
1510: G_CheckDemoStatus ();
1511: *demo_p++ = cmd->forwardmove;
1512: *demo_p++ = cmd->sidemove;
1513: *demo_p++ = (cmd->angleturn+128)>>8;
1514: *demo_p++ = cmd->buttons;
1515: demo_p -= 4;
1516: if (demo_p > demoend - 16)
1517: {
1518: // no more space
1519: G_CheckDemoStatus ();
1520: return;
1521: }
1.1.1.3 root 1522:
1.1.1.4 root 1523: G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
1524: }
1525:
1526:
1527:
1528: //
1529: // G_RecordDemo
1530: //
1531: void G_RecordDemo (char* name)
1532: {
1533: int i;
1534: int maxsize;
1.1.1.3 root 1535:
1.1.1.4 root 1536: usergame = false;
1537: strcpy (demoname, name);
1538: strcat (demoname, ".lmp");
1539: maxsize = 0x20000;
1540: i = M_CheckParm ("-maxdemo");
1541: if (i && i<myargc-1)
1542: maxsize = atoi(myargv[i+1])*1024;
1543: demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL);
1544: demoend = demobuffer + maxsize;
1.1.1.3 root 1545:
1.1.1.4 root 1546: demorecording = true;
1547: }
1548:
1549:
1550: void G_BeginRecording (void)
1551: {
1552: int i;
1553:
1554: demo_p = demobuffer;
1.1.1.3 root 1555:
1.1.1.4 root 1556: *demo_p++ = VERSION;
1557: *demo_p++ = gameskill;
1558: *demo_p++ = gameepisode;
1559: *demo_p++ = gamemap;
1560: *demo_p++ = deathmatch;
1561: *demo_p++ = respawnparm;
1562: *demo_p++ = fastparm;
1563: *demo_p++ = nomonsters;
1564: *demo_p++ = consoleplayer;
1565:
1566: for (i=0 ; i<MAXPLAYERS ; i++)
1567: *demo_p++ = playeringame[i];
1568: }
1569:
1570:
1571: //
1572: // G_PlayDemo
1573: //
1574:
1575: char* defdemoname;
1576:
1577: void G_DeferedPlayDemo (char* name)
1578: {
1579: defdemoname = name;
1580: gameaction = ga_playdemo;
1581: }
1582:
1583: void G_DoPlayDemo (void)
1584: {
1585: skill_t skill;
1586: int i, episode, map;
1587:
1588: gameaction = ga_nothing;
1589: demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
1590: if ( *demo_p++ != VERSION)
1591: {
1592: fprintf( stderr, "Demo is from a different game version!\n");
1593: gameaction = ga_nothing;
1594: return;
1595: }
1596:
1597: skill = *demo_p++;
1598: episode = *demo_p++;
1599: map = *demo_p++;
1600: deathmatch = *demo_p++;
1601: respawnparm = *demo_p++;
1602: fastparm = *demo_p++;
1603: nomonsters = *demo_p++;
1604: consoleplayer = *demo_p++;
1.1.1.3 root 1605:
1.1.1.4 root 1606: for (i=0 ; i<MAXPLAYERS ; i++)
1607: playeringame[i] = *demo_p++;
1608: if (playeringame[1])
1609: {
1610: netgame = true;
1611: netdemo = true;
1612: }
1613:
1614: // don't spend a lot of time in loadlevel
1615: precache = false;
1616: G_InitNew (skill, episode, map);
1617: precache = true;
1618:
1619: usergame = false;
1620: demoplayback = true;
1621: }
1622:
1623: //
1624: // G_TimeDemo
1625: //
1626: void G_TimeDemo (char* name)
1627: {
1628: nodrawers = M_CheckParm ("-nodraw");
1629: noblit = M_CheckParm ("-noblit");
1630: timingdemo = true;
1631: singletics = true;
1632:
1633: defdemoname = name;
1634: gameaction = ga_playdemo;
1635: }
1636:
1637:
1638: /*
1639: ===================
1640: =
1641: = G_CheckDemoStatus
1642: =
1643: = Called after a death or level completion to allow demos to be cleaned up
1644: = Returns true if a new demo loop action will take place
1645: ===================
1646: */
1647:
1648: boolean G_CheckDemoStatus (void)
1649: {
1650: int endtime;
1651:
1652: if (timingdemo)
1653: {
1654: endtime = I_GetTime ();
1655: I_Error ("timed %i gametics in %i realtics",gametic
1656: , endtime-starttime);
1657: }
1658:
1659: if (demoplayback)
1660: {
1661: if (singledemo)
1662: I_Quit ();
1663:
1664: Z_ChangeTag (demobuffer, PU_CACHE);
1665: demoplayback = false;
1666: netdemo = false;
1667: netgame = false;
1668: deathmatch = false;
1669: playeringame[1] = playeringame[2] = playeringame[3] = 0;
1670: respawnparm = false;
1671: fastparm = false;
1672: nomonsters = false;
1673: consoleplayer = 0;
1674: D_AdvanceDemo ();
1675: return true;
1676: }
1677:
1678: if (demorecording)
1679: {
1680: *demo_p++ = DEMOMARKER;
1681: M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
1682: Z_Free (demobuffer);
1683: demorecording = false;
1684: I_Error ("Demo %s recorded",demoname);
1685: }
1686:
1687: return false;
1688: }
1689:
1690:
1691:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.