1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 
27 //#define MAIN
28 //#define QUIET
29 #include "build.h"
30 #include "cache1d.h"
31 #include "osd.h"
32 
33 #include "keys.h"
34 #include "names2.h"
35 #include "panel.h"
36 #include "game.h"
37 #include "net.h"
38 
39 #include "mytypes.h"
40 #include "control.h"
41 #include "function.h"
42 #include "demo.h"
43 
44 #include "player.h"
45 #include "menus.h"
46 
47 
48 DFILE DemoFileIn = DF_ERR;
49 FILE *DemoFileOut;
50 BOOL DemoPlaying = FALSE;
51 BOOL DemoRecording = FALSE;
52 BOOL DemoEdit = FALSE;
53 BOOL DemoMode = FALSE;
54 BOOL DemoModeMenuState = FALSE;
55 BOOL DemoOverride = FALSE;
56 char DemoFileName[16] = "demo.dmo";
57 char DemoLevelName[16] = "";
58 extern BOOL NewGame;
59 
60 // Demo sync stuff
61 FILE *DemoSyncFile;
62 BOOL DemoSyncTest = FALSE, DemoSyncRecord = FALSE;
63 char DemoTmpName[16] = "";
64 
65 SW_PACKET DemoBuffer[DEMO_BUFFER_MAX];
66 int DemoRecCnt = 0;                    // Can only record 1-player game
67 
68 BOOL DemoDone;
69 
70 VOID DemoWriteHeader(VOID);
71 VOID DemoReadHeader(VOID);
72 VOID DemoReadBuffer(VOID);
73 
74 
75 //
76 // DemoDebug Vars
77 //
78 
79 // DemoDebugMode will close the file after every write
80 BOOL DemoDebugMode = FALSE;
81 //BOOL DemoDebugMode = TRUE;
82 BOOL DemoInitOnce = FALSE;
83 short DemoDebugBufferMax = 1;
84 
85 extern char LevelName[];
86 extern char LevelSong[16];
87 extern BYTE FakeMultiNumPlayers;
88 extern BOOL QuitFlag;
89 
90 ///////////////////////////////////////////
91 //
92 // Demo File Manipulation
93 //
94 ///////////////////////////////////////////
95 
DemoSyncFileName(VOID)96 char *DemoSyncFileName(VOID)
97     {
98     static char file_name[32];
99     char *ptr;
100 
101     strcpy(file_name, DemoFileName);
102 
103     if ((ptr = strchr(file_name, '.')) == 0)
104         strcat(file_name, ".dms");
105     else
106         {
107         *ptr = '\0';
108         strcat(file_name, ".dms");
109         }
110 
111     return(file_name);
112     }
113 
114 VOID
DemoSetup(VOID)115 DemoSetup(VOID)
116     {
117     if (DemoRecording)
118         {
119         if (DemoSyncRecord)
120             DemoSyncFile = fopen(DemoSyncFileName(),"wb");
121 
122         DemoWriteHeader();
123         memset(&DemoBuffer, -1, sizeof(DemoBuffer));
124         }
125 
126     if (DemoPlaying)
127         {
128         if (DemoSyncRecord)
129             DemoSyncFile = fopen(DemoSyncFileName(),"wb");
130         if (DemoSyncTest)
131             DemoSyncFile = fopen(DemoSyncFileName(),"rb");
132 
133         DemoReadHeader();
134         memset(&DemoBuffer, -1, sizeof(DemoBuffer));
135         DemoReadBuffer();
136         }
137     }
138 
139 VOID
DemoRecordSetup(VOID)140 DemoRecordSetup(VOID)
141     {
142     if (DemoRecording)
143         {
144         if (DemoSyncRecord)
145             DemoSyncFile = fopen(DemoSyncFileName(),"wb");
146 
147         DemoWriteHeader();
148         memset(&DemoBuffer, -1, sizeof(DemoBuffer));
149         }
150     }
151 
152 VOID
DemoPlaySetup(VOID)153 DemoPlaySetup(VOID)
154     {
155     if (DemoPlaying)
156         {
157         if (DemoSyncRecord)
158             DemoSyncFile = fopen(DemoSyncFileName(),"wb");
159         if (DemoSyncTest)
160             DemoSyncFile = fopen(DemoSyncFileName(),"rb");
161 
162         DemoReadHeader();
163         memset(&DemoBuffer, -1, sizeof(DemoBuffer));
164         DemoReadBuffer();
165         }
166     }
167 
168 VOID
DemoWriteHeader(VOID)169 DemoWriteHeader(VOID)
170     {
171     DEMO_HEADER dh;
172     DEMO_START_POS dsp;
173     PLAYERp pp;
174 
175     DemoFileOut = fopen(DemoFileName, "wb");
176 
177     if (!DemoFileOut)
178         return;
179 
180     strcpy(dh.map_name, LevelName);
181     strcpy(dh.LevelSong, LevelSong);
182     dh.Level = Level;
183 
184     if (FakeMultiNumPlayers)
185         dh.numplayers = FakeMultiNumPlayers;
186     else
187         dh.numplayers = CommPlayers;
188 
189     fwrite(&dh, sizeof(dh), 1, DemoFileOut);
190 
191     for (pp = Player; pp < Player + dh.numplayers; pp++)
192         {
193         dsp.x = pp->posx;
194         dsp.y = pp->posy;
195         dsp.z = pp->posz;
196         fwrite(&dsp, sizeof(dsp), 1, DemoFileOut);
197         fwrite(&pp->Flags, sizeof(pp->Flags), 1, DemoFileOut);
198         fwrite(&pp->pang, sizeof(pp->pang), 1, DemoFileOut);
199         }
200 
201     fwrite(&Skill, sizeof(Skill), 1, DemoFileOut);
202     fwrite(&gNet, sizeof(gNet), 1, DemoFileOut);
203 
204     if (DemoDebugMode)
205         {
206         DemoDebugBufferMax = CommPlayers;
207         fclose(DemoFileOut);
208         }
209     }
210 
211 VOID
DemoReadHeader(VOID)212 DemoReadHeader(VOID)
213     {
214     DEMO_HEADER dh;
215     DEMO_START_POS dsp;
216     PLAYERp pp;
217 
218     #if DEMO_FILE_TYPE != DEMO_FILE_GROUP
219     if (DemoEdit)
220         {
221         DemoFileIn = fopen(DemoFileName, "rb+");
222         }
223     else
224     #endif
225         {
226         //DemoFileIn = fopen(DemoFileName, "rb");
227         DemoFileIn = DOPEN_READ(DemoFileName);
228         }
229 
230     if (DemoFileIn == DF_ERR)
231         {
232         TerminateGame();
233         printf("File %s is not a valid demo file.",DemoFileName);
234         exit(0);
235         }
236 
237     DREAD(&dh, sizeof(dh), 1, DemoFileIn);
238 
239     strcpy(DemoLevelName, dh.map_name);
240     strcpy(LevelSong, dh.LevelSong);
241     Level = dh.Level;
242     if (dh.numplayers > 1)
243         {
244         FakeMultiNumPlayers = dh.numplayers;
245         }
246     else
247         CommPlayers = dh.numplayers;
248 
249     for (pp = Player; pp < Player + dh.numplayers; pp++)
250         {
251         DREAD(&dsp, sizeof(dsp), 1, DemoFileIn);
252         pp->posx = dsp.x;
253         pp->posy = dsp.y;
254         pp->posz = dsp.z;
255         COVERupdatesector(pp->posx, pp->posy, &pp->cursectnum);
256         //pp->cursectnum = 0;
257         //updatesectorz(pp->posx, pp->posy, pp->posz, &pp->cursectnum);
258         DREAD(&pp->Flags, sizeof(pp->Flags), 1, DemoFileIn);
259         DREAD(&pp->pang, sizeof(pp->pang), 1, DemoFileIn);
260         }
261 
262     DREAD(&Skill, sizeof(Skill), 1, DemoFileIn);
263     DREAD(&gNet, sizeof(gNet), 1, DemoFileIn);
264     }
265 
266 VOID
DemoDebugWrite(VOID)267 DemoDebugWrite(VOID)
268     {
269     int size;
270 
271     DemoFileOut = fopen(DemoFileName, "ab");
272 
273     ASSERT(DemoFileOut);
274 
275     size = sizeof(SW_PACKET) * DemoDebugBufferMax;
276     fwrite(&DemoBuffer, size, 1, DemoFileOut);
277     memset(&DemoBuffer, -1, size);
278 
279     fclose(DemoFileOut);
280     }
281 
282 VOID
DemoWriteBuffer(VOID)283 DemoWriteBuffer(VOID)
284     {
285     fwrite(&DemoBuffer, sizeof(DemoBuffer), 1, DemoFileOut);
286     memset(&DemoBuffer, -1, sizeof(DemoBuffer));
287     }
288 
289 VOID
DemoReadBuffer(VOID)290 DemoReadBuffer(VOID)
291     {
292     memset(&DemoBuffer, -1, sizeof(DemoBuffer));
293     DREAD(&DemoBuffer, sizeof(DemoBuffer), 1, DemoFileIn);
294     }
295 
296 VOID
DemoBackupBuffer(VOID)297 DemoBackupBuffer(VOID)
298     {
299     #if DEMO_FILE_TYPE != DEMO_FILE_GROUP
300     FILE *NewDemoFile;
301     FILE *OldDemoFile = DemoFileIn;
302     int pos,i;
303     char copy_buffer;
304     char NewDemoFileName[16] = "!";
305 
306     // seek backwards to beginning of last buffer
307     fseek(OldDemoFile, -sizeof(DemoBuffer), SEEK_CUR);
308     pos = ftell(OldDemoFile);
309 
310     // open a new edit file
311     strcat(NewDemoFileName, DemoFileName);
312     NewDemoFile = fopen(NewDemoFileName, "wb");
313 
314     rewind(OldDemoFile);
315 
316     // copy old demo to new demo
317     for (i = 0; i < pos; i++)
318         {
319         fread(&copy_buffer, sizeof(copy_buffer), 1, OldDemoFile);
320         fwrite(&copy_buffer,sizeof(copy_buffer), 1, NewDemoFile);
321         }
322 
323     DemoFileOut = NewDemoFile;
324     fclose(OldDemoFile);
325     #endif
326     }
327 
328 VOID
DemoTerm(VOID)329 DemoTerm(VOID)
330     {
331     if (DemoRecording)
332         {
333         // if already closed
334         if (DemoFileOut == NULL)
335             return;
336 
337         if (DemoDebugMode)
338             {
339             DemoFileOut = fopen(DemoFileName, "ab");
340             ASSERT(DemoFileOut);
341             }
342         else
343             {
344             // paste on a -1 record to the current buffer
345             if (DemoRecCnt < DEMO_BUFFER_MAX)
346                 memset(&DemoBuffer[DemoRecCnt], -1, sizeof(DemoBuffer[DemoRecCnt]));
347 
348             DemoWriteBuffer();
349             }
350 
351         // write at least 1 record at the end filled with -1
352         // just for good measure
353         memset(&DemoBuffer[0], -1, sizeof(DemoBuffer[0]));
354         fwrite(&DemoBuffer[0], sizeof(DemoBuffer[0]), 1, DemoFileOut);
355 
356         fclose(DemoFileOut);
357         DemoFileOut = NULL;
358         }
359 
360     if (DemoPlaying)
361         {
362         if (DemoFileIn == DF_ERR)
363             return;
364 
365         DCLOSE(DemoFileIn);
366         DemoFileIn = DF_ERR;
367         }
368 
369     if (DemoSyncTest||DemoSyncRecord)
370         {
371         fclose(DemoSyncFile);
372         DemoSyncFile = NULL;
373         }
374     }
375 
376 ///////////////////////////////////////////
377 //
378 // Demo Play Back
379 //
380 ///////////////////////////////////////////
381 
382 
383 VOID
DemoPlayBack(VOID)384 DemoPlayBack(VOID)
385     {
386     int pnum, cnt;
387     static int buf_ndx;
388     PLAYERp pp;
389     ControlInfo info;
390     int Xdim, Ydim, ScreenSize;
391 
392     if (SW_SHAREWARE) {
393     // code here needs to be similar to RunLevel startup code
394     PlaySong(LevelSong, -1, TRUE, TRUE);
395     }
396 
397 
398     // Initialize Game part of network code (When ready2send != 0)
399     InitNetVars();
400 
401     // IMPORTANT - MUST be right before game loop
402     InitTimingVars();
403 
404     // THIS STUFF DEPENDS ON MYCONNECTINDEX BEING SET RIGHT
405     pp = Player + myconnectindex;
406     SetRedrawScreen(pp);
407 
408     if (!DemoInitOnce)
409         buf_ndx = 0;
410 
411     // everything has been inited at least once for PLAYBACK
412     DemoInitOnce = TRUE;
413 
414     cnt = 0;
415     ready2send = 0;
416     DemoDone = FALSE;
417 
418     while (TRUE)
419         {
420         // makes code run at the same rate
421         while (totalclock > totalsynctics)
422             {
423 			handleevents();
424 
425             TRAVERSE_CONNECT(pnum)
426                 {
427                 pp = Player + pnum;
428                 pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ-1)] = DemoBuffer[buf_ndx];
429                 pp->movefifoend++;
430                 buf_ndx++;
431 
432                 if (pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ-1)].bits == -1)
433                     {
434                     DemoDone = TRUE;
435                     break;
436                     }
437 
438                 if (buf_ndx > DEMO_BUFFER_MAX - 1)
439                     {
440                     DemoReadBuffer();
441                     buf_ndx = 0;
442                     }
443                 }
444 
445             if (DemoDone)
446                 break;
447 
448             cnt++;
449 
450             if (!UsingMenus)
451                 CONTROL_GetInput(&info);
452 
453             domovethings();
454 
455             OSD_DispatchQueued();
456             MNU_CheckForMenus();
457 
458             // fast forward and slow mo
459             if (DemoEdit)
460                 {
461                 if (KEY_PRESSED(KEYSC_F))
462                     {
463                     if (KEY_PRESSED(KEYSC_LSHIFT) || KEY_PRESSED(KEYSC_RSHIFT))
464                         totalclock += synctics;
465                     else
466                         totalclock += synctics-1;
467                     }
468 
469                 if (KEY_PRESSED(KEYSC_S))
470                     totalclock += 1-synctics;
471                 }
472             else
473                 {
474                 #if DEBUG
475                 if (KEY_PRESSED(KEYSC_ALT) && KEY_PRESSED(KEYSC_CTRL) && KEY_PRESSED(KEYSC_S))
476                     {
477                     KEY_PRESSED(KEYSC_ALT) = KEY_PRESSED(KEYSC_CTRL) = KEY_PRESSED(KEYSC_S) = 0;
478                     saveboard("demosave.map", &Player->posx, &Player->posy, &Player->posz, &Player->pang, &Player->cursectnum);
479                     }
480                 #endif
481 
482                 if (BUTTON(gamefunc_See_Co_Op_View))
483                     {
484                     CONTROL_ClearButton(gamefunc_See_Co_Op_View);
485                     NextScreenPeek();
486                     }
487 
488                 #if DEBUG
489                 if (KEY_PRESSED(KEYSC_RIGHT) || KEY_PRESSED(KEYSC_UP))
490                     {
491                     if (KEY_PRESSED(KEYSC_LSHIFT) || KEY_PRESSED(KEYSC_RSHIFT))
492                         totalclock += synctics;
493                     else
494                         totalclock += synctics-1;
495                     }
496 
497                 if (KEY_PRESSED(KEYSC_LEFT) || KEY_PRESSED(KEYSC_DOWN))
498                     totalclock += 1-synctics;
499                 #endif
500                 }
501 
502 
503             if (DemoSyncRecord)
504                 demosync_record();
505             if (DemoSyncTest)
506                demosync_test(cnt);
507             }
508 
509         // Put this back in later when keyboard stuff is stable
510         if (DemoEdit)
511             {
512             //CONTROL_GetButtonInput();
513             CONTROL_GetInput(&info);
514 
515             // if a key is pressed, start recording from the point the key
516             // was pressed
517             if (BUTTON(gamefunc_Move_Forward) ||
518                 BUTTON(gamefunc_Move_Backward) ||
519                 BUTTON(gamefunc_Turn_Left) ||
520                 BUTTON(gamefunc_Turn_Right) ||
521                 BUTTON(gamefunc_Fire) ||
522                 BUTTON(gamefunc_Open) ||
523                 BUTTON(gamefunc_Jump) ||
524                 BUTTON(gamefunc_Crouch) ||
525                 BUTTON(gamefunc_Look_Up) ||
526                 BUTTON(gamefunc_Look_Down))
527                 {
528                 DemoBackupBuffer();
529 
530                 DemoRecCnt = buf_ndx;
531                 DemoPlaying = FALSE;
532                 DemoRecording = TRUE;
533                 return;
534                 }
535             }
536 
537         if (BUTTON(gamefunc_See_Co_Op_View))
538             {
539             NextScreenPeek();
540             }
541 
542         // demo is over
543         if (DemoDone)
544             break;
545 
546         if (QuitFlag)
547             {
548             DemoMode = FALSE;
549             break;
550             }
551 
552         if (ExitLevel)
553             {
554             // Quiting Demo
555             ExitLevel = FALSE;
556             if (DemoMode)
557                 {
558                 DemoPlaying = FALSE;
559                 DemoMode = FALSE;
560                 }
561             break;
562             }
563 
564         drawscreen(Player + screenpeek);
565         }
566 
567     // only exit if conditions are write
568     if (DemoDone && !DemoMode && !NewGame)
569         {
570         TerminateLevel();
571         TerminateGame();
572         exit(0);
573         }
574 
575     }
576 
577 //
578 // Still using old method of playback - this was for opening demo
579 //
580 
581 VOID
ScenePlayBack(VOID)582 ScenePlayBack(VOID)
583     {
584     int buf_ndx, pnum, cnt;
585     PLAYERp pp;
586 
587     if (SW_SHAREWARE) {
588     // code here needs to be similar to RunLevel startup code
589     strcpy(LevelSong,"yokoha03.mid");
590     PlaySong(LevelSong, -1, TRUE, TRUE);
591     }
592 
593     // IMPORTANT - MUST be right before game loop
594     InitTimingVars();
595 
596     buf_ndx = 0;
597     cnt = 0;
598     ready2send = 0;
599     DemoDone = FALSE;
600 
601     ResetKeys();
602 
603     while (TRUE)
604         {
605         // makes code run at the same rate
606         while ((totalclock > totalsynctics))
607             {
608             TRAVERSE_CONNECT(pnum)
609                 {
610                 pp = Player + pnum;
611                 pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ - 1)] = DemoBuffer[buf_ndx];
612                 pp->movefifoend++;
613                 buf_ndx++;
614 
615                 if (pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)].bits == -1)
616                     {
617                     DemoDone = TRUE;
618                     break;
619                     }
620 
621                 if (buf_ndx > DEMO_BUFFER_MAX - 1)
622                     {
623                     DemoReadBuffer();
624                     buf_ndx = 0;
625                     }
626                 }
627 
628             if (KeyPressed())
629                 DemoDone = TRUE;
630 
631             if (DemoDone)
632                 break;
633 
634             cnt++;
635 
636             //movethings();
637             domovethings();
638 
639             MNU_CheckForMenus();
640             }
641 
642         // demo is over
643         if (DemoDone)
644             break;
645 
646         drawscreen(Player + screenpeek);
647         }
648     }
649 
650 
651 
652