1 /* $Id: newdemo.c,v 1.12 2003/03/18 02:31:16 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14 
15 /*
16  *
17  * Code to make a complete demo playback system.
18  *
19  * $Log: newdemo.c,v $
20  * Revision 1.12  2003/03/18 02:31:16  btb
21  * simplify DEMO_FILENAME macro
22  *
23  * Revision 1.11  2003/03/17 07:59:11  btb
24  * also look in shared data dir for demos
25  *
26  * Revision 1.10  2003/03/17 07:10:21  btb
27  * comments/formatting
28  *
29  * Revision 1.12  1995/10/31  10:19:43  allender
30  * shareware stuff
31  *
32  * Revision 1.11  1995/10/17  13:19:16  allender
33  * close boxes for demo save
34  *
35  * Revision 1.10  1995/10/05  10:36:07  allender
36  * fixed calls to digi_play_sample to account for differing volume and angle calculations
37  *
38  * Revision 1.9  1995/09/12  15:49:13  allender
39  * define __useAppleExts__ if not already defined
40  *
41  * Revision 1.8  1995/09/05  14:28:32  allender
42  * fixed previous N_players bug in newdemo_goto_end
43  *
44  * Revision 1.7  1995/09/05  14:16:51  allender
45  * added space to allowable demo filename characters
46  * and fixed bug with netgame demos N_players got getting
47  * set correctly
48  *
49  * Revision 1.6  1995/09/01  16:10:47  allender
50  * fixed bug with reading in N_players variable on
51  * netgame demo playback
52  *
53  * Revision 1.5  1995/08/24  16:04:11  allender
54  * fix signed byte problem
55  *
56  * Revision 1.4  1995/08/12  12:21:59  allender
57  * made call to create_shortpos not swap the shortpos
58  * elements
59  *
60  * Revision 1.3  1995/08/01  16:04:19  allender
61  * made random picking of demo work
62  *
63  * Revision 1.2  1995/08/01  13:56:56  allender
64  * demo system working on the mac
65  *
66  * Revision 1.1  1995/05/16  15:28:59  allender
67  * Initial revision
68  *
69  * Revision 2.7  1995/05/26  16:16:06  john
70  * Split SATURN into define's for requiring cd, using cd, etc.
71  * Also started adding all the Rockwell stuff.
72  *
73  * Revision 2.6  1995/03/21  14:39:38  john
74  * Ifdef'd out the NETWORK code.
75  *
76  * Revision 2.5  1995/03/14  18:24:31  john
77  * Force Destination Saturn to use CD-ROM drive.
78  *
79  * Revision 2.4  1995/03/14  16:22:29  john
80  * Added cdrom alternate directory stuff.
81  *
82  * Revision 2.3  1995/03/10  12:58:33  allender
83  * only display rear view cockpit when cockpit mode was CM_FULL_COCKPIT.
84  *
85  * Revision 2.2  1995/03/08  16:12:15  allender
86  * changes for Destination Saturn
87  *
88  * Revision 2.1  1995/03/08  12:11:26  allender
89  * fix shortpos reading
90  *
91  * Revision 2.0  1995/02/27  11:29:40  john
92  * New version 2.0, which has no anonymous unions, builds with
93  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
94  *
95  * Revision 1.189  1995/02/22  14:53:42  allender
96  * missed some anonymous stuff
97  *
98  * Revision 1.188  1995/02/22  13:24:53  john
99  * Removed the vecmat anonymous unions.
100  *
101  * Revision 1.187  1995/02/22  13:13:54  allender
102  * remove anonymous unions from object structure
103  *
104  * Revision 1.186  1995/02/14  15:36:41  allender
105  * fix fix for morph effect
106  *
107  * Revision 1.185  1995/02/14  11:25:48  allender
108  * save cockpit mode and restore after playback.  get orientation for morph
109  * effect when object is morph vclip
110  *
111  * Revision 1.184  1995/02/13  12:18:14  allender
112  * change to decide about interpolating or not
113  *
114  * Revision 1.183  1995/02/12  00:46:23  adam
115  * don't decide to skip frames until after at least 10 frames have
116  * passed -- allender
117  *
118  * Revision 1.182  1995/02/11  22:34:01  john
119  * Made textures page in for newdemos before playback time.
120  *
121  * Revision 1.181  1995/02/11  17:28:32  allender
122  * strip frames from end of demo
123  *
124  * Revision 1.180  1995/02/11  16:40:35  allender
125  * start of frame stripping debug code
126  *
127  * Revision 1.179  1995/02/10  17:40:06  allender
128  * put back in wall_hit_process code to fix door problem
129  *
130  * Revision 1.178  1995/02/10  17:17:24  adam
131  * allender } fix
132  *
133  * Revision 1.177  1995/02/10  17:16:24  allender
134  * fix possible tmap problems
135  *
136  * Revision 1.176  1995/02/10  15:54:37  allender
137  * changes for out of space on device.
138  *
139  * Revision 1.175  1995/02/09  19:55:00  allender
140  * fix bug with morph recording -- force rendertype to RT_POLYOBJ when
141  * playing back since it won't render until fully morphed otherwise
142  *
143  * Revision 1.174  1995/02/07  17:15:35  allender
144  * DOH!!!!!
145  *
146  * Revision 1.173  1995/02/07  17:14:21  allender
147  * immediately return when loading bogus level stuff when reading a frame
148  *
149  * Revision 1.172  1995/02/02  11:15:03  allender
150  * after loading new level, read next frame (forward or back) always because
151  * of co-op ships showing up when level is loaded
152  *
153  * Revision 1.171  1995/02/02  10:24:16  allender
154  * removed cfile stuff.  Use standard FILE functions for demo playback
155  *
156  * Revision 1.170  1995/01/30  13:54:32  allender
157  * support for missions
158  *
159  * Revision 1.169  1995/01/27  16:27:35  allender
160  * put game mode to demo_game_mode when sorting multiplayer kill (and score)
161  * list
162  *
163  * Revision 1.168  1995/01/27  09:52:25  allender
164  * minor changes because of object/segment linking problems
165  *
166  * Revision 1.167  1995/01/27  09:22:28  allender
167  * changed way multi-player score is recorded.  Record difference, not
168  * actual
169  *
170  * Revision 1.166  1995/01/25  14:32:44  allender
171  * changed with recorded player flags.  More checks for paused state
172  * during interpolation reading of objects
173  *
174  * Revision 1.165  1995/01/25  11:23:32  allender
175  * found bug with out of disk space problem
176  *
177  * Revision 1.164  1995/01/25  11:11:33  allender
178  * coupla' things.  Fix problem with objects apparently being linked in
179  * the wrong segment.  Put an Int3 in to check why demos will write to
180  * end of space on drive. close demo file if demo doens't start playing
181  * back.  Put obj->type == OBJ_ROBOT around checking for boss cloaking
182  *
183  * Revision 1.163  1995/01/24  19:44:30  allender
184  * fix obscure problem with rewinding and having the wrong object linked
185  * to the wrong segments.  will investigate further.
186  *
187  * Revision 1.162  1995/01/23  09:31:28  allender
188  * add team score in team mode playback
189  *
190  * Revision 1.161  1995/01/20  22:47:39  matt
191  * Mission system implemented, though imcompletely
192  *
193  * Revision 1.160  1995/01/20  09:30:37  allender
194  * don't call LoadLevel with bogus data
195  *
196  * Revision 1.159  1995/01/20  09:13:23  allender
197  * *&^%&*%$ typo
198  *
199  * Revision 1.158  1995/01/20  09:12:04  allender
200  * record team names during demo recoring in GM_TEAM
201  *
202  * Revision 1.157  1995/01/19  16:31:09  allender
203  * forgot to bump demo version for new weapon change stuff
204  *
205  * Revision 1.156  1995/01/19  16:29:33  allender
206  * added new byte for weapon change (old weapon) so rewinding works
207  * correctly for weapon changes in registered
208  *
209  * Revision 1.155  1995/01/19  15:00:05  allender
210  * remove code to take away blastable walls in multiplayer demo playbacks
211  *
212  * Revision 1.154  1995/01/19  11:07:05  allender
213  * put in psuedo cloaking for boss robots.  Problem is that cloaking is
214  * time based, and that don't get done in demos, so bosses just disappear.
215  * oh well
216  *
217  * Revision 1.153  1995/01/19  09:42:29  allender
218  * record laser levels in demos
219  *
220  * Revision 1.152  1995/01/18  20:43:12  allender
221  * fix laser level stuff on goto-beginning and goto-end
222  *
223  * Revision 1.151  1995/01/18  20:28:18  allender
224  * cloak robots now cloak (except maybe for boss........)  Put in function
225  * to deal with control center triggers
226  *
227  * Revision 1.150  1995/01/18  18:55:07  allender
228  * bug fix
229  *
230  * Revision 1.149  1995/01/18  18:49:03  allender
231  * lots 'o stuff....record laser level.  Record beginning of door opening
232  * sequence.  Fix some problems with control center stuff.  Control center
233  * triggers now work in reverse
234  *
235  * Revision 1.148  1995/01/18  08:51:40  allender
236  * forgot to record ammo counts at beginning of demo
237  *
238  * Revision 1.147  1995/01/17  17:42:07  allender
239  * added primary and secondary ammo counts.  Changed goto_end routine
240  * to be more efficient
241  *
242  * Revision 1.146  1995/01/17  13:46:35  allender
243  * fix problem with destroyed control center and rewinding a demo.
244  * Save callsign and restore after demo playback
245  *
246  * Revision 1.145  1995/01/12  10:21:53  allender
247  * fixes for 1.0 to 1.1 demo incompatibility
248  *
249  * Revision 1.144  1995/01/05  13:51:43  allender
250  * fixed type of player num variable
251  *
252  * Revision 1.143  1995/01/04  16:58:28  allender
253  * bumped up demo version number
254  *
255  * Revision 1.142  1995/01/04  14:59:02  allender
256  * added more information to end of demo for registered.  Forced game mode
257  * to be GM_NORMAL on demo playback
258  *
259  * Revision 1.141  1995/01/03  17:30:47  allender
260  * fixed logic problem with cloak stuf
261  *
262  * Revision 1.140  1995/01/03  17:12:23  allender
263  * fix for getting cloak stuff at end of demo for shareware
264  *
265  * Revision 1.139  1995/01/03  15:20:24  allender
266  * fix goto_end for shareware -- changes to goto_end for registered
267  *
268  * Revision 1.138  1995/01/03  13:13:26  allender
269  * add } I forgot
270  *
271  * Revision 1.137  1995/01/03  13:10:29  allender
272  * make score work forwards and backwards
273  *
274  * Revision 1.136  1995/01/03  11:45:20  allender
275  * added code to record players scores
276  *
277  * Revision 1.135  1994/12/30  10:03:57  allender
278  * put cloak stuff at end of demo for fast forward to the end
279  *
280  * Revision 1.134  1994/12/29  17:02:55  allender
281  * spelling fix on SHAREWARE
282  *
283  * Revision 1.133  1994/12/29  16:43:41  allender
284  * lots of new multiplayer stuff.  wrapped much code with SHAREWARE defines
285  *
286  * Revision 1.132  1994/12/28  14:15:01  allender
287  * added routines to deal with connecting and reconnecting players when
288  * recording multiplayer demos
289  *
290  * Revision 1.131  1994/12/21  12:57:59  allender
291  * bug fix
292  *
293  * Revision 1.130  1994/12/21  12:46:53  allender
294  * record multi player deaths and kills
295  *
296  * Revision 1.129  1994/12/19  16:37:27  allender
297  * pick good filename when trying to save in network play and player
298  * gets bumped out of menu by multi-player code
299  *
300  * Revision 1.128  1994/12/14  10:49:01  allender
301  * reset bad_read variable when starting demo playback
302  *
303  * Revision 1.127  1994/12/14  08:53:06  allender
304  * lowered watermark for out of space
305  *
306  * Revision 1.126  1994/12/14  08:49:52  allender
307  * put up warning when starting demo recording if not enough space and
308  * not let them record
309  *
310  * Revision 1.125  1994/12/13  00:01:37  allender
311  * CLOAK FIX -- (I'm tempted to take cloak out of game because I can't
312  * seem to get it right in demo playback)
313  *
314  * Revision 1.124  1994/12/12  14:51:21  allender
315  * more fixed to multiplayer cloak stuff
316  *
317  * Revision 1.123  1994/12/12  11:33:11  allender
318  * fixed rearview mode to work again
319  *
320  * Revision 1.122  1994/12/12  11:00:16  matt
321  * Added code to handle confusion with attached objects
322  *
323  * Revision 1.121  1994/12/12  00:31:29  allender
324  * give better warning when out of space when recording.  Don't record
325  * until no space left.  We have 500K watermark when we now stop recording
326  *
327  * Revision 1.120  1994/12/10  16:44:54  matt
328  * Added debugging code to track down door that turns into rock
329  *
330  * Revision 1.119  1994/12/09  18:46:15  matt
331  * Added code to handle odd error condition
332  *
333  * Revision 1.118  1994/12/09  17:27:37  allender
334  * force playernum to 0 when demo is done playing
335  *
336  * Revision 1.117  1994/12/09  16:40:39  allender
337  * yet more cloak stuff.  Assign cloak/invuln time when starting demo
338  * if flags are set.  Check cloak and invuln time when demo
339  * even when paused
340  *
341  * Revision 1.116  1994/12/09  14:59:22  matt
342  * Added system to attach a fireball to another object for rendering purposes,
343  * so the fireball always renders on top of (after) the object.
344  *
345  * Revision 1.115  1994/12/09  12:21:45  allender
346  * only allow valid chars when typing in demo filename
347  *
348  * Revision 1.114  1994/12/08  23:19:02  allender
349  * final(?) fix for getting cloak gauge to work on demo playback
350  * with forward and reverse
351  *
352  * Revision 1.113  1994/12/08  21:34:38  allender
353  * record old and new player flags to accuratedly record cloaking and
354  * decloaking
355  * ./
356  *
357  * Revision 1.112  1994/12/08  18:04:47  allender
358  * bashed playernum right after reading it in demo header so shields
359  * and energy are put in right place
360  *
361  * Revision 1.111  1994/12/08  17:10:07  allender
362  * encode playernum in demo header.  Bash viewer segment to 0 if in
363  * bogus segnum.  Don't link render objs for same reason
364  *
365  * Revision 1.110  1994/12/08  15:36:12  allender
366  * cloak stuff works forwards and backwards
367  *
368  * Revision 1.109  1994/12/08  13:46:03  allender
369  * don't record rearview anymore, but leave in case statement for playback
370  * purposes.  change the way letterbox <--> cockpit transitions happen
371  *
372  * Revision 1.108  1994/12/08  12:36:06  matt
373  * Added new object allocation & deallocation functions so other code
374  * could stop messing around with internal object data structures.
375  *
376  * Revision 1.107  1994/12/08  11:19:04  allender
377  * handle out of space (more) gracefully then before
378  *
379  * Revision 1.106  1994/12/08  00:29:49  allender
380  * fixed bug that didn't load level on goto_beginning
381  *
382  * Revision 1.105  1994/12/08  00:11:51  mike
383  * change matrix interpolation.
384  *
385  * Revision 1.104  1994/12/07  23:46:37  allender
386  * changed invulnerability and cloak to work (almost) correctly both
387  * in single and multi player
388  *
389  * Revision 1.103  1994/12/07  11:48:49  adam
390  * BY ALLENDER -- added dampening of interpolation factor to 1 if greater
391  * than 1 (although I have not seen this happen).  this is attempt to
392  * get wobbling problem solved
393  *
394  * Revision 1.102  1994/12/07  11:23:56  allender
395  * attempt at getting rid of wobbling on demo playback
396  *
397  * Revision 1.101  1994/12/06  19:31:17  allender
398  * moved blastable wall stuff code to where we load level during demo
399  * playback
400  *
401  * Revision 1.100  1994/12/06  19:21:51  allender
402  * multi games, destroy blastable walls.  Do wall toggle when control center
403  * destroyed
404  *
405  * Revision 1.99  1994/12/06  16:54:48  allender
406  * fixed code so if demo automatically started from menu, don't bring up
407  * message if demo is too old
408  *
409  * Revision 1.98  1994/12/06  13:55:15  matt
410  * Use new rounding func, f2ir()
411  *
412  * Revision 1.97  1994/12/06  13:44:45  allender
413  * suppressed compiler warnings
414  *
415  * Revision 1.96  1994/12/06  13:38:03  allender
416  * removed recording of wall hit process.  I think that all bases are covered
417  * elsewhere
418  *
419  * Revision 1.95  1994/12/06  12:57:35  allender
420  * added recording of multi_decloaking.  Fixed some other cloaking code so
421  * that cloak should last as long as player was cloaked.  We will lose the
422  * guage effect, but the time is probably more important on playback
423  *
424  * Revision 1.94  1994/12/05  23:37:17  matt
425  * Took out calls to warning() function
426  *
427  * Revision 1.93  1994/12/03  17:52:04  yuan
428  * Localization 380ish
429  *
430  * Revision 1.92  1994/12/02  12:53:39  allender
431  * fixed goto_beginning and goto_end on demo playback
432  *
433  * Revision 1.91  1994/12/01  12:01:49  allender
434  * added multi player cloak stuff
435  *
436  * Revision 1.90  1994/11/30  09:33:58  allender
437  * added field in header to tell what version (shareware or registered)
438  * demo was recorded with.  Don't allow demo recorded on one to playback
439  * on the other
440  *
441  * Revision 1.89  1994/11/29  00:31:01  allender
442  * major changes -- added level recording feature which records level
443  * advancement.  Changes to internal code to handle this.
444  *
445  * Revision 1.88  1994/11/27  23:13:54  matt
446  * Made changes for new mprintf calling convention
447  *
448  * Revision 1.87  1994/11/27  23:07:35  allender
449  * starting on code to get all level transitions recorded. not done yet
450  *
451  * Revision 1.86  1994/11/27  17:39:47  matt
452  * Don't xlate tmap numbers when editor compiled out
453  *
454  * Revision 1.85  1994/11/23  09:27:21  allender
455  * put up info box with message if demo version is too old or level
456  * cannot be loaded
457  *
458  * Revision 1.84  1994/11/22  19:37:39  allender
459  * fix array mistake
460  *
461  * Revision 1.83  1994/11/22  19:35:09  allender
462  * record player ship colors in multiplayer demo recordings
463  *
464  * Revision 1.82  1994/11/19  15:36:42  mike
465  * fix fix.
466  *
467  * Revision 1.81  1994/11/19  15:23:21  mike
468  * rip out unused code
469  *
470  * Revision 1.80  1994/11/16  14:51:49  rob
471  * Fixed network/demo incompatibility.
472  *
473  * Revision 1.79  1994/11/15  10:55:48  allender
474  * made start of demo playback read initial demo information so
475  * level will get loaded.  Made demo record to single file which
476  * will get renamed.  Added numerics after old filename so
477  * sequential filenames would be defaulted to
478  *
479  * Revision 1.78  1994/11/15  09:46:06  allender
480  * added versioning.  Fixed problems with trying to interpolating a completely
481  * 0 orientation matrix
482  *
483  * Revision 1.77  1994/11/14  14:34:31  matt
484  * Fixed up handling when textures can't be found during remap
485  *
486  * Revision 1.76  1994/11/14  09:15:29  allender
487  * make ESC from file save menu exit w/o saving.  Fix letterbox, rear view,
488  * to normal cockpit mode transition to work correctly when skipping and
489  * interpolating frames
490  *
491  * Revision 1.75  1994/11/11  16:22:07  allender
492  * made morphing objects record only the object being morphed.
493  *
494  * Revision 1.74  1994/11/08  14:59:19  john
495  * Added code to respond to network while in menus.
496  *
497  * Revision 1.73  1994/11/08  14:52:20  adam
498  * *** empty log message ***
499  *
500  * Revision 1.72  1994/11/07  15:47:04  allender
501  * prompt for filename when done recording demo
502  *
503  * Revision 1.71  1994/11/07  11:47:19  allender
504  * when interpolating frames, delete weapon, fireball, and debris objects
505  * from an inpolated frame if they don't appear in the next recorded
506  * frame
507  *
508  * Revision 1.70  1994/11/07  11:02:41  allender
509  * more with interpolation. I believe that I have it right now
510  *
511  * Revision 1.69  1994/11/07  08:47:40  john
512  * Made wall state record.
513  *
514  * Revision 1.68  1994/11/05  17:22:51  john
515  * Fixed lots of sequencing problems with newdemo stuff.
516  *
517  * Revision 1.67  1994/11/04  20:11:52  john
518  * Neatening up palette stuff with demos.
519  *
520  * Revision 1.66  1994/11/04  16:49:44  allender
521  * changed newdemo_do_interpolate to default to on
522  *
523  * Revision 1.65  1994/11/04  16:44:51  allender
524  * added filename support for demo recording.  more auto demo stuff
525  *
526  * Revision 1.64  1994/11/04  13:05:31  allender
527  * fixing the lifeleft variable again.  (I think I got it right this time)
528  *
529  * Revision 1.63  1994/11/04  11:37:37  allender
530  * commented out fprintfs and fixed compiler warning
531  *
532  * Revision 1.62  1994/11/04  11:33:50  allender
533  * added OBJ_FLARE and OBJ_LIGHT to obj->lifeleft recording
534  *
535  * Revision 1.61  1994/11/04  11:29:21  allender
536  * more interpolation stuff -- not done yet.  Fixed so hostage vclips
537  * render correctly.  Changed lifeleft to full precision, but only
538  * write it when object is fireball or weapon type of object
539  *
540  * Revision 1.60  1994/11/03  10:00:11  allender
541  * fixed divide by zero in calculating render time.  more interpolation
542  * stuff which isn't quite done
543  *
544  * Revision 1.59  1994/11/02  17:10:59  allender
545  * never play recorded frames when interpolation is occuring
546  *
547  * Revision 1.58  1994/11/02  14:28:58  allender
548  * profile total playback time and average frame render time
549  *
550  * Revision 1.57  1994/11/02  14:09:03  allender
551  * record rear view.  start of playback interpolation code -- this
552  * is not yet done
553  *
554  * Revision 1.56  1994/11/01  13:25:30  allender
555  * drop frames if playing back demo on slower machine
556  *
557  * Revision 1.55  1994/10/31  16:10:40  allender
558  * record letterbox mode on death seq, and then restore
559  *
560  * Revision 1.54  1994/10/29  16:01:38  allender
561  * added ND_STATE_NODEMOS to indicate that there are no demos currently
562  * available for playback
563  *
564  * Revision 1.53  1994/10/29  15:38:42  allender
565  * in newdemo_start_playback, make Newdemo_at_eof = 0
566  *
567  * Revision 1.52  1994/10/28  14:45:28  john
568  * fixed typo from last checkin.
569  *
570  * Revision 1.51  1994/10/28  14:42:55  john
571  * Added sound volumes to all sound calls.
572  *
573  * Revision 1.50  1994/10/28  14:31:57  allender
574  * homing missle and autodemo stuff
575  *
576  * Revision 1.49  1994/10/28  12:42:14  allender
577  * record homing distance
578  *
579  * Revision 1.48  1994/10/27  16:57:54  allender
580  * changed demo vcr to be able to play any number of frames by storing
581  * frame length (in bytes) in the demo file.  Added blowing up monitors
582  *
583  * Revision 1.47  1994/10/26  16:50:50  allender
584  * put two functions inside of VCR_MODE ifdef
585  *
586  * Revision 1.46  1994/10/26  15:20:32  allender
587  * added CT_REMOTE as valid control type for recording
588  *
589  * Revision 1.45  1994/10/26  14:45:35  allender
590  * completed hacked in vcr demo playback stuff
591  *
592  * Revision 1.44  1994/10/26  13:40:52  allender
593  * vcr playback of demo stuff
594  *
595  * Revision 1.43  1994/10/26  08:51:57  allender
596  * record player weapon change
597  *
598  * Revision 1.42  1994/10/25  15:48:01  allender
599  * add shields, energy, and player flags to demo recording.
600  * ,
601  *
602  * Revision 1.41  1994/10/24  08:19:35  allender
603  * fixed compilation errors
604  *
605  * Revision 1.40  1994/10/23  19:17:08  matt
606  * Fixed bug with "no key" messages
607  *
608  * Revision 1.39  1994/10/22  14:15:08  mike
609  * Suppress compiler warnings.
610  *
611  * Revision 1.38  1994/10/21  15:24:55  allender
612  * compressed writing of object structures with specialized code
613  * to write out only pertinent object structures.
614  *
615  * Revision 1.37  1994/10/20  13:03:17  matt
616  * Replaced old save files (MIN/SAV/HOT) with new LVL files
617  *
618  * Revision 1.36  1994/09/28  23:13:10  matt
619  * Macroized palette flash system
620  *
621  * Revision 1.35  1994/09/26  17:28:32  matt
622  * Made new multiple-object morph code work with the demo system
623  *
624  * Revision 1.34  1994/09/10  13:31:54  matt
625  * Made exploding walls a type of blastable walls.
626  * Cleaned up blastable walls, making them tmap2 bitmaps.
627  *
628  * Revision 1.33  1994/08/15  18:05:28  john
629  * *** empty log message ***
630  *
631  * Revision 1.32  1994/08/15  17:56:38  john
632  * ,
633  *
634  * Revision 1.31  1994/08/10  09:44:54  john
635  * *** empty log message ***
636  *
637  * Revision 1.30  1994/07/22  12:35:48  matt
638  * Cleaned up editor/game interactions some more.
639  *
640  * Revision 1.29  1994/07/21  13:06:45  matt
641  * Ripped out remants of old demo system, and added demo only system that
642  * disables object movement and game options from menu.
643  *
644  * Revision 1.28  1994/07/18  16:22:44  john
645  * Made all file read/writes call the same routine.
646  *
647  * Revision 1.27  1994/07/14  22:38:27  matt
648  * Added exploding doors
649  *
650  * Revision 1.26  1994/07/05  12:49:04  john
651  * Put functionality of New Hostage spec into code.
652  *
653  * Revision 1.25  1994/06/29  11:05:38  john
654  * Made demos read in compressed.
655  *
656  * Revision 1.24  1994/06/29  09:14:06  john
657  * Made files write out uncompressed and read in compressed.
658  *
659  * Revision 1.23  1994/06/28  11:55:28  john
660  * Made newdemo system record/play directly to/from disk, so
661  * we don't need the 4 MB buffer anymore.
662  *
663  * Revision 1.22  1994/06/27  15:52:38  john
664  * #define'd out the newdemo stuff
665  *
666  *
667  * Revision 1.21  1994/06/22  00:29:04  john
668  * Fixed bug with playing demo then playing game without
669  * loading new mine.
670  *
671  * Revision 1.20  1994/06/22  00:14:23  john
672  * Attempted to fix sign.
673  *
674  * Revision 1.19  1994/06/21  23:57:54  john
675  * Hopefully fixed bug with negative countdowns.
676  *
677  * Revision 1.18  1994/06/21  23:47:44  john
678  * MAde Malloc always 4*1024*1024.
679  *
680  * Revision 1.17  1994/06/21  22:58:47  john
681  * Added error if out of memory.
682  *
683  * Revision 1.16  1994/06/21  22:15:48  john
684  * Added  % done to demo recording.
685  *
686  *
687  * Revision 1.15  1994/06/21  19:45:55  john
688  * Added palette effects to demo recording.
689  *
690  * Revision 1.14  1994/06/21  15:08:54  john
691  * Made demo record HUD message and cleaned up the HUD code.
692  *
693  * Revision 1.13  1994/06/21  14:20:08  john
694  * Put in hooks to record HUD messages.
695  *
696  * Revision 1.12  1994/06/20  11:50:15  john
697  * Made demo record flash effect, and control center triggers.
698  *
699  * Revision 1.11  1994/06/17  18:01:33  john
700  * A bunch of new stuff by John
701  *
702  * Revision 1.10  1994/06/17  12:13:31  john
703  * More newdemo stuff; made editor->game transition start in slew mode.
704  *
705  * Revision 1.9  1994/06/16  13:14:36  matt
706  * Fixed typo
707  *
708  * Revision 1.8  1994/06/16  13:02:07  john
709  * Added morph hooks.
710  *
711  * Revision 1.7  1994/06/15  19:01:33  john
712  * Added the capability to make 3d sounds play just once for the
713  * laser hit wall effects.
714  *
715  * Revision 1.6  1994/06/15  14:56:59  john
716  * Added triggers to demo recording.
717  *
718  * Revision 1.5  1994/06/14  20:42:15  john
719  * Made robot matztn cntr not work until no robots or player are
720  * in the segment.
721  *
722  * Revision 1.4  1994/06/14  14:43:27  john
723  * Made doors work with newdemo system.
724  *
725  * Revision 1.3  1994/06/14  11:32:29  john
726  * Made Newdemo record & restore the current mine.
727  *
728  * Revision 1.2  1994/06/13  21:02:43  john
729  * Initial version of new demo recording system.
730  *
731  * Revision 1.1  1994/06/13  11:09:00  john
732  * Initial revision
733  *
734  *
735  */
736 
737 
738 #ifdef HAVE_CONFIG_H
739 #include <conf.h>
740 #endif
741 
742 #include <stdlib.h>
743 #include <stdio.h>
744 #include <stdarg.h>
745 #include <string.h> // for memset
746 #include <errno.h>
747 #include <ctype.h>      /* for isdigit */
748 #include <limits.h>
749 #ifdef __unix__
750 #include <sys/stat.h>
751 #include <sys/types.h>
752 #endif
753 
754 #include "u_mem.h"
755 #include "inferno.h"
756 #include "game.h"
757 #include "gr.h"
758 #include "stdlib.h"
759 #include "bm.h"
760 //#include "error.h"
761 #include "mono.h"
762 #include "3d.h"
763 #include "segment.h"
764 #include "texmap.h"
765 #include "laser.h"
766 #include "key.h"
767 #include "gameseg.h"
768 
769 #include "object.h"
770 #include "physics.h"
771 #include "slew.h"
772 #include "render.h"
773 #include "wall.h"
774 #include "vclip.h"
775 #include "polyobj.h"
776 #include "fireball.h"
777 #include "laser.h"
778 #include "error.h"
779 #include "ai.h"
780 #include "hostage.h"
781 #include "morph.h"
782 
783 #include "powerup.h"
784 #include "fuelcen.h"
785 
786 #include "sounds.h"
787 #include "collide.h"
788 
789 #include "lighting.h"
790 #include "newdemo.h"
791 #include "gameseq.h"
792 #include "gamesave.h"
793 #include "gamemine.h"
794 #include "switch.h"
795 #include "gauges.h"
796 #include "player.h"
797 #include "vecmat.h"
798 #include "newmenu.h"
799 #include "args.h"
800 #include "palette.h"
801 #include "multi.h"
802 #ifdef NETWORK
803 #include "network.h"
804 #endif
805 #include "text.h"
806 #include "cntrlcen.h"
807 #include "aistruct.h"
808 #include "mission.h"
809 #include "piggy.h"
810 #include "controls.h"
811 #include "d_io.h"
812 #include "timer.h"
813 
814 #include "findfile.h"
815 
816 #ifdef EDITOR
817 #include "editor/editor.h"
818 #endif
819 
820 #ifdef MACINTOSH
821 #pragma global_optimizer off        // pretty much sucks...need to look into this
822 #endif
823 
824 void DoJasonInterpolate (fix recorded_time);
825 
826 //#include "nocfile.h"
827 
828 //Does demo start automatically?
829 int Auto_demo = 0;
830 
831 byte WasRecorded [MAX_OBJECTS];
832 byte ViewWasRecorded[MAX_OBJECTS];
833 byte RenderingWasRecorded[32];
834 
835 #define ND_EVENT_EOF                0   // EOF
836 #define ND_EVENT_START_DEMO         1   // Followed by 16 character, NULL terminated filename of .SAV file to use
837 #define ND_EVENT_START_FRAME        2   // Followed by integer frame number, then a fix FrameTime
838 #define ND_EVENT_VIEWER_OBJECT      3   // Followed by an object structure
839 #define ND_EVENT_RENDER_OBJECT      4   // Followed by an object structure
840 #define ND_EVENT_SOUND              5   // Followed by int soundum
841 #define ND_EVENT_SOUND_ONCE         6   // Followed by int soundum
842 #define ND_EVENT_SOUND_3D           7   // Followed by int soundum, int angle, int volume
843 #define ND_EVENT_WALL_HIT_PROCESS   8   // Followed by int segnum, int side, fix damage
844 #define ND_EVENT_TRIGGER            9   // Followed by int segnum, int side, int objnum
845 #define ND_EVENT_HOSTAGE_RESCUED    10  // Followed by int hostage_type
846 #define ND_EVENT_SOUND_3D_ONCE      11  // Followed by int soundum, int angle, int volume
847 #define ND_EVENT_MORPH_FRAME        12  // Followed by ? data
848 #define ND_EVENT_WALL_TOGGLE        13  // Followed by int seg, int side
849 #define ND_EVENT_HUD_MESSAGE        14  // Followed by char size, char * string (+null)
850 #define ND_EVENT_CONTROL_CENTER_DESTROYED 15 // Just a simple flag
851 #define ND_EVENT_PALETTE_EFFECT     16  // Followed by short r,g,b
852 #define ND_EVENT_PLAYER_ENERGY      17  // followed by byte energy
853 #define ND_EVENT_PLAYER_SHIELD      18  // followed by byte shields
854 #define ND_EVENT_PLAYER_FLAGS       19  // followed by player flags
855 #define ND_EVENT_PLAYER_WEAPON      20  // followed by weapon type and weapon number
856 #define ND_EVENT_EFFECT_BLOWUP      21  // followed by segment, side, and pnt
857 #define ND_EVENT_HOMING_DISTANCE    22  // followed by homing distance
858 #define ND_EVENT_LETTERBOX          23  // letterbox mode for death seq.
859 #define ND_EVENT_RESTORE_COCKPIT    24  // restore cockpit after death
860 #define ND_EVENT_REARVIEW           25  // going to rear view mode
861 #define ND_EVENT_WALL_SET_TMAP_NUM1 26  // Wall changed
862 #define ND_EVENT_WALL_SET_TMAP_NUM2 27  // Wall changed
863 #define ND_EVENT_NEW_LEVEL          28  // followed by level number
864 #define ND_EVENT_MULTI_CLOAK        29  // followed by player num
865 #define ND_EVENT_MULTI_DECLOAK      30  // followed by player num
866 #define ND_EVENT_RESTORE_REARVIEW   31  // restore cockpit after rearview mode
867 #define ND_EVENT_MULTI_DEATH        32  // with player number
868 #define ND_EVENT_MULTI_KILL         33  // with player number
869 #define ND_EVENT_MULTI_CONNECT      34  // with player number
870 #define ND_EVENT_MULTI_RECONNECT    35  // with player number
871 #define ND_EVENT_MULTI_DISCONNECT   36  // with player number
872 #define ND_EVENT_MULTI_SCORE        37  // playernum / score
873 #define ND_EVENT_PLAYER_SCORE       38  // followed by score
874 #define ND_EVENT_PRIMARY_AMMO       39  // with old/new ammo count
875 #define ND_EVENT_SECONDARY_AMMO     40  // with old/new ammo count
876 #define ND_EVENT_DOOR_OPENING       41  // with segment/side
877 #define ND_EVENT_LASER_LEVEL        42  // no data
878 #define ND_EVENT_PLAYER_AFTERBURNER 43  // followed by byte old ab, current ab
879 #define ND_EVENT_CLOAKING_WALL      44  // info changing while wall cloaking
880 #define ND_EVENT_CHANGE_COCKPIT     45  // change the cockpit
881 #define ND_EVENT_START_GUIDED       46  // switch to guided view
882 #define ND_EVENT_END_GUIDED         47  // stop guided view/return to ship
883 #define ND_EVENT_SECRET_THINGY      48  // 0/1 = secret exit functional/non-functional
884 #define ND_EVENT_LINK_SOUND_TO_OBJ  49  // record digi_link_sound_to_object3
885 #define ND_EVENT_KILL_SOUND_TO_OBJ  50  // record digi_kill_sound_linked_to_object
886 
887 
888 #define NORMAL_PLAYBACK         0
889 #define SKIP_PLAYBACK           1
890 #define INTERPOLATE_PLAYBACK    2
891 #define INTERPOL_FACTOR         (F1_0 + (F1_0/5))
892 
893 #define DEMO_VERSION            15      // last D1 version was 13
894 #define DEMO_GAME_TYPE          3       // 1 was shareware, 2 registered
895 
896 #define DEMO_FILENAME           DEMO_DIR "tmpdemo.dem"
897 
898 #define DEMO_MAX_LEVELS         29
899 
900 
901 char nd_save_callsign[CALLSIGN_LEN+1];
902 int Newdemo_state = 0;
903 int Newdemo_vcr_state = 0;
904 int Newdemo_start_frame = -1;
905 unsigned int Newdemo_size;
906 int Newdemo_num_written;
907 int Newdemo_game_mode;
908 int Newdemo_old_cockpit;
909 byte Newdemo_no_space;
910 byte Newdemo_at_eof;
911 byte Newdemo_do_interpolate = 0; // 1
912 byte Newdemo_players_cloaked;
913 byte Newdemo_warning_given = 0;
914 byte Newdemo_cntrlcen_destroyed = 0;
915 static byte nd_bad_read;
916 int NewdemoFrameCount;
917 short frame_bytes_written = 0;
918 fix nd_playback_total;
919 fix nd_recorded_total;
920 fix nd_recorded_time;
921 byte playback_style;
922 byte First_time_playback=1;
923 fix JasonPlaybackTotal=0;
924 
925 
926 FILE *infile;
927 FILE *outfile=NULL;
928 
newdemo_get_percent_done()929 int newdemo_get_percent_done() {
930 	if ( Newdemo_state == ND_STATE_PLAYBACK ) {
931 		return (ftell(infile)*100)/Newdemo_size;
932 	}
933 	if ( Newdemo_state == ND_STATE_RECORDING ) {
934 		return ftell(outfile);
935 	}
936 	return 0;
937 }
938 
939 #define VEL_PRECISION 12
940 
my_extract_shortpos(object * objp,shortpos * spp)941 void my_extract_shortpos(object *objp, shortpos *spp)
942 {
943 	int segnum;
944 	byte *sp;
945 
946 	sp = spp->bytemat;
947 	objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
948 	objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
949 	objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
950 
951 	objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
952 	objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
953 	objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
954 
955 	objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
956 	objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
957 	objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
958 
959 	segnum = spp->segment;
960 	objp->segnum = segnum;
961 
962 	objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
963 	objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
964 	objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
965 
966 	objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
967 	objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
968 	objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
969 }
970 
newdemo_read(void * buffer,int elsize,int nelem)971 int newdemo_read( void *buffer, int elsize, int nelem )
972 {
973 	int num_read;
974 	num_read = fread( buffer,elsize,nelem, infile );
975 	if (ferror(infile) || feof(infile))
976 		nd_bad_read = -1;
977 
978 	return num_read;
979 }
980 
newdemo_find_object(int signature)981 int newdemo_find_object( int signature )
982 {
983 	int i;
984 	object * objp;
985 	objp = Objects;
986 	for (i=0; i<=Highest_object_index; i++, objp++ ) {
987 		if ( (objp->type != OBJ_NONE) && (objp->signature == signature))
988 			return i;
989 	}
990 	return -1;
991 }
992 
newdemo_write(void * buffer,int elsize,int nelem)993 int newdemo_write( void *buffer, int elsize, int nelem )
994 {
995 	int num_written, total_size;
996 
997 	total_size = elsize * nelem;
998 	frame_bytes_written += total_size;
999 	Newdemo_num_written += total_size;
1000 	Assert(outfile != NULL);
1001 	num_written = fwrite( buffer, elsize, nelem, outfile );
1002 	//if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space) {
1003 	//	Newdemo_no_space=1;
1004 	//	newdemo_stop_recording();
1005 	//	return -1;
1006 	//}
1007 	if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space)
1008 		Newdemo_no_space=1;
1009 	if (num_written == nelem && !Newdemo_no_space)
1010 		return num_written;
1011 
1012 	Newdemo_no_space=2;
1013 	newdemo_stop_recording();
1014 	return -1;
1015 }
1016 
1017 /*
1018  *  The next bunch of files taken from Matt's gamesave.c.  We have to modify
1019  *  these since the demo must save more information about objects that
1020  *  just a gamesave
1021 */
1022 
nd_write_byte(byte b)1023 static void nd_write_byte(byte b)
1024 {
1025 	newdemo_write(&b, 1, 1);
1026 }
1027 
nd_write_short(short s)1028 static void nd_write_short(short s)
1029 {
1030 	newdemo_write(&s, 2, 1);
1031 }
1032 
nd_write_int(int i)1033 static void nd_write_int(int i)
1034 {
1035 	newdemo_write(&i, 4, 1);
1036 }
1037 
nd_write_string(char * str)1038 static void nd_write_string(char *str)
1039 {
1040 	nd_write_byte(strlen(str) + 1);
1041 	newdemo_write(str, strlen(str) + 1, 1);
1042 }
1043 
nd_write_fix(fix f)1044 static void nd_write_fix(fix f)
1045 {
1046 	newdemo_write(&f, sizeof(fix), 1);
1047 }
1048 
nd_write_fixang(fixang f)1049 static void nd_write_fixang(fixang f)
1050 {
1051 	newdemo_write(&f, sizeof(fixang), 1);
1052 }
1053 
nd_write_vector(vms_vector * v)1054 static void nd_write_vector(vms_vector *v)
1055 {
1056 	nd_write_fix(v->x);
1057 	nd_write_fix(v->y);
1058 	nd_write_fix(v->z);
1059 }
1060 
nd_write_angvec(vms_angvec * v)1061 static void nd_write_angvec(vms_angvec *v)
1062 {
1063 	nd_write_fixang(v->p);
1064 	nd_write_fixang(v->b);
1065 	nd_write_fixang(v->h);
1066 }
1067 
nd_write_shortpos(object * obj)1068 void nd_write_shortpos(object *obj)
1069 {
1070 	int i;
1071 	shortpos sp;
1072 	ubyte render_type;
1073 
1074 	create_shortpos(&sp, obj, 0);
1075 
1076 	render_type = obj->render_type;
1077 	if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
1078 		for (i = 0; i < 9; i++)
1079 			nd_write_byte(sp.bytemat[i]);
1080 		for (i = 0; i < 9; i++) {
1081 			if (sp.bytemat[i] != 0)
1082 				break;
1083 		}
1084 		if (i == 9) {
1085 			Int3();         // contact Allender about this.
1086 		}
1087 	}
1088 
1089 	nd_write_short(sp.xo);
1090 	nd_write_short(sp.yo);
1091 	nd_write_short(sp.zo);
1092 	nd_write_short(sp.segment);
1093 	nd_write_short(sp.velx);
1094 	nd_write_short(sp.vely);
1095 	nd_write_short(sp.velz);
1096 }
1097 
nd_read_byte(byte * b)1098 static void nd_read_byte(byte *b)
1099 {
1100 	newdemo_read(b, 1, 1);
1101 }
1102 
nd_read_short(short * s)1103 static void nd_read_short(short *s)
1104 {
1105 	newdemo_read(s, 2, 1);
1106 }
1107 
nd_read_int(int * i)1108 static void nd_read_int(int *i)
1109 {
1110 	newdemo_read(i, 4, 1);
1111 }
1112 
nd_read_string(char * str)1113 static void nd_read_string(char *str)
1114 {
1115 	byte len;
1116 
1117 	nd_read_byte(&len);
1118 	newdemo_read(str, len, 1);
1119 }
1120 
nd_read_fix(fix * f)1121 static void nd_read_fix(fix *f)
1122 {
1123 	newdemo_read(f, sizeof(fix), 1);
1124 }
1125 
nd_read_fixang(fixang * f)1126 static void nd_read_fixang(fixang *f)
1127 {
1128 	newdemo_read(f, sizeof(fixang), 1);
1129 }
1130 
nd_read_vector(vms_vector * v)1131 static void nd_read_vector(vms_vector *v)
1132 {
1133 	nd_read_fix(&(v->x));
1134 	nd_read_fix(&(v->y));
1135 	nd_read_fix(&(v->z));
1136 }
1137 
nd_read_angvec(vms_angvec * v)1138 static void nd_read_angvec(vms_angvec *v)
1139 {
1140 	nd_read_fixang(&(v->p));
1141 	nd_read_fixang(&(v->b));
1142 	nd_read_fixang(&(v->h));
1143 }
1144 
nd_read_shortpos(object * obj)1145 static void nd_read_shortpos(object *obj)
1146 {
1147 	shortpos sp;
1148 	int i;
1149 	ubyte render_type;
1150 
1151 	render_type = obj->render_type;
1152 	if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
1153 		for (i = 0; i < 9; i++)
1154 			nd_read_byte(&(sp.bytemat[i]));
1155 	}
1156 
1157 	nd_read_short(&(sp.xo));
1158 	nd_read_short(&(sp.yo));
1159 	nd_read_short(&(sp.zo));
1160 	nd_read_short(&(sp.segment));
1161 	nd_read_short(&(sp.velx));
1162 	nd_read_short(&(sp.vely));
1163 	nd_read_short(&(sp.velz));
1164 
1165 	my_extract_shortpos(obj, &sp);
1166 	if ((obj->id == VCLIP_MORPHING_ROBOT) && (render_type == RT_FIREBALL) && (obj->control_type == CT_EXPLOSION))
1167 		extract_orient_from_segment(&obj->orient,&Segments[obj->segnum]);
1168 
1169 }
1170 
1171 object *prev_obj=NULL;      //ptr to last object read in
1172 
nd_read_object(object * obj)1173 void nd_read_object(object *obj)
1174 {
1175 	memset(obj, 0, sizeof(object));
1176 
1177 	/*
1178 	 * Do render type first, since with render_type == RT_NONE, we
1179 	 * blow by all other object information
1180 	 */
1181 	nd_read_byte(&(obj->render_type));
1182 	nd_read_byte(&(obj->type));
1183 	if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
1184 		return;
1185 
1186 	nd_read_byte(&(obj->id));
1187 	nd_read_byte(&(obj->flags));
1188 	nd_read_short((short *)&(obj->signature));
1189 	nd_read_shortpos(obj);
1190 
1191 	if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
1192 		Int3();
1193 
1194 	obj->attached_obj = -1;
1195 
1196 	switch(obj->type) {
1197 
1198 	case OBJ_HOSTAGE:
1199 		obj->control_type = CT_POWERUP;
1200 		obj->movement_type = MT_NONE;
1201 		obj->size = HOSTAGE_SIZE;
1202 		break;
1203 
1204 	case OBJ_ROBOT:
1205 		obj->control_type = CT_AI;
1206 		// (MarkA and MikeK said we should not do the crazy last secret stuff with multiple reactors...
1207 		// This necessary code is our vindication. --MK, 2/15/96)
1208 		if (obj->id != SPECIAL_REACTOR_ROBOT)
1209 			obj->movement_type = MT_PHYSICS;
1210 		else
1211 			obj->movement_type = MT_NONE;
1212 		obj->size = Polygon_models[Robot_info[obj->id].model_num].rad;
1213 		obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
1214 		obj->rtype.pobj_info.subobj_flags = 0;
1215 		obj->ctype.ai_info.CLOAKED = (Robot_info[obj->id].cloak_type?1:0);
1216 		break;
1217 
1218 	case OBJ_POWERUP:
1219 		obj->control_type = CT_POWERUP;
1220 		nd_read_byte(&(obj->movement_type));        // might have physics movement
1221 		obj->size = Powerup_info[obj->id].size;
1222 		break;
1223 
1224 	case OBJ_PLAYER:
1225 		obj->control_type = CT_NONE;
1226 		obj->movement_type = MT_PHYSICS;
1227 		obj->size = Polygon_models[Player_ship->model_num].rad;
1228 		obj->rtype.pobj_info.model_num = Player_ship->model_num;
1229 		obj->rtype.pobj_info.subobj_flags = 0;
1230 		break;
1231 
1232 	case OBJ_CLUTTER:
1233 		obj->control_type = CT_NONE;
1234 		obj->movement_type = MT_NONE;
1235 		obj->size = Polygon_models[obj->id].rad;
1236 		obj->rtype.pobj_info.model_num = obj->id;
1237 		obj->rtype.pobj_info.subobj_flags = 0;
1238 		break;
1239 
1240 	default:
1241 		nd_read_byte(&(obj->control_type));
1242 		nd_read_byte(&(obj->movement_type));
1243 		nd_read_fix(&(obj->size));
1244 		break;
1245 	}
1246 
1247 
1248 	nd_read_vector(&(obj->last_pos));
1249 	if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
1250 		nd_read_fix(&(obj->lifeleft));
1251 	else {
1252 		ubyte b;
1253 
1254 		nd_read_byte(&b);
1255 		obj->lifeleft = (fix)b;
1256 		// MWA old way -- won't work with big endian machines       nd_read_byte((ubyte *)&(obj->lifeleft));
1257 		obj->lifeleft = (fix)((int)obj->lifeleft << 12);
1258 	}
1259 
1260 	if (obj->type == OBJ_ROBOT) {
1261 		if (Robot_info[obj->id].boss_flag) {
1262 			byte cloaked;
1263 
1264 			nd_read_byte(&cloaked);
1265 			obj->ctype.ai_info.CLOAKED = cloaked;
1266 		}
1267 	}
1268 
1269 	switch (obj->movement_type) {
1270 
1271 	case MT_PHYSICS:
1272 		nd_read_vector(&(obj->mtype.phys_info.velocity));
1273 		nd_read_vector(&(obj->mtype.phys_info.thrust));
1274 		break;
1275 
1276 	case MT_SPINNING:
1277 		nd_read_vector(&(obj->mtype.spin_rate));
1278 		break;
1279 
1280 	case MT_NONE:
1281 		break;
1282 
1283 	default:
1284 		Int3();
1285 	}
1286 
1287 	switch (obj->control_type) {
1288 
1289 	case CT_EXPLOSION:
1290 
1291 		nd_read_fix(&(obj->ctype.expl_info.spawn_time));
1292 		nd_read_fix(&(obj->ctype.expl_info.delete_time));
1293 		nd_read_short(&(obj->ctype.expl_info.delete_objnum));
1294 
1295 		obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
1296 
1297 		if (obj->flags & OF_ATTACHED) {     //attach to previous object
1298 			Assert(prev_obj!=NULL);
1299 			if (prev_obj->control_type == CT_EXPLOSION) {
1300 				if (prev_obj->flags & OF_ATTACHED && prev_obj->ctype.expl_info.attach_parent!=-1)
1301 					obj_attach(&Objects[prev_obj->ctype.expl_info.attach_parent],obj);
1302 				else
1303 					obj->flags &= ~OF_ATTACHED;
1304 			}
1305 			else
1306 				obj_attach(prev_obj,obj);
1307 		}
1308 
1309 		break;
1310 
1311 	case CT_LIGHT:
1312 		nd_read_fix(&(obj->ctype.light_info.intensity));
1313 		break;
1314 
1315 	case CT_AI:
1316 	case CT_WEAPON:
1317 	case CT_NONE:
1318 	case CT_FLYING:
1319 	case CT_DEBRIS:
1320 	case CT_POWERUP:
1321 	case CT_SLEW:
1322 	case CT_CNTRLCEN:
1323 	case CT_REMOTE:
1324 	case CT_MORPH:
1325 		break;
1326 
1327 	case CT_FLYTHROUGH:
1328 	case CT_REPAIRCEN:
1329 	default:
1330 		Int3();
1331 
1332 	}
1333 
1334 	switch (obj->render_type) {
1335 
1336 	case RT_NONE:
1337 		break;
1338 
1339 	case RT_MORPH:
1340 	case RT_POLYOBJ: {
1341 		int i, tmo;
1342 
1343 		if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
1344 			nd_read_int(&(obj->rtype.pobj_info.model_num));
1345 			nd_read_int(&(obj->rtype.pobj_info.subobj_flags));
1346 		}
1347 
1348 		if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
1349 #if 0
1350 			for (i=0;i<MAX_SUBMODELS;i++)
1351 				nd_read_angvec(&(obj->pobj_info.anim_angles[i]));
1352 #endif
1353 		for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
1354 			nd_read_angvec(&obj->rtype.pobj_info.anim_angles[i]);
1355 
1356 		nd_read_int(&tmo);
1357 
1358 #ifndef EDITOR
1359 		obj->rtype.pobj_info.tmap_override = tmo;
1360 #else
1361 		if (tmo==-1)
1362 			obj->rtype.pobj_info.tmap_override = -1;
1363 		else {
1364 			int xlated_tmo = tmap_xlate_table[tmo];
1365 			if (xlated_tmo < 0) {
1366 				//mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->pobj_info.model_num));
1367 				Int3();
1368 				xlated_tmo = 0;
1369 			}
1370 			obj->rtype.pobj_info.tmap_override = xlated_tmo;
1371 		}
1372 #endif
1373 
1374 		break;
1375 	}
1376 
1377 	case RT_POWERUP:
1378 	case RT_WEAPON_VCLIP:
1379 	case RT_FIREBALL:
1380 	case RT_HOSTAGE:
1381 		nd_read_int(&(obj->rtype.vclip_info.vclip_num));
1382 		nd_read_fix(&(obj->rtype.vclip_info.frametime));
1383 		nd_read_byte(&(obj->rtype.vclip_info.framenum));
1384 		break;
1385 
1386 	case RT_LASER:
1387 		break;
1388 
1389 	default:
1390 		Int3();
1391 
1392 	}
1393 
1394 	prev_obj = obj;
1395 }
1396 
nd_write_object(object * obj)1397 void nd_write_object(object *obj)
1398 {
1399 	int life;
1400 
1401 	if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
1402 		Int3();
1403 
1404 	/*
1405 	 * Do render_type first so on read, we can make determination of
1406 	 * what else to read in
1407 	 */
1408 	nd_write_byte(obj->render_type);
1409 	nd_write_byte(obj->type);
1410 	if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
1411 		return;
1412 
1413 	nd_write_byte(obj->id);
1414 	nd_write_byte(obj->flags);
1415 	nd_write_short((short)obj->signature);
1416 	nd_write_shortpos(obj);
1417 
1418 	if ((obj->type != OBJ_HOSTAGE) && (obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_POWERUP) && (obj->type != OBJ_CLUTTER)) {
1419 		nd_write_byte(obj->control_type);
1420 		nd_write_byte(obj->movement_type);
1421 		nd_write_fix(obj->size);
1422 	}
1423 	if (obj->type == OBJ_POWERUP)
1424 		nd_write_byte(obj->movement_type);
1425 
1426 	nd_write_vector(&obj->last_pos);
1427 
1428 	if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
1429 		nd_write_fix(obj->lifeleft);
1430 	else {
1431 		life = (int)obj->lifeleft;
1432 		life = life >> 12;
1433 		if (life > 255)
1434 			life = 255;
1435 		nd_write_byte((ubyte)life);
1436 	}
1437 
1438 	if (obj->type == OBJ_ROBOT) {
1439 		if (Robot_info[obj->id].boss_flag) {
1440 			if ((GameTime > Boss_cloak_start_time) && (GameTime < Boss_cloak_end_time))
1441 				nd_write_byte(1);
1442 			else
1443 				nd_write_byte(0);
1444 		}
1445 	}
1446 
1447 	switch (obj->movement_type) {
1448 
1449 	case MT_PHYSICS:
1450 		nd_write_vector(&obj->mtype.phys_info.velocity);
1451 		nd_write_vector(&obj->mtype.phys_info.thrust);
1452 		break;
1453 
1454 	case MT_SPINNING:
1455 		nd_write_vector(&obj->mtype.spin_rate);
1456 		break;
1457 
1458 	case MT_NONE:
1459 		break;
1460 
1461 	default:
1462 		Int3();
1463 	}
1464 
1465 	switch (obj->control_type) {
1466 
1467 	case CT_AI:
1468 		break;
1469 
1470 	case CT_EXPLOSION:
1471 		nd_write_fix(obj->ctype.expl_info.spawn_time);
1472 		nd_write_fix(obj->ctype.expl_info.delete_time);
1473 		nd_write_short(obj->ctype.expl_info.delete_objnum);
1474 		break;
1475 
1476 	case CT_WEAPON:
1477 		break;
1478 
1479 	case CT_LIGHT:
1480 
1481 		nd_write_fix(obj->ctype.light_info.intensity);
1482 		break;
1483 
1484 	case CT_NONE:
1485 	case CT_FLYING:
1486 	case CT_DEBRIS:
1487 	case CT_POWERUP:
1488 	case CT_SLEW:       //the player is generally saved as slew
1489 	case CT_CNTRLCEN:
1490 	case CT_REMOTE:
1491 	case CT_MORPH:
1492 		break;
1493 
1494 	case CT_REPAIRCEN:
1495 	case CT_FLYTHROUGH:
1496 	default:
1497 		Int3();
1498 
1499 	}
1500 
1501 	switch (obj->render_type) {
1502 
1503 	case RT_NONE:
1504 		break;
1505 
1506 	case RT_MORPH:
1507 	case RT_POLYOBJ: {
1508 		int i;
1509 
1510 		if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
1511 			nd_write_int(obj->rtype.pobj_info.model_num);
1512 			nd_write_int(obj->rtype.pobj_info.subobj_flags);
1513 		}
1514 
1515 		if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
1516 #if 0
1517 			for (i=0;i<MAX_SUBMODELS;i++)
1518 				nd_write_angvec(&obj->pobj_info.anim_angles[i]);
1519 #endif
1520 		for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
1521 			nd_write_angvec(&obj->rtype.pobj_info.anim_angles[i]);
1522 
1523 		nd_write_int(obj->rtype.pobj_info.tmap_override);
1524 
1525 		break;
1526 	}
1527 
1528 	case RT_POWERUP:
1529 	case RT_WEAPON_VCLIP:
1530 	case RT_FIREBALL:
1531 	case RT_HOSTAGE:
1532 		nd_write_int(obj->rtype.vclip_info.vclip_num);
1533 		nd_write_fix(obj->rtype.vclip_info.frametime);
1534 		nd_write_byte(obj->rtype.vclip_info.framenum);
1535 		break;
1536 
1537 	case RT_LASER:
1538 		break;
1539 
1540 	default:
1541 		Int3();
1542 
1543 	}
1544 
1545 }
1546 
1547 int JustStartedRecording=0,JustStartedPlayback=0;
1548 
newdemo_record_start_demo()1549 void newdemo_record_start_demo()
1550 {
1551 	int i;
1552 
1553 	stop_time();
1554 	nd_write_byte(ND_EVENT_START_DEMO);
1555 	nd_write_byte(DEMO_VERSION);
1556 	nd_write_byte(DEMO_GAME_TYPE);
1557 	nd_write_fix(GameTime);
1558 
1559 #ifdef NETWORK
1560 	if (Game_mode & GM_MULTI)
1561 		nd_write_int(Game_mode | (Player_num << 16));
1562 	else
1563 #endif
1564 		// NOTE LINK TO ABOVE!!!
1565 		nd_write_int(Game_mode);
1566 #ifdef NETWORK
1567 
1568 	if (Game_mode & GM_TEAM) {
1569 		nd_write_byte(Netgame.team_vector);
1570 		nd_write_string(Netgame.team_name[0]);
1571 		nd_write_string(Netgame.team_name[1]);
1572 	}
1573 
1574 	if (Game_mode & GM_MULTI) {
1575 		nd_write_byte((byte)N_players);
1576 		for (i = 0; i < N_players; i++) {
1577 			nd_write_string(Players[i].callsign);
1578 			nd_write_byte(Players[i].connected);
1579 
1580 			if (Game_mode & GM_MULTI_COOP) {
1581 				nd_write_int(Players[i].score);
1582 			} else {
1583 				nd_write_short((short)Players[i].net_killed_total);
1584 				nd_write_short((short)Players[i].net_kills_total);
1585 			}
1586 		}
1587 	} else
1588 #endif
1589 		// NOTE LINK TO ABOVE!!!
1590 		nd_write_int(Players[Player_num].score);
1591 
1592 	for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
1593 		nd_write_short((short)Players[Player_num].primary_ammo[i]);
1594 
1595 	for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
1596 		nd_write_short((short)Players[Player_num].secondary_ammo[i]);
1597 
1598 	nd_write_byte((byte)Players[Player_num].laser_level);
1599 
1600 //  Support for missions added here
1601 
1602 	nd_write_string(Current_mission_filename);
1603 
1604 	nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
1605 	nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
1606 	nd_write_int(Players[Player_num].flags);        // be sure players flags are set
1607 	nd_write_byte((byte)Primary_weapon);
1608 	nd_write_byte((byte)Secondary_weapon);
1609 	Newdemo_start_frame = FrameCount;
1610 	JustStartedRecording=1;
1611 
1612 	newdemo_set_new_level(Current_level_num);
1613 	start_time();
1614 
1615 }
1616 
newdemo_record_start_frame(int frame_number,fix frame_time)1617 void newdemo_record_start_frame(int frame_number, fix frame_time )
1618 {
1619 	int i;
1620 
1621 	if (Newdemo_no_space) {
1622 		newdemo_stop_playback();
1623 		return;
1624 	}
1625 
1626 	stop_time();
1627 
1628 	for (i=0;i<MAX_OBJECTS;i++)
1629 	{
1630 		WasRecorded[i]=0;
1631 		ViewWasRecorded[i]=0;
1632 	}
1633 	for (i=0;i<32;i++)
1634 		RenderingWasRecorded[i]=0;
1635 
1636 	frame_number -= Newdemo_start_frame;
1637 
1638 	Assert(frame_number >= 0 );
1639 
1640 	nd_write_byte(ND_EVENT_START_FRAME);
1641 	nd_write_short(frame_bytes_written - 1);        // from previous frame
1642 	frame_bytes_written=3;
1643 	nd_write_int(frame_number);
1644 	nd_write_int(frame_time);
1645 	start_time();
1646 
1647 }
1648 
newdemo_record_render_object(object * obj)1649 void newdemo_record_render_object(object * obj)
1650 {
1651 	if (ViewWasRecorded[obj-Objects])
1652 		return;
1653 
1654 	//if (obj==&Objects[Players[Player_num].objnum] && !Player_is_dead)
1655 	//	return;
1656 
1657 	stop_time();
1658 	nd_write_byte(ND_EVENT_RENDER_OBJECT);
1659 	nd_write_object(obj);
1660 	start_time();
1661 }
1662 
1663 extern ubyte RenderingType;
1664 
newdemo_record_viewer_object(object * obj)1665 void newdemo_record_viewer_object(object * obj)
1666 {
1667 
1668 	if (ViewWasRecorded[obj-Objects] && (ViewWasRecorded[obj-Objects]-1)==RenderingType)
1669 		return;
1670 	//if (WasRecorded[obj-Objects])
1671 	//	return;
1672 	if (RenderingWasRecorded[RenderingType])
1673 		return;
1674 
1675 	ViewWasRecorded[obj-Objects]=RenderingType+1;
1676 	RenderingWasRecorded[RenderingType]=1;
1677 	stop_time();
1678 	nd_write_byte(ND_EVENT_VIEWER_OBJECT);
1679 	nd_write_byte(RenderingType);
1680 	nd_write_object(obj);
1681 	start_time();
1682 }
1683 
newdemo_record_sound(int soundno)1684 void newdemo_record_sound( int soundno )
1685 {
1686 	stop_time();
1687 	nd_write_byte(ND_EVENT_SOUND);
1688 	nd_write_int( soundno );
1689 	start_time();
1690 }
1691 
1692 //--unused-- void newdemo_record_sound_once( int soundno ) {
1693 //--unused-- 	stop_time();
1694 //--unused-- 	nd_write_byte( ND_EVENT_SOUND_ONCE );
1695 //--unused-- 	nd_write_int( soundno );
1696 //--unused-- 	start_time();
1697 //--unused-- }
1698 //--unused--
1699 
newdemo_record_cockpit_change(int mode)1700 void newdemo_record_cockpit_change (int mode)
1701 {
1702 	stop_time();
1703 	nd_write_byte (ND_EVENT_CHANGE_COCKPIT);
1704 	nd_write_int(mode);
1705 	start_time();
1706 }
1707 
1708 
newdemo_record_sound_3d(int soundno,int angle,int volume)1709 void newdemo_record_sound_3d( int soundno, int angle, int volume )
1710 {
1711 	stop_time();
1712 	nd_write_byte( ND_EVENT_SOUND_3D );
1713 	nd_write_int( soundno );
1714 	nd_write_int( angle );
1715 	nd_write_int( volume );
1716 	start_time();
1717 }
1718 
newdemo_record_sound_3d_once(int soundno,int angle,int volume)1719 void newdemo_record_sound_3d_once( int soundno, int angle, int volume )
1720 {
1721 	stop_time();
1722 	nd_write_byte( ND_EVENT_SOUND_3D_ONCE );
1723 	nd_write_int( soundno );
1724 	nd_write_int( angle );
1725 	nd_write_int( volume );
1726 	start_time();
1727 }
1728 
1729 
newdemo_record_link_sound_to_object3(int soundno,short objnum,fix max_volume,fix max_distance,int loop_start,int loop_end)1730 void newdemo_record_link_sound_to_object3( int soundno, short objnum, fix max_volume, fix  max_distance, int loop_start, int loop_end )
1731 {
1732 	stop_time();
1733 	nd_write_byte( ND_EVENT_LINK_SOUND_TO_OBJ );
1734 	nd_write_int( soundno );
1735 	nd_write_int( Objects[objnum].signature );
1736 	nd_write_int( max_volume );
1737 	nd_write_int( max_distance );
1738 	nd_write_int( loop_start );
1739 	nd_write_int( loop_end );
1740 	start_time();
1741 }
1742 
newdemo_record_kill_sound_linked_to_object(int objnum)1743 void newdemo_record_kill_sound_linked_to_object( int objnum )
1744 {
1745 	stop_time();
1746 	nd_write_byte( ND_EVENT_KILL_SOUND_TO_OBJ );
1747 	nd_write_int( Objects[objnum].signature );
1748 	start_time();
1749 }
1750 
1751 
newdemo_record_wall_hit_process(int segnum,int side,int damage,int playernum)1752 void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum )
1753 {
1754 	stop_time();
1755 	//segnum = segnum;
1756 	//side = side;
1757 	//damage = damage;
1758 	//playernum = playernum;
1759 	nd_write_byte( ND_EVENT_WALL_HIT_PROCESS );
1760 	nd_write_int( segnum );
1761 	nd_write_int( side );
1762 	nd_write_int( damage );
1763 	nd_write_int( playernum );
1764 	start_time();
1765 }
1766 
newdemo_record_guided_start()1767 void newdemo_record_guided_start ()
1768 {
1769 	nd_write_byte (ND_EVENT_START_GUIDED);
1770 }
1771 
newdemo_record_guided_end()1772 void newdemo_record_guided_end ()
1773 {
1774 	nd_write_byte (ND_EVENT_END_GUIDED);
1775 }
1776 
newdemo_record_secret_exit_blown(int truth)1777 void newdemo_record_secret_exit_blown(int truth)
1778 {
1779 	stop_time();
1780 	nd_write_byte( ND_EVENT_SECRET_THINGY );
1781 	nd_write_int( truth );
1782 	start_time();
1783 }
1784 
newdemo_record_trigger(int segnum,int side,int objnum,int shot)1785 void newdemo_record_trigger( int segnum, int side, int objnum,int shot )
1786 {
1787 	stop_time();
1788 	nd_write_byte( ND_EVENT_TRIGGER );
1789 	nd_write_int( segnum );
1790 	nd_write_int( side );
1791 	nd_write_int( objnum );
1792 	nd_write_int(shot);
1793 	start_time();
1794 }
1795 
newdemo_record_hostage_rescued(int hostage_number)1796 void newdemo_record_hostage_rescued( int hostage_number ) {
1797 	stop_time();
1798 	nd_write_byte( ND_EVENT_HOSTAGE_RESCUED );
1799 	nd_write_int( hostage_number );
1800 	start_time();
1801 }
1802 
newdemo_record_morph_frame(morph_data * md)1803 void newdemo_record_morph_frame(morph_data *md)
1804 {
1805 	stop_time();
1806 
1807 	nd_write_byte( ND_EVENT_MORPH_FRAME );
1808 #if 0
1809 	newdemo_write( md->morph_vecs, sizeof(md->morph_vecs), 1 );
1810 	newdemo_write( md->submodel_active, sizeof(md->submodel_active), 1 );
1811 	newdemo_write( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 );
1812 #endif
1813 	nd_write_object( md->obj );
1814 	start_time();
1815 }
1816 
newdemo_record_wall_toggle(int segnum,int side)1817 void newdemo_record_wall_toggle( int segnum, int side )
1818 {
1819 	stop_time();
1820 	nd_write_byte( ND_EVENT_WALL_TOGGLE );
1821 	nd_write_int( segnum );
1822 	nd_write_int( side );
1823 	start_time();
1824 }
1825 
newdemo_record_control_center_destroyed()1826 void newdemo_record_control_center_destroyed()
1827 {
1828 	stop_time();
1829 	nd_write_byte( ND_EVENT_CONTROL_CENTER_DESTROYED );
1830 	nd_write_int( Countdown_seconds_left );
1831 	start_time();
1832 }
1833 
newdemo_record_hud_message(char * message)1834 void newdemo_record_hud_message( char * message )
1835 {
1836 	stop_time();
1837 	nd_write_byte( ND_EVENT_HUD_MESSAGE );
1838 	nd_write_string(message);
1839 	start_time();
1840 }
1841 
newdemo_record_palette_effect(short r,short g,short b)1842 void newdemo_record_palette_effect(short r, short g, short b )
1843 {
1844 	stop_time();
1845 	nd_write_byte( ND_EVENT_PALETTE_EFFECT );
1846 	nd_write_short( r );
1847 	nd_write_short( g );
1848 	nd_write_short( b );
1849 	start_time();
1850 }
1851 
newdemo_record_player_energy(int old_energy,int energy)1852 void newdemo_record_player_energy(int old_energy, int energy)
1853 {
1854 	stop_time();
1855 	nd_write_byte( ND_EVENT_PLAYER_ENERGY );
1856 	nd_write_byte((byte) old_energy);
1857 	nd_write_byte((byte) energy);
1858 	start_time();
1859 }
1860 
newdemo_record_player_afterburner(fix old_afterburner,fix afterburner)1861 void newdemo_record_player_afterburner(fix old_afterburner, fix afterburner)
1862 {
1863 	stop_time();
1864 	nd_write_byte( ND_EVENT_PLAYER_AFTERBURNER );
1865 	nd_write_byte((byte) (old_afterburner>>9));
1866 	nd_write_byte((byte) (afterburner>>9));
1867 	start_time();
1868 }
1869 
newdemo_record_player_shields(int old_shield,int shield)1870 void newdemo_record_player_shields(int old_shield, int shield)
1871 {
1872 	stop_time();
1873 	nd_write_byte( ND_EVENT_PLAYER_SHIELD );
1874 	nd_write_byte((byte)old_shield);
1875 	nd_write_byte((byte)shield);
1876 	start_time();
1877 }
1878 
newdemo_record_player_flags(uint oflags,uint flags)1879 void newdemo_record_player_flags(uint oflags, uint flags)
1880 {
1881 	stop_time();
1882 	nd_write_byte( ND_EVENT_PLAYER_FLAGS );
1883 	nd_write_int(((short)oflags << 16) | (short)flags);
1884 	start_time();
1885 }
1886 
newdemo_record_player_weapon(int weapon_type,int weapon_num)1887 void newdemo_record_player_weapon(int weapon_type, int weapon_num)
1888 {
1889 	stop_time();
1890 	nd_write_byte( ND_EVENT_PLAYER_WEAPON );
1891 	nd_write_byte((byte)weapon_type);
1892 	nd_write_byte((byte)weapon_num);
1893 	if (weapon_type)
1894 		nd_write_byte((byte)Secondary_weapon);
1895 	else
1896 		nd_write_byte((byte)Primary_weapon);
1897 	start_time();
1898 }
1899 
newdemo_record_effect_blowup(short segment,int side,vms_vector * pnt)1900 void newdemo_record_effect_blowup(short segment, int side, vms_vector *pnt)
1901 {
1902 	stop_time();
1903 	nd_write_byte (ND_EVENT_EFFECT_BLOWUP);
1904 	nd_write_short(segment);
1905 	nd_write_byte((byte)side);
1906 	nd_write_vector(pnt);
1907 	start_time();
1908 }
1909 
newdemo_record_homing_distance(fix distance)1910 void newdemo_record_homing_distance(fix distance)
1911 {
1912 	stop_time();
1913 	nd_write_byte(ND_EVENT_HOMING_DISTANCE);
1914 	nd_write_short((short)(distance>>16));
1915 	start_time();
1916 }
1917 
newdemo_record_letterbox(void)1918 void newdemo_record_letterbox(void)
1919 {
1920 	stop_time();
1921 	nd_write_byte(ND_EVENT_LETTERBOX);
1922 	start_time();
1923 }
1924 
newdemo_record_rearview(void)1925 void newdemo_record_rearview(void)
1926 {
1927 	stop_time();
1928 	nd_write_byte(ND_EVENT_REARVIEW);
1929 	start_time();
1930 }
1931 
newdemo_record_restore_cockpit(void)1932 void newdemo_record_restore_cockpit(void)
1933 {
1934 	stop_time();
1935 	nd_write_byte(ND_EVENT_RESTORE_COCKPIT);
1936 	start_time();
1937 }
1938 
newdemo_record_restore_rearview(void)1939 void newdemo_record_restore_rearview(void)
1940 {
1941 	stop_time();
1942 	nd_write_byte(ND_EVENT_RESTORE_REARVIEW);
1943 	start_time();
1944 }
1945 
newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)1946 void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1947 {
1948 	stop_time();
1949 	nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM1);
1950 	nd_write_short(seg);
1951 	nd_write_byte(side);
1952 	nd_write_short(cseg);
1953 	nd_write_byte(cside);
1954 	nd_write_short(tmap);
1955 	start_time();
1956 }
1957 
newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)1958 void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1959 {
1960 	stop_time();
1961 	nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM2);
1962 	nd_write_short(seg);
1963 	nd_write_byte(side);
1964 	nd_write_short(cseg);
1965 	nd_write_byte(cside);
1966 	nd_write_short(tmap);
1967 	start_time();
1968 }
1969 
newdemo_record_multi_cloak(int pnum)1970 void newdemo_record_multi_cloak(int pnum)
1971 {
1972 	stop_time();
1973 	nd_write_byte(ND_EVENT_MULTI_CLOAK);
1974 	nd_write_byte((byte)pnum);
1975 	start_time();
1976 }
1977 
newdemo_record_multi_decloak(int pnum)1978 void newdemo_record_multi_decloak(int pnum)
1979 {
1980 	stop_time();
1981 	nd_write_byte(ND_EVENT_MULTI_DECLOAK);
1982 	nd_write_byte((byte)pnum);
1983 	start_time();
1984 }
1985 
newdemo_record_multi_death(int pnum)1986 void newdemo_record_multi_death(int pnum)
1987 {
1988 	stop_time();
1989 	nd_write_byte(ND_EVENT_MULTI_DEATH);
1990 	nd_write_byte((byte)pnum);
1991 	start_time();
1992 }
1993 
newdemo_record_multi_kill(int pnum,byte kill)1994 void newdemo_record_multi_kill(int pnum, byte kill)
1995 {
1996 	stop_time();
1997 	nd_write_byte(ND_EVENT_MULTI_KILL);
1998 	nd_write_byte((byte)pnum);
1999 	nd_write_byte(kill);
2000 	start_time();
2001 }
2002 
newdemo_record_multi_connect(int pnum,int new_player,char * new_callsign)2003 void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign)
2004 {
2005 	stop_time();
2006 	nd_write_byte(ND_EVENT_MULTI_CONNECT);
2007 	nd_write_byte((byte)pnum);
2008 	nd_write_byte((byte)new_player);
2009 	if (!new_player) {
2010 		nd_write_string(Players[pnum].callsign);
2011 		nd_write_int(Players[pnum].net_killed_total);
2012 		nd_write_int(Players[pnum].net_kills_total);
2013 	}
2014 	nd_write_string(new_callsign);
2015 	start_time();
2016 }
2017 
newdemo_record_multi_reconnect(int pnum)2018 void newdemo_record_multi_reconnect(int pnum)
2019 {
2020 	stop_time();
2021 	nd_write_byte(ND_EVENT_MULTI_RECONNECT);
2022 	nd_write_byte((byte)pnum);
2023 	start_time();
2024 }
2025 
newdemo_record_multi_disconnect(int pnum)2026 void newdemo_record_multi_disconnect(int pnum)
2027 {
2028 	stop_time();
2029 	nd_write_byte(ND_EVENT_MULTI_DISCONNECT);
2030 	nd_write_byte((byte)pnum);
2031 	start_time();
2032 }
2033 
newdemo_record_player_score(int score)2034 void newdemo_record_player_score(int score)
2035 {
2036 	stop_time();
2037 	nd_write_byte(ND_EVENT_PLAYER_SCORE);
2038 	nd_write_int(score);
2039 	start_time();
2040 }
2041 
newdemo_record_multi_score(int pnum,int score)2042 void newdemo_record_multi_score(int pnum, int score)
2043 {
2044 	stop_time();
2045 	nd_write_byte(ND_EVENT_MULTI_SCORE);
2046 	nd_write_byte((byte)pnum);
2047 	nd_write_int(score - Players[pnum].score);      // called before score is changed!!!!
2048 	start_time();
2049 }
2050 
newdemo_record_primary_ammo(int old_ammo,int new_ammo)2051 void newdemo_record_primary_ammo(int old_ammo, int new_ammo)
2052 {
2053 	stop_time();
2054 	nd_write_byte(ND_EVENT_PRIMARY_AMMO);
2055 	if (old_ammo < 0)
2056 		nd_write_short((short)new_ammo);
2057 	else
2058 		nd_write_short((short)old_ammo);
2059 	nd_write_short((short)new_ammo);
2060 	start_time();
2061 }
2062 
newdemo_record_secondary_ammo(int old_ammo,int new_ammo)2063 void newdemo_record_secondary_ammo(int old_ammo, int new_ammo)
2064 {
2065 	stop_time();
2066 	nd_write_byte(ND_EVENT_SECONDARY_AMMO);
2067 	if (old_ammo < 0)
2068 		nd_write_short((short)new_ammo);
2069 	else
2070 		nd_write_short((short)old_ammo);
2071 	nd_write_short((short)new_ammo);
2072 	start_time();
2073 }
2074 
newdemo_record_door_opening(int segnum,int side)2075 void newdemo_record_door_opening(int segnum, int side)
2076 {
2077 	stop_time();
2078 	nd_write_byte(ND_EVENT_DOOR_OPENING);
2079 	nd_write_short((short)segnum);
2080 	nd_write_byte((byte)side);
2081 	start_time();
2082 }
2083 
newdemo_record_laser_level(byte old_level,byte new_level)2084 void newdemo_record_laser_level(byte old_level, byte new_level)
2085 {
2086 	stop_time();
2087 	nd_write_byte(ND_EVENT_LASER_LEVEL);
2088 	nd_write_byte(old_level);
2089 	nd_write_byte(new_level);
2090 	start_time();
2091 }
2092 
newdemo_record_cloaking_wall(int front_wall_num,int back_wall_num,ubyte type,ubyte state,fix cloak_value,fix l0,fix l1,fix l2,fix l3)2093 void newdemo_record_cloaking_wall(int front_wall_num, int back_wall_num, ubyte type, ubyte state, fix cloak_value, fix l0, fix l1, fix l2, fix l3)
2094 {
2095 	Assert(front_wall_num <= 255 && back_wall_num <= 255);
2096 
2097 	stop_time();
2098 	nd_write_byte(ND_EVENT_CLOAKING_WALL);
2099 	nd_write_byte(front_wall_num);
2100 	nd_write_byte(back_wall_num);
2101 	nd_write_byte(type);
2102 	nd_write_byte(state);
2103 	nd_write_byte(cloak_value);
2104 	nd_write_short(l0>>8);
2105 	nd_write_short(l1>>8);
2106 	nd_write_short(l2>>8);
2107 	nd_write_short(l3>>8);
2108 	start_time();
2109 }
2110 
newdemo_set_new_level(int level_num)2111 void newdemo_set_new_level(int level_num)
2112 {
2113 	int i;
2114 	int side;
2115 	segment *seg;
2116 
2117 	stop_time();
2118 	nd_write_byte(ND_EVENT_NEW_LEVEL);
2119 	nd_write_byte((byte)level_num);
2120 	nd_write_byte((byte)Current_level_num);
2121 
2122 	if (JustStartedRecording==1)
2123 	{
2124 		nd_write_int(Num_walls);
2125 		for (i=0;i<Num_walls;i++)
2126 		{
2127 			nd_write_byte (Walls[i].type);
2128 			nd_write_byte (Walls[i].flags);
2129 			nd_write_byte (Walls[i].state);
2130 
2131 			seg = &Segments[Walls[i].segnum];
2132 			side = Walls[i].sidenum;
2133 			nd_write_short (seg->sides[side].tmap_num);
2134 			nd_write_short (seg->sides[side].tmap_num2);
2135 			JustStartedRecording=0;
2136 		}
2137 	}
2138 
2139 	start_time();
2140 }
2141 
newdemo_read_demo_start(int rnd_demo)2142 int newdemo_read_demo_start(int rnd_demo)
2143 {
2144 	byte i, version, game_type, laser_level;
2145 	char c, energy, shield;
2146 	char text[50], current_mission[9];
2147 
2148 	nd_read_byte(&c);
2149 	if ((c != ND_EVENT_START_DEMO) || nd_bad_read) {
2150 		newmenu_item m[1];
2151 
2152 		sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_CORRUPT);
2153 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2154 		newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2155 		return 1;
2156 	}
2157 	nd_read_byte(&version);
2158 	nd_read_byte(&game_type);
2159 	if (game_type < DEMO_GAME_TYPE) {
2160 		newmenu_item m[2];
2161 
2162 		sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
2163 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2164 		m[ 1].type = NM_TYPE_TEXT; m[ 1].text = "    In Descent: First Strike";
2165 
2166 		newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2167 		return 1;
2168 	}
2169 	if (game_type != DEMO_GAME_TYPE) {
2170 		newmenu_item m[2];
2171 
2172 		sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
2173 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2174 		m[ 1].type = NM_TYPE_TEXT; m[ 1].text = "   In Unknown Descent version";
2175 
2176 		newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2177 		return 1;
2178 	}
2179 	if (version < DEMO_VERSION) {
2180 		if (!rnd_demo) {
2181 			newmenu_item m[1];
2182 			sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD);
2183 			m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2184 			newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2185 		}
2186 		return 1;
2187 	}
2188 	nd_read_fix(&GameTime);
2189 	Boss_cloak_start_time=Boss_cloak_end_time=GameTime;
2190 	JasonPlaybackTotal=0;
2191 
2192 	nd_read_int(&Newdemo_game_mode);
2193 
2194 #ifdef NETWORK
2195 	change_playernum_to((Newdemo_game_mode >> 16) & 0x7);
2196 	if (Newdemo_game_mode & GM_TEAM) {
2197 		nd_read_byte(&(Netgame.team_vector));
2198 		nd_read_string(Netgame.team_name[0]);
2199 		nd_read_string(Netgame.team_name[1]);
2200 	}
2201 	if (Newdemo_game_mode & GM_MULTI) {
2202 
2203 		multi_new_game();
2204 		nd_read_byte(&c);
2205 		N_players = (int)c;
2206 		// changed this to above two lines -- breaks on the mac because of
2207 		// endian issues
2208 		//		nd_read_byte((byte *)&N_players);
2209 		for (i = 0 ; i < N_players; i++) {
2210 			Players[i].cloak_time = 0;
2211 			Players[i].invulnerable_time = 0;
2212 			nd_read_string(Players[i].callsign);
2213 			nd_read_byte(&(Players[i].connected));
2214 
2215 			if (Newdemo_game_mode & GM_MULTI_COOP) {
2216 				nd_read_int(&(Players[i].score));
2217 			} else {
2218 				nd_read_short((short *)&(Players[i].net_killed_total));
2219 				nd_read_short((short *)&(Players[i].net_kills_total));
2220 			}
2221 		}
2222 		Game_mode = Newdemo_game_mode;
2223 		multi_sort_kill_list();
2224 		Game_mode = GM_NORMAL;
2225 	} else
2226 #endif
2227 		nd_read_int(&(Players[Player_num].score));      // Note link to above if!
2228 
2229 	for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
2230 		nd_read_short((short*)&(Players[Player_num].primary_ammo[i]));
2231 
2232 	for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
2233 			nd_read_short((short*)&(Players[Player_num].secondary_ammo[i]));
2234 
2235 	nd_read_byte(&laser_level);
2236 	if (laser_level != Players[Player_num].laser_level) {
2237 		Players[Player_num].laser_level = laser_level;
2238 		update_laser_weapon_info();
2239 	}
2240 
2241 	// Support for missions
2242 
2243 	nd_read_string(current_mission);
2244 	if (!load_mission_by_name(current_mission)) {
2245 		if (!rnd_demo) {
2246 			newmenu_item m[1];
2247 
2248 			sprintf(text, TXT_NOMISSION4DEMO, current_mission);
2249 			m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2250 			newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2251 		}
2252 		return 1;
2253 	}
2254 
2255 	nd_recorded_total = 0;
2256 	nd_playback_total = 0;
2257 	nd_read_byte(&energy);
2258 	nd_read_byte(&shield);
2259 
2260 	nd_read_int((int *)&(Players[Player_num].flags));
2261 	if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
2262 		Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2263 		Newdemo_players_cloaked |= (1 << Player_num);
2264 	}
2265 	if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2266 		Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2267 
2268 	nd_read_byte((byte *)&Primary_weapon);
2269 	nd_read_byte((byte *)&Secondary_weapon);
2270 
2271 	// Next bit of code to fix problem that I introduced between 1.0 and 1.1
2272 	// check the next byte -- it _will_ be a load_new_level event.  If it is
2273 	// not, then we must shift all bytes up by one.
2274 
2275 	Players[Player_num].energy = i2f(energy);
2276 	Players[Player_num].shields = i2f(shield);
2277 	JustStartedPlayback=1;
2278 	return 0;
2279 }
2280 
newdemo_pop_ctrlcen_triggers()2281 void newdemo_pop_ctrlcen_triggers()
2282 {
2283 	int anim_num, n, i;
2284 	int side, cside;
2285 	segment *seg, *csegp;
2286 
2287 	for (i = 0; i < ControlCenterTriggers.num_links; i++) {
2288 		seg = &Segments[ControlCenterTriggers.seg[i]];
2289 		side = ControlCenterTriggers.side[i];
2290 		csegp = &Segments[seg->children[side]];
2291 		cside = find_connect_side(seg, csegp);
2292 		anim_num = Walls[seg->sides[side].wall_num].clip_num;
2293 		n = WallAnims[anim_num].num_frames;
2294 		if (WallAnims[anim_num].flags & WCF_TMAP1) {
2295 		seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[n-1];
2296 		} else {
2297 			seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[n-1];
2298 		}
2299 	}
2300 }
2301 
2302 #define N_PLAYER_SHIP_TEXTURES 6
2303 
2304 void nd_render_extras (ubyte,object *);
2305 extern void multi_apply_goal_textures ();
2306 ubyte Newdemo_flying_guided=0;
2307 
newdemo_read_frame_information()2308 int newdemo_read_frame_information()
2309 {
2310 	int done, segnum, side, objnum, soundno, angle, volume, i,shot;
2311 	object *obj;
2312 	ubyte c,WhichWindow;
2313 	static byte saved_letter_cockpit;
2314 	static byte saved_rearview_cockpit;
2315 	object extraobj;
2316 	static char LastReadValue=101;
2317 	segment *seg;
2318 
2319 	done = 0;
2320 
2321 	if (Newdemo_vcr_state != ND_STATE_PAUSED)
2322 		for (segnum=0; segnum <= Highest_segment_index; segnum++)
2323 			Segments[segnum].objects = -1;
2324 
2325 	reset_objects(1);
2326 	Players[Player_num].homing_object_dist = -F1_0;
2327 
2328 	prev_obj = NULL;
2329 
2330 	while( !done ) {
2331 		nd_read_byte(&c);
2332 		if (nd_bad_read) { done = -1; break; }
2333 
2334 		switch( c ) {
2335 
2336 		case ND_EVENT_START_FRAME: {        // Followed by an integer frame number, then a fix FrameTime
2337 			short last_frame_length;
2338 
2339 			done=1;
2340 			nd_read_short(&last_frame_length);
2341 			nd_read_int(&NewdemoFrameCount);
2342 			nd_read_int((int *)&nd_recorded_time);
2343 			if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2344 				nd_recorded_total += nd_recorded_time;
2345 			NewdemoFrameCount--;
2346 
2347 			if (nd_bad_read) { done = -1; break; }
2348 			break;
2349 		}
2350 
2351 		case ND_EVENT_VIEWER_OBJECT:        // Followed by an object structure
2352 			nd_read_byte (&WhichWindow);
2353 			if (WhichWindow&15)
2354 			{
2355 				//mprintf ((0,"Reading extra!\n"));
2356 				nd_read_object (&extraobj);
2357 				if (Newdemo_vcr_state!=ND_STATE_PAUSED)
2358 				{
2359 					if (nd_bad_read) { done = -1; break; }
2360 
2361 					nd_render_extras (WhichWindow,&extraobj);
2362 				}
2363 			}
2364 			else
2365 			{
2366 				//mprintf ((0,"Reading viewer!\n"));
2367 				//Viewer=&Objects[0];
2368 				nd_read_object(Viewer);
2369 
2370 				if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2371 					if (nd_bad_read) { done = -1; break; }
2372 					segnum = Viewer->segnum;
2373 					Viewer->next = Viewer->prev = Viewer->segnum = -1;
2374 
2375 					// HACK HACK HACK -- since we have multiple level recording, it can be the case
2376 					// HACK HACK HACK -- that when rewinding the demo, the viewer is in a segment
2377 					// HACK HACK HACK -- that is greater than the highest index of segments.  Bash
2378 					// HACK HACK HACK -- the viewer to segment 0 for bogus view.
2379 
2380 					if (segnum > Highest_segment_index)
2381 						segnum = 0;
2382 					obj_link(Viewer-Objects,segnum);
2383 				}
2384 			}
2385 			break;
2386 
2387 		case ND_EVENT_RENDER_OBJECT:       // Followed by an object structure
2388 			objnum = obj_allocate();
2389 			if (objnum==-1)
2390 				break;
2391 			obj = &Objects[objnum];
2392 			nd_read_object(obj);
2393 			if (nd_bad_read) { done = -1; break; }
2394 			if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2395 				segnum = obj->segnum;
2396 				obj->next = obj->prev = obj->segnum = -1;
2397 
2398 				// HACK HACK HACK -- don't render objects is segments greater than Highest_segment_index
2399 				// HACK HACK HACK -- (see above)
2400 
2401 				if (segnum > Highest_segment_index)
2402 					break;
2403 
2404 				obj_link(obj-Objects,segnum);
2405 #ifdef NETWORK
2406 				if ((obj->type == OBJ_PLAYER) && (Newdemo_game_mode & GM_MULTI)) {
2407 					int player;
2408 
2409 					if (Newdemo_game_mode & GM_TEAM)
2410 						player = get_team(obj->id);
2411 					else
2412 						player = obj->id;
2413 					if (player == 0)
2414 						break;
2415 					player--;
2416 
2417 					for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2418 						multi_player_textures[player][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[obj->rtype.pobj_info.model_num].first_texture+i]];
2419 
2420 					multi_player_textures[player][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2]];
2421 					multi_player_textures[player][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2+1]];
2422 					obj->rtype.pobj_info.alt_textures = player+1;
2423 				}
2424 #endif
2425 			}
2426 			break;
2427 
2428 		case ND_EVENT_SOUND:
2429 			nd_read_int(&soundno);
2430 			if (nd_bad_read) {done = -1; break; }
2431 			if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2432 				digi_play_sample( soundno, F1_0 );
2433 			break;
2434 
2435 			//--unused		case ND_EVENT_SOUND_ONCE:
2436 			//--unused			nd_read_int(&soundno);
2437 			//--unused			if (nd_bad_read) { done = -1; break; }
2438 			//--unused			if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2439 			//--unused				digi_play_sample_once( soundno, F1_0 );
2440 			//--unused			break;
2441 
2442 		case ND_EVENT_SOUND_3D:
2443 			nd_read_int(&soundno);
2444 			nd_read_int(&angle);
2445 			nd_read_int(&volume);
2446 			if (nd_bad_read) { done = -1; break; }
2447 			if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2448 				digi_play_sample_3d( soundno, angle, volume, 0 );
2449 			break;
2450 
2451 		case ND_EVENT_SOUND_3D_ONCE:
2452 			nd_read_int(&soundno);
2453 			nd_read_int(&angle);
2454 			nd_read_int(&volume);
2455 			if (nd_bad_read) { done = -1; break; }
2456 			if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2457 				digi_play_sample_3d( soundno, angle, volume, 1 );
2458 			break;
2459 
2460 		case ND_EVENT_LINK_SOUND_TO_OBJ:
2461 			{
2462 				int soundno, objnum, max_volume, max_distance, loop_start, loop_end;
2463 				int signature;
2464 				nd_read_int( &soundno );
2465 				nd_read_int( &signature );
2466 				nd_read_int( &max_volume );
2467 				nd_read_int( &max_distance );
2468 				nd_read_int( &loop_start );
2469 				nd_read_int( &loop_end );
2470 				objnum = newdemo_find_object( signature );
2471 				if ( objnum > -1 )  {   //  @mk, 2/22/96, John told me to.
2472 					digi_link_sound_to_object3( soundno, objnum, 1, max_volume, max_distance, loop_start, loop_end );
2473 				}
2474 			}
2475 			break;
2476 
2477 		case ND_EVENT_KILL_SOUND_TO_OBJ:
2478 			{
2479 				int objnum, signature;
2480 				nd_read_int( &signature );
2481 				objnum = newdemo_find_object( signature );
2482 				if ( objnum > -1 )  {   //  @mk, 2/22/96, John told me to.
2483 					digi_kill_sound_linked_to_object(objnum);
2484 				}
2485 			}
2486 			break;
2487 
2488 		case ND_EVENT_WALL_HIT_PROCESS: {
2489 			int player, segnum;
2490 			fix damage;
2491 
2492 			nd_read_int(&segnum);
2493 			nd_read_int(&side);
2494 			nd_read_fix(&damage);
2495 			nd_read_int(&player);
2496 			if (nd_bad_read) { done = -1; break; }
2497 			if (Newdemo_vcr_state != ND_STATE_PAUSED)
2498 				wall_hit_process(&Segments[segnum], side, damage, player, &(Objects[0]) );
2499 			break;
2500 		}
2501 
2502 		case ND_EVENT_TRIGGER:
2503 			nd_read_int(&segnum);
2504 			nd_read_int(&side);
2505 			nd_read_int(&objnum);
2506 			nd_read_int(&shot);
2507 			if (nd_bad_read) { done = -1; break; }
2508 			if (Newdemo_vcr_state != ND_STATE_PAUSED)
2509 			{
2510 				mprintf ((0,"EVENT TRIGGER! shot=%d\n",shot));
2511 
2512 				if (Triggers[Walls[Segments[segnum].sides[side].wall_num].trigger].type == TT_SECRET_EXIT) {
2513 					int truth;
2514 
2515 					nd_read_byte(&c);
2516 					Assert(c == ND_EVENT_SECRET_THINGY);
2517 					nd_read_int(&truth);
2518 					if (!truth)
2519 						check_trigger(&Segments[segnum], side, objnum,shot);
2520 				} else
2521 					check_trigger(&Segments[segnum], side, objnum,shot);
2522 			}
2523 			break;
2524 
2525 		case ND_EVENT_HOSTAGE_RESCUED: {
2526 			int hostage_number;
2527 
2528 			nd_read_int(&hostage_number);
2529 			if (nd_bad_read) { done = -1; break; }
2530 			if (Newdemo_vcr_state != ND_STATE_PAUSED)
2531 				hostage_rescue( hostage_number );
2532 			break;
2533 		}
2534 
2535 		case ND_EVENT_MORPH_FRAME: {
2536 #if 0
2537 			morph_data *md;
2538 
2539 			md = &morph_objects[0];
2540 			if (newdemo_read( md->morph_vecs, sizeof(md->morph_vecs), 1 )!=1) { done=-1; break; }
2541 			if (newdemo_read( md->submodel_active, sizeof(md->submodel_active), 1 )!=1) { done=-1; break; }
2542 			if (newdemo_read( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 )!=1) { done=-1; break; }
2543 #endif
2544 			objnum = obj_allocate();
2545 			if (objnum==-1)
2546 				break;
2547 			obj = &Objects[objnum];
2548 			nd_read_object(obj);
2549 			obj->render_type = RT_POLYOBJ;
2550 			if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2551 				if (nd_bad_read) { done = -1; break; }
2552 				if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2553 					segnum = obj->segnum;
2554 					obj->next = obj->prev = obj->segnum = -1;
2555 					obj_link(obj-Objects,segnum);
2556 				}
2557 			}
2558 			break;
2559 		}
2560 
2561 		case ND_EVENT_WALL_TOGGLE:
2562 			nd_read_int(&segnum);
2563 			nd_read_int(&side);
2564 			if (nd_bad_read) {done = -1; break; }
2565 			if (Newdemo_vcr_state != ND_STATE_PAUSED)
2566 				wall_toggle(&Segments[segnum], side);
2567 			break;
2568 
2569 		case ND_EVENT_CONTROL_CENTER_DESTROYED:
2570 			nd_read_int(&Countdown_seconds_left);
2571 			Control_center_destroyed = 1;
2572 			if (nd_bad_read) { done = -1; break; }
2573 			if (!Newdemo_cntrlcen_destroyed) {
2574 				newdemo_pop_ctrlcen_triggers();
2575 				Newdemo_cntrlcen_destroyed = 1;
2576 				//do_controlcen_destroyed_stuff(NULL);
2577 			}
2578 			break;
2579 
2580 		case ND_EVENT_HUD_MESSAGE: {
2581 			char hud_msg[60];
2582 
2583 			nd_read_string(&(hud_msg[0]));
2584 			if (nd_bad_read) { done = -1; break; }
2585 			HUD_init_message( hud_msg );
2586 			break;
2587 			}
2588 		case ND_EVENT_START_GUIDED:
2589 			Newdemo_flying_guided=1;
2590 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2591 				Newdemo_flying_guided=0;
2592 			break;
2593 		case ND_EVENT_END_GUIDED:
2594 			Newdemo_flying_guided=0;
2595 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2596 				Newdemo_flying_guided=1;
2597 			break;
2598 
2599 		case ND_EVENT_PALETTE_EFFECT: {
2600 			short r, g, b;
2601 
2602 			nd_read_short(&r);
2603 			nd_read_short(&g);
2604 			nd_read_short(&b);
2605 			if (nd_bad_read) { done = -1; break; }
2606 			PALETTE_FLASH_SET(r,g,b);
2607 			break;
2608 		}
2609 
2610 		case ND_EVENT_PLAYER_ENERGY: {
2611 			ubyte energy;
2612 			ubyte old_energy;
2613 
2614 			nd_read_byte(&old_energy);
2615 			nd_read_byte(&energy);
2616 			if (nd_bad_read) {done = -1; break; }
2617 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2618 				Players[Player_num].energy = i2f(energy);
2619 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2620 				if (old_energy != 255)
2621 					Players[Player_num].energy = i2f(old_energy);
2622 			}
2623 			break;
2624 		}
2625 
2626 		case ND_EVENT_PLAYER_AFTERBURNER: {
2627 			ubyte afterburner;
2628 			ubyte old_afterburner;
2629 
2630 			nd_read_byte(&old_afterburner);
2631 			nd_read_byte(&afterburner);
2632 			if (nd_bad_read) {done = -1; break; }
2633 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2634 				Afterburner_charge = afterburner<<9;
2635 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2636 				if (old_afterburner != 255)
2637 					Afterburner_charge = old_afterburner<<9;
2638 			}
2639 			break;
2640 		}
2641 
2642 		case ND_EVENT_PLAYER_SHIELD: {
2643 			ubyte shield;
2644 			ubyte old_shield;
2645 
2646 			nd_read_byte(&old_shield);
2647 			nd_read_byte(&shield);
2648 			if (nd_bad_read) {done = -1; break; }
2649 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2650 				Players[Player_num].shields = i2f(shield);
2651 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2652 				if (old_shield != 255)
2653 					Players[Player_num].shields = i2f(old_shield);
2654 			}
2655 			break;
2656 		}
2657 
2658 		case ND_EVENT_PLAYER_FLAGS: {
2659 			uint oflags;
2660 
2661 			nd_read_int((int *)&(Players[Player_num].flags));
2662 			if (nd_bad_read) {done = -1; break; }
2663 
2664 			oflags = Players[Player_num].flags >> 16;
2665 			Players[Player_num].flags &= 0xffff;
2666 
2667 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || ((Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) && (oflags != 0xffff)) ) {
2668 				if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2669 					Players[Player_num].cloak_time = 0;
2670 					Newdemo_players_cloaked &= ~(1 << Player_num);
2671 				}
2672 				if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2673 					Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2674 					Newdemo_players_cloaked |= (1 << Player_num);
2675 				}
2676 				if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2677 					Players[Player_num].invulnerable_time = 0;
2678 				if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2679 					Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2680 				Players[Player_num].flags = oflags;
2681 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2682 				if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2683 					Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2684 					Newdemo_players_cloaked |= (1 << Player_num);
2685 				}
2686 				if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2687 					Players[Player_num].cloak_time = 0;
2688 					Newdemo_players_cloaked &= ~(1 << Player_num);
2689 				}
2690 				if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2691 					Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2692 				if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2693 					Players[Player_num].invulnerable_time = 0;
2694 			}
2695 			update_laser_weapon_info();     // in case of quad laser change
2696 			break;
2697 		}
2698 
2699 		case ND_EVENT_PLAYER_WEAPON: {
2700 			byte weapon_type, weapon_num;
2701 			byte old_weapon;
2702 
2703 			nd_read_byte(&weapon_type);
2704 			nd_read_byte(&weapon_num);
2705 			nd_read_byte(&old_weapon);
2706 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2707 				if (weapon_type == 0)
2708 					Primary_weapon = (int)weapon_num;
2709 				else
2710 					Secondary_weapon = (int)weapon_num;
2711 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2712 				if (weapon_type == 0)
2713 					Primary_weapon = (int)old_weapon;
2714 				else
2715 					Secondary_weapon = (int)old_weapon;
2716 			}
2717 			break;
2718 		}
2719 
2720 		case ND_EVENT_EFFECT_BLOWUP: {
2721 			short segnum;
2722 			byte side;
2723 			vms_vector pnt;
2724 			object dummy;
2725 
2726 			//create a dummy object which will be the weapon that hits
2727 			//the monitor. the blowup code wants to know who the parent of the
2728 			//laser is, so create a laser whose parent is the player
2729 			dummy.ctype.laser_info.parent_type = OBJ_PLAYER;
2730 
2731 			nd_read_short(&segnum);
2732 			nd_read_byte(&side);
2733 			nd_read_vector(&pnt);
2734 			if (Newdemo_vcr_state != ND_STATE_PAUSED)
2735 				check_effect_blowup(&(Segments[segnum]), side, &pnt, &dummy, 0);
2736 			break;
2737 		}
2738 
2739 		case ND_EVENT_HOMING_DISTANCE: {
2740 			short distance;
2741 
2742 			nd_read_short(&distance);
2743 			Players[Player_num].homing_object_dist = i2f((int)(distance << 16));
2744 			break;
2745 		}
2746 
2747 		case ND_EVENT_LETTERBOX:
2748 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2749 				saved_letter_cockpit = Cockpit_mode;
2750 				select_cockpit(CM_LETTERBOX);
2751 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2752 				select_cockpit(saved_letter_cockpit);
2753 			break;
2754 
2755 		case ND_EVENT_CHANGE_COCKPIT: {
2756 			int dummy;
2757 
2758 			nd_read_int (&dummy);
2759 			select_cockpit (dummy);
2760 
2761 			break;
2762 		}
2763 		case ND_EVENT_REARVIEW:
2764 			if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2765 				saved_rearview_cockpit = Cockpit_mode;
2766 				if (Cockpit_mode == CM_FULL_COCKPIT)
2767 					select_cockpit(CM_REAR_VIEW);
2768 				Rear_view=1;
2769 			} else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2770 				if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
2771 					saved_rearview_cockpit = CM_FULL_COCKPIT;
2772 				select_cockpit(saved_rearview_cockpit);
2773 				Rear_view=0;
2774 			}
2775 			break;
2776 
2777 		case ND_EVENT_RESTORE_COCKPIT:
2778 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2779 				saved_letter_cockpit = Cockpit_mode;
2780 				select_cockpit(CM_LETTERBOX);
2781 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2782 				select_cockpit(saved_letter_cockpit);
2783 			break;
2784 
2785 
2786 		case ND_EVENT_RESTORE_REARVIEW:
2787 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2788 				saved_rearview_cockpit = Cockpit_mode;
2789 				if (Cockpit_mode == CM_FULL_COCKPIT)
2790 					select_cockpit(CM_REAR_VIEW);
2791 				Rear_view=1;
2792 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2793 				if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
2794 					saved_rearview_cockpit = CM_FULL_COCKPIT;
2795 				select_cockpit(saved_rearview_cockpit);
2796 				Rear_view=0;
2797 			}
2798 			break;
2799 
2800 
2801 		case ND_EVENT_WALL_SET_TMAP_NUM1: {
2802 			short seg, cseg, tmap;
2803 			ubyte side,cside;
2804 
2805 			nd_read_short(&seg);
2806 			nd_read_byte(&side);
2807 			nd_read_short(&cseg);
2808 			nd_read_byte(&cside);
2809 			nd_read_short( &tmap );
2810 			if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD))
2811 				Segments[seg].sides[side].tmap_num = Segments[cseg].sides[cside].tmap_num = tmap;
2812 			break;
2813 		}
2814 
2815 		case ND_EVENT_WALL_SET_TMAP_NUM2: {
2816 			short seg, cseg, tmap;
2817 			ubyte side,cside;
2818 
2819 			nd_read_short(&seg);
2820 			nd_read_byte(&side);
2821 			nd_read_short(&cseg);
2822 			nd_read_byte(&cside);
2823 			nd_read_short( &tmap );
2824 			if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) {
2825 				Assert(tmap!=0 && Segments[seg].sides[side].tmap_num2!=0);
2826 				Segments[seg].sides[side].tmap_num2 = Segments[cseg].sides[cside].tmap_num2 = tmap;
2827 			}
2828 			break;
2829 		}
2830 
2831 		case ND_EVENT_MULTI_CLOAK: {
2832 			byte pnum;
2833 
2834 			nd_read_byte(&pnum);
2835 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2836 				Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2837 				Players[pnum].cloak_time = 0;
2838 				Newdemo_players_cloaked &= ~(1 << pnum);
2839 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2840 				Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2841 				Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
2842 				Newdemo_players_cloaked |= (1 << pnum);
2843 			}
2844 			break;
2845 		}
2846 
2847 		case ND_EVENT_MULTI_DECLOAK: {
2848 			byte pnum;
2849 
2850 			nd_read_byte(&pnum);
2851 
2852 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2853 				Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2854 				Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
2855 				Newdemo_players_cloaked |= (1 << pnum);
2856 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2857 				Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2858 				Players[pnum].cloak_time = 0;
2859 				Newdemo_players_cloaked &= ~(1 << pnum);
2860 			}
2861 			break;
2862 		}
2863 
2864 		case ND_EVENT_MULTI_DEATH: {
2865 			byte pnum;
2866 
2867 			nd_read_byte(&pnum);
2868 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2869 				Players[pnum].net_killed_total--;
2870 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2871 				Players[pnum].net_killed_total++;
2872 			break;
2873 		}
2874 
2875 #ifdef NETWORK
2876 		case ND_EVENT_MULTI_KILL: {
2877 			byte pnum, kill;
2878 
2879 			nd_read_byte(&pnum);
2880 			nd_read_byte(&kill);
2881 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2882 				Players[pnum].net_kills_total -= kill;
2883 				if (Newdemo_game_mode & GM_TEAM)
2884 					team_kills[get_team(pnum)] -= kill;
2885 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2886 				Players[pnum].net_kills_total += kill;
2887 				if (Newdemo_game_mode & GM_TEAM)
2888 					team_kills[get_team(pnum)] += kill;
2889 			}
2890 			Game_mode = Newdemo_game_mode;
2891 			multi_sort_kill_list();
2892 			Game_mode = GM_NORMAL;
2893 			break;
2894 		}
2895 
2896 		case ND_EVENT_MULTI_CONNECT: {
2897 			byte pnum, new_player;
2898 			int killed_total, kills_total;
2899 			char new_callsign[CALLSIGN_LEN+1], old_callsign[CALLSIGN_LEN+1];
2900 
2901 			nd_read_byte(&pnum);
2902 			nd_read_byte(&new_player);
2903 			if (!new_player) {
2904 				nd_read_string(old_callsign);
2905 				nd_read_int(&killed_total);
2906 				nd_read_int(&kills_total);
2907 			}
2908 			nd_read_string(new_callsign);
2909 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2910 				Players[pnum].connected = 0;
2911 				if (!new_player) {
2912 					memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
2913 					Players[pnum].net_killed_total = killed_total;
2914 					Players[pnum].net_kills_total = kills_total;
2915 				} else {
2916 					N_players--;
2917 				}
2918 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2919 				Players[pnum].connected = 1;
2920 				Players[pnum].net_kills_total = 0;
2921 				Players[pnum].net_killed_total = 0;
2922 				memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
2923 				if (new_player)
2924 					N_players++;
2925 			}
2926 			break;
2927 		}
2928 
2929 		case ND_EVENT_MULTI_RECONNECT: {
2930 			byte pnum;
2931 
2932 			nd_read_byte(&pnum);
2933 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2934 				Players[pnum].connected = 0;
2935 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2936 				Players[pnum].connected = 1;
2937 			break;
2938 		}
2939 
2940 		case ND_EVENT_MULTI_DISCONNECT: {
2941 			byte pnum;
2942 
2943 			nd_read_byte(&pnum);
2944 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2945 				Players[pnum].connected = 1;
2946 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2947 				Players[pnum].connected = 0;
2948 			break;
2949 		}
2950 
2951 		case ND_EVENT_MULTI_SCORE: {
2952 			int score;
2953 			byte pnum;
2954 
2955 			nd_read_byte(&pnum);
2956 			nd_read_int(&score);
2957 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2958 				Players[pnum].score -= score;
2959 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2960 				Players[pnum].score += score;
2961 			Game_mode = Newdemo_game_mode;
2962 			multi_sort_kill_list();
2963 			Game_mode = GM_NORMAL;
2964 			break;
2965 		}
2966 
2967 #endif // NETWORK
2968 		case ND_EVENT_PLAYER_SCORE: {
2969 			int score;
2970 
2971 			nd_read_int(&score);
2972 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2973 				Players[Player_num].score -= score;
2974 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2975 				Players[Player_num].score += score;
2976 			break;
2977 		}
2978 
2979 
2980 		case ND_EVENT_PRIMARY_AMMO: {
2981 			short old_ammo, new_ammo;
2982 
2983 			nd_read_short(&old_ammo);
2984 			nd_read_short(&new_ammo);
2985 
2986 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2987 				Players[Player_num].primary_ammo[Primary_weapon] = old_ammo;
2988 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2989 				Players[Player_num].primary_ammo[Primary_weapon] = new_ammo;
2990 			break;
2991 		}
2992 
2993 		case ND_EVENT_SECONDARY_AMMO: {
2994 			short old_ammo, new_ammo;
2995 
2996 			nd_read_short(&old_ammo);
2997 			nd_read_short(&new_ammo);
2998 
2999 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3000 				Players[Player_num].secondary_ammo[Secondary_weapon] = old_ammo;
3001 			else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
3002 				Players[Player_num].secondary_ammo[Secondary_weapon] = new_ammo;
3003 			break;
3004 		}
3005 
3006 		case ND_EVENT_DOOR_OPENING: {
3007 			short segnum;
3008 			byte side;
3009 
3010 			nd_read_short(&segnum);
3011 			nd_read_byte(&side);
3012 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
3013 				int anim_num;
3014 				int cside;
3015 				segment *segp, *csegp;
3016 
3017 				segp = &Segments[segnum];
3018 				csegp = &Segments[segp->children[side]];
3019 				cside = find_connect_side(segp, csegp);
3020 				anim_num = Walls[segp->sides[side].wall_num].clip_num;
3021 
3022 				if (WallAnims[anim_num].flags & WCF_TMAP1) {
3023 					segp->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[0];
3024 				} else {
3025 					segp->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[0];
3026 				}
3027 			}
3028 			break;
3029 		}
3030 
3031 		case ND_EVENT_LASER_LEVEL: {
3032 			byte old_level, new_level;
3033 
3034 			nd_read_byte(&old_level);
3035 			nd_read_byte(&new_level);
3036 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
3037 				Players[Player_num].laser_level = old_level;
3038 				update_laser_weapon_info();
3039 			} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
3040 				Players[Player_num].laser_level = new_level;
3041 				update_laser_weapon_info();
3042 			}
3043 			break;
3044 		}
3045 
3046 		case ND_EVENT_CLOAKING_WALL: {
3047 			ubyte back_wall_num,front_wall_num,type,state,cloak_value;
3048 			short l0,l1,l2,l3;
3049 			segment *segp;
3050 			int sidenum;
3051 
3052 			nd_read_byte(&front_wall_num);
3053 			nd_read_byte(&back_wall_num);
3054 			nd_read_byte(&type);
3055 			nd_read_byte(&state);
3056 			nd_read_byte(&cloak_value);
3057 			nd_read_short(&l0);
3058 			nd_read_short(&l1);
3059 			nd_read_short(&l2);
3060 			nd_read_short(&l3);
3061 
3062 			Walls[front_wall_num].type = type;
3063 			Walls[front_wall_num].state = state;
3064 			Walls[front_wall_num].cloak_value = cloak_value;
3065 			segp = &Segments[Walls[front_wall_num].segnum];
3066 			sidenum = Walls[front_wall_num].sidenum;
3067 			segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
3068 			segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
3069 			segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
3070 			segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
3071 
3072 			Walls[back_wall_num].type = type;
3073 			Walls[back_wall_num].state = state;
3074 			Walls[back_wall_num].cloak_value = cloak_value;
3075 			segp = &Segments[Walls[back_wall_num].segnum];
3076 			sidenum = Walls[back_wall_num].sidenum;
3077 			segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
3078 			segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
3079 			segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
3080 			segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
3081 
3082 			break;
3083 		}
3084 
3085 		case ND_EVENT_NEW_LEVEL: {
3086 			byte new_level, old_level, loaded_level;
3087 
3088 			nd_read_byte (&new_level);
3089 			nd_read_byte (&old_level);
3090 			if (Newdemo_vcr_state == ND_STATE_PAUSED)
3091 				break;
3092 
3093 			stop_time();
3094 			if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3095 				loaded_level = old_level;
3096 			else {
3097 				loaded_level = new_level;
3098 				for (i = 0; i < MAX_PLAYERS; i++) {
3099 					Players[i].cloak_time = 0;
3100 					Players[i].flags &= ~PLAYER_FLAGS_CLOAKED;
3101 				}
3102 			}
3103 			if ((loaded_level < Last_secret_level) || (loaded_level > Last_level)) {
3104 				newmenu_item m[3];
3105 
3106 				m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
3107 				m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
3108 				m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
3109 				newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3110 				return -1;
3111 			}
3112 
3113 			LoadLevel((int)loaded_level,1);
3114 			Newdemo_cntrlcen_destroyed = 0;
3115 
3116 			if (JustStartedPlayback)
3117 			{
3118 				nd_read_int (&Num_walls);
3119 				for (i=0;i<Num_walls;i++)    // restore the walls
3120 				{
3121 					nd_read_byte (&Walls[i].type);
3122 					nd_read_byte (&Walls[i].flags);
3123 					nd_read_byte (&Walls[i].state);
3124 
3125 					seg = &Segments[Walls[i].segnum];
3126 					side = Walls[i].sidenum;
3127 					nd_read_short (&seg->sides[side].tmap_num);
3128 					nd_read_short (&seg->sides[side].tmap_num2);
3129 				}
3130 #ifdef NETWORK
3131 				if (Newdemo_game_mode & GM_CAPTURE)
3132 					multi_apply_goal_textures ();
3133 #endif
3134 				JustStartedPlayback=0;
3135 			}
3136 
3137 
3138 			// so says Rob H.!!!			if (Newdemo_game_mode & GM_MULTI) {
3139 			// so says Rob H.!!!				for (i = 0; i < Num_walls; i++) {
3140 			// so says Rob H.!!!					if (Walls[i].type == WALL_BLASTABLE)
3141 			// so says Rob H.!!!					{
3142 			// so says Rob H.!!!						int a, n;
3143 			// so says Rob H.!!!						int side;
3144 			// so says Rob H.!!!						segment *seg;
3145 			// so says Rob H.!!!
3146 			// so says Rob H.!!!						seg = &Segments[Walls[i].segnum];
3147 			// so says Rob H.!!!						side = Walls[i].sidenum;
3148 			// so says Rob H.!!!						a = Walls[i].clip_num;
3149 			// so says Rob H.!!!						n = WallAnims[a].num_frames;
3150 			// so says Rob H.!!!						seg->sides[side].tmap_num = WallAnims[a].frames[n-1];
3151 			// so says Rob H.!!!						Walls[i].flags |= WALL_BLASTED;
3152 			// so says Rob H.!!!					}
3153 			// so says Rob H.!!!				}
3154 			// so says Rob H.!!!			}
3155 
3156 			reset_palette_add();                // get palette back to normal
3157 			start_time();
3158 			break;
3159 		}
3160 
3161 		case ND_EVENT_EOF: {
3162 			done=-1;
3163 			fseek(infile, -1, SEEK_CUR);        // get back to the EOF marker
3164 			Newdemo_at_eof = 1;
3165 			NewdemoFrameCount++;
3166 			break;
3167 		}
3168 
3169 		default:
3170 			Int3();
3171 		}
3172 	}
3173 
3174 	LastReadValue=c;
3175 
3176 	if (nd_bad_read) {
3177 		newmenu_item m[2];
3178 
3179 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_ERR_READING;
3180 		m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_DEMO_OLD_CORRUPT;
3181 		newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3182 	}
3183 
3184 	return done;
3185 }
3186 
newdemo_goto_beginning()3187 void newdemo_goto_beginning()
3188 {
3189 	//if (NewdemoFrameCount == 0)
3190 	//	return;
3191 	fseek(infile, 0, SEEK_SET);
3192 	Newdemo_vcr_state = ND_STATE_PLAYBACK;
3193 	if (newdemo_read_demo_start(0))
3194 		newdemo_stop_playback();
3195 	if (newdemo_read_frame_information() == -1)
3196 		newdemo_stop_playback();
3197 	if (newdemo_read_frame_information() == -1)
3198 		newdemo_stop_playback();
3199 	Newdemo_vcr_state = ND_STATE_PAUSED;
3200 	Newdemo_at_eof = 0;
3201 }
3202 
newdemo_goto_end()3203 void newdemo_goto_end()
3204 {
3205 	short frame_length, byte_count, bshort;
3206 	byte level, bbyte, laser_level;
3207 	ubyte energy, shield, c;
3208 	int i, loc, bint;
3209 
3210 	fseek(infile, -2, SEEK_END);
3211 	nd_read_byte(&level);
3212 
3213 	if ((level < Last_secret_level) || (level > Last_level)) {
3214 		newmenu_item m[3];
3215 
3216 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
3217 		m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
3218 		m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
3219 		newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3220 		newdemo_stop_playback();
3221 		return;
3222 	}
3223 	if (level != Current_level_num)
3224 		LoadLevel(level,1);
3225 
3226 	fseek(infile, -4, SEEK_END);
3227 	nd_read_short(&byte_count);
3228 	fseek(infile, -2 - byte_count, SEEK_CUR);
3229 
3230 	nd_read_short(&frame_length);
3231 	loc = ftell(infile);
3232 	if (Newdemo_game_mode & GM_MULTI)
3233 		nd_read_byte(&Newdemo_players_cloaked);
3234 	else
3235 		nd_read_byte(&bbyte);
3236 	nd_read_byte(&bbyte);
3237 	nd_read_short(&bshort);
3238 	nd_read_int(&bint);
3239 
3240 	nd_read_byte(&energy);
3241 	nd_read_byte(&shield);
3242 	Players[Player_num].energy = i2f(energy);
3243 	Players[Player_num].shields = i2f(shield);
3244 	nd_read_int((int *)&(Players[Player_num].flags));
3245 	if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
3246 		Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
3247 		Newdemo_players_cloaked |= (1 << Player_num);
3248 	}
3249 	if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
3250 		Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
3251 	nd_read_byte((byte *)&Primary_weapon);
3252 	nd_read_byte((byte *)&Secondary_weapon);
3253 	for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3254 		nd_read_short((short *)&(Players[Player_num].primary_ammo[i]));
3255 	for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3256 		nd_read_short((short *)&(Players[Player_num].secondary_ammo[i]));
3257 	nd_read_byte(&laser_level);
3258 	if (laser_level != Players[Player_num].laser_level) {
3259 		Players[Player_num].laser_level = laser_level;
3260 		update_laser_weapon_info();
3261 	}
3262 
3263 	if (Newdemo_game_mode & GM_MULTI) {
3264 		nd_read_byte(&c);
3265 		N_players = (int)c;
3266 		// see newdemo_read_start_demo for explanation of
3267 		// why this is commented out
3268 		//		nd_read_byte((byte *)&N_players);
3269 		for (i = 0; i < N_players; i++) {
3270 			nd_read_string(Players[i].callsign);
3271 			nd_read_byte(&(Players[i].connected));
3272 			if (Newdemo_game_mode & GM_MULTI_COOP) {
3273 				nd_read_int(&(Players[i].score));
3274 			} else {
3275 				nd_read_short((short *)&(Players[i].net_killed_total));
3276 				nd_read_short((short *)&(Players[i].net_kills_total));
3277 			}
3278 		}
3279 	} else {
3280 		nd_read_int(&(Players[Player_num].score));
3281 	}
3282 
3283 	fseek(infile, loc, SEEK_SET);
3284 	fseek(infile, -frame_length, SEEK_CUR);
3285 	nd_read_int(&NewdemoFrameCount);            // get the frame count
3286 	NewdemoFrameCount--;
3287 	fseek(infile, 4, SEEK_CUR);
3288 	Newdemo_vcr_state = ND_STATE_PLAYBACK;
3289 	newdemo_read_frame_information();           // then the frame information
3290 	Newdemo_vcr_state = ND_STATE_PAUSED;
3291 	return;
3292 }
3293 
newdemo_back_frames(int frames)3294 void newdemo_back_frames(int frames)
3295 {
3296 	short last_frame_length;
3297 	int i;
3298 
3299 	for (i = 0; i < frames; i++)
3300 	{
3301 		fseek(infile, -10, SEEK_CUR);
3302 		nd_read_short(&last_frame_length);
3303 		fseek(infile, 8 - last_frame_length, SEEK_CUR);
3304 
3305 		if (!Newdemo_at_eof && newdemo_read_frame_information() == -1) {
3306 			newdemo_stop_playback();
3307 			return;
3308 		}
3309 		if (Newdemo_at_eof)
3310 			Newdemo_at_eof = 0;
3311 
3312 		fseek(infile, -10, SEEK_CUR);
3313 		nd_read_short(&last_frame_length);
3314 		fseek(infile, 8 - last_frame_length, SEEK_CUR);
3315 	}
3316 
3317 }
3318 
3319 /*
3320  *  routine to interpolate the viewer position.  the current position is
3321  *  stored in the Viewer object.  Save this position, and read the next
3322  *  frame to get all objects read in.  Calculate the delta playback and
3323  *  the delta recording frame times between the two frames, then intepolate
3324  *  the viewers position accordingly.  nd_recorded_time is the time that it
3325  *  took the recording to render the frame that we are currently looking
3326  *  at.
3327 */
3328 
interpolate_frame(fix d_play,fix d_recorded)3329 void interpolate_frame(fix d_play, fix d_recorded)
3330 {
3331 	int i, j, num_cur_objs;
3332 	fix factor;
3333 	object *cur_objs;
3334 
3335 	factor = fixdiv(d_play, d_recorded);
3336 	if (factor > F1_0)
3337 		factor = F1_0;
3338 
3339 	num_cur_objs = Highest_object_index;
3340 	cur_objs = (object *)d_malloc(sizeof(object) * (num_cur_objs + 1));
3341 	if (cur_objs == NULL) {
3342 		mprintf((0,"Couldn't get %d bytes for cur_objs in interpolate_frame\n", sizeof(object) * num_cur_objs));
3343 		Int3();
3344 		return;
3345 	}
3346 	for (i = 0; i <= num_cur_objs; i++)
3347 		memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
3348 
3349 	Newdemo_vcr_state = ND_STATE_PAUSED;
3350 	if (newdemo_read_frame_information() == -1) {
3351 		d_free(cur_objs);
3352 		newdemo_stop_playback();
3353 		return;
3354 	}
3355 
3356 	for (i = 0; i <= num_cur_objs; i++) {
3357 		for (j = 0; j <= Highest_object_index; j++) {
3358 			if (cur_objs[i].signature == Objects[j].signature) {
3359 				ubyte render_type = cur_objs[i].render_type;
3360 				//fix delta_p, delta_h, delta_b;
3361 				fix delta_x, delta_y, delta_z;
3362 				//vms_angvec cur_angles, dest_angles;
3363 
3364 				//  Extract the angles from the object orientation matrix.
3365 				//  Some of this code taken from ai_turn_towards_vector
3366 				//  Don't do the interpolation on certain render types which don't use an orientation matrix
3367 
3368 				if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) {
3369 
3370 					vms_vector  fvec1, fvec2, rvec1, rvec2;
3371 					fix         mag1;
3372 
3373 					fvec1 = cur_objs[i].orient.fvec;
3374 					vm_vec_scale(&fvec1, F1_0-factor);
3375 					fvec2 = Objects[j].orient.fvec;
3376 					vm_vec_scale(&fvec2, factor);
3377 					vm_vec_add2(&fvec1, &fvec2);
3378 					mag1 = vm_vec_normalize_quick(&fvec1);
3379 					if (mag1 > F1_0/256) {
3380 						rvec1 = cur_objs[i].orient.rvec;
3381 						vm_vec_scale(&rvec1, F1_0-factor);
3382 						rvec2 = Objects[j].orient.rvec;
3383 						vm_vec_scale(&rvec2, factor);
3384 						vm_vec_add2(&rvec1, &rvec2);
3385 						vm_vec_normalize_quick(&rvec1); // Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1
3386 						vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
3387 					}
3388 
3389 					//--old new way --	vms_vector fvec1, fvec2, rvec1, rvec2;
3390 					//--old new way --
3391 					//--old new way --	fvec1 = cur_objs[i].orient.fvec;
3392 					//--old new way --	vm_vec_scale(&fvec1, F1_0-factor);
3393 					//--old new way --	fvec2 = Objects[j].orient.fvec;
3394 					//--old new way --	vm_vec_scale(&fvec2, factor);
3395 					//--old new way --	vm_vec_add2(&fvec1, &fvec2);
3396 					//--old new way --	vm_vec_normalize_quick(&fvec1);
3397 					//--old new way --
3398 					//--old new way --	rvec1 = cur_objs[i].orient.rvec;
3399 					//--old new way --	vm_vec_scale(&rvec1, F1_0-factor);
3400 					//--old new way --	rvec2 = Objects[j].orient.rvec;
3401 					//--old new way --	vm_vec_scale(&rvec2, factor);
3402 					//--old new way --	vm_vec_add2(&rvec1, &rvec2);
3403 					//--old new way --	vm_vec_normalize_quick(&rvec1);
3404 					//--old new way --
3405 					//--old new way --	vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
3406 
3407 					// -- old fashioned way --					vm_extract_angles_matrix(&cur_angles, &(cur_objs[i].orient));
3408 					// -- old fashioned way --					vm_extract_angles_matrix(&dest_angles, &(Objects[j].orient));
3409 					// -- old fashioned way --
3410 					// -- old fashioned way --					delta_p = (dest_angles.p - cur_angles.p);
3411 					// -- old fashioned way --					delta_h = (dest_angles.h - cur_angles.h);
3412 					// -- old fashioned way --					delta_b = (dest_angles.b - cur_angles.b);
3413 					// -- old fashioned way --
3414 					// -- old fashioned way --					if (delta_p != 0) {
3415 					// -- old fashioned way --						if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
3416 					// -- old fashioned way --						if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
3417 					// -- old fashioned way --						delta_p = fixmul(delta_p, factor);
3418 					// -- old fashioned way --						cur_angles.p += delta_p;
3419 					// -- old fashioned way --					}
3420 					// -- old fashioned way --					if (delta_h != 0) {
3421 					// -- old fashioned way --						if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
3422 					// -- old fashioned way --						if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
3423 					// -- old fashioned way --						delta_h = fixmul(delta_h, factor);
3424 					// -- old fashioned way --						cur_angles.h += delta_h;
3425 					// -- old fashioned way --					}
3426 					// -- old fashioned way --					if (delta_b != 0) {
3427 					// -- old fashioned way --						if (delta_b > F1_0/2) delta_b = dest_angles.b - cur_angles.b - F1_0;
3428 					// -- old fashioned way --						if (delta_b < -F1_0/2) delta_b = dest_angles.b - cur_angles.b + F1_0;
3429 					// -- old fashioned way --						delta_b = fixmul(delta_b, factor);
3430 					// -- old fashioned way --						cur_angles.b += delta_b;
3431 					// -- old fashioned way --					}
3432 				}
3433 
3434 				// Interpolate the object position.  This is just straight linear
3435 				// interpolation.
3436 
3437 				delta_x = Objects[j].pos.x - cur_objs[i].pos.x;
3438 				delta_y = Objects[j].pos.y - cur_objs[i].pos.y;
3439 				delta_z = Objects[j].pos.z - cur_objs[i].pos.z;
3440 
3441 				delta_x = fixmul(delta_x, factor);
3442 				delta_y = fixmul(delta_y, factor);
3443 				delta_z = fixmul(delta_z, factor);
3444 
3445 				cur_objs[i].pos.x += delta_x;
3446 				cur_objs[i].pos.y += delta_y;
3447 				cur_objs[i].pos.z += delta_z;
3448 
3449 				// -- old fashioned way --// stuff the new angles back into the object structure
3450 				// -- old fashioned way --				vm_angles_2_matrix(&(cur_objs[i].orient), &cur_angles);
3451 			}
3452 		}
3453 	}
3454 
3455 	// get back to original position in the demo file.  Reread the current
3456 	// frame information again to reset all of the object stuff not covered
3457 	// with Highest_object_index and the object array (previously rendered
3458 	// objects, etc....)
3459 
3460 	newdemo_back_frames(1);
3461 	newdemo_back_frames(1);
3462 	if (newdemo_read_frame_information() == -1)
3463 		newdemo_stop_playback();
3464 	Newdemo_vcr_state = ND_STATE_PLAYBACK;
3465 
3466 	for (i = 0; i <= num_cur_objs; i++)
3467 		memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object));
3468 	Highest_object_index = num_cur_objs;
3469 	d_free(cur_objs);
3470 }
3471 
newdemo_playback_one_frame()3472 void newdemo_playback_one_frame()
3473 {
3474 	int frames_back, i, level;
3475 	static fix base_interpol_time = 0;
3476 	static fix d_recorded = 0;
3477 
3478 	for (i = 0; i < MAX_PLAYERS; i++)
3479 		if (Newdemo_players_cloaked & (1 << i))
3480 			Players[i].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
3481 
3482 	if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
3483 		Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
3484 
3485 	if (Newdemo_vcr_state == ND_STATE_PAUSED)       // render a frame or not
3486 		return;
3487 
3488 	if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
3489 		DoJasonInterpolate(nd_recorded_time);
3490 
3491 	Control_center_destroyed = 0;
3492 	Countdown_seconds_left = -1;
3493 	PALETTE_FLASH_SET(0,0,0);       //clear flash
3494 
3495 	if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3496 	{
3497 		level = Current_level_num;
3498 		if (NewdemoFrameCount == 0)
3499 			return;
3500 		else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (NewdemoFrameCount < 10)) {
3501 			newdemo_goto_beginning();
3502 			return;
3503 		}
3504 		if (Newdemo_vcr_state == ND_STATE_REWINDING)
3505 			frames_back = 10;
3506 		else
3507 			frames_back = 1;
3508 		if (Newdemo_at_eof) {
3509 			fseek(infile, 11, SEEK_CUR);
3510 		}
3511 		newdemo_back_frames(frames_back);
3512 
3513 		if (level != Current_level_num)
3514 			newdemo_pop_ctrlcen_triggers();
3515 
3516 		if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) {
3517 			if (level != Current_level_num)
3518 				newdemo_back_frames(1);
3519 			Newdemo_vcr_state = ND_STATE_PAUSED;
3520 		}
3521 	}
3522 	else if (Newdemo_vcr_state == ND_STATE_FASTFORWARD) {
3523 		if (!Newdemo_at_eof)
3524 		{
3525 			for (i = 0; i < 10; i++)
3526 			{
3527 				if (newdemo_read_frame_information() == -1)
3528 				{
3529 					if (Newdemo_at_eof)
3530 						Newdemo_vcr_state = ND_STATE_PAUSED;
3531 					else
3532 						newdemo_stop_playback();
3533 					break;
3534 				}
3535 			}
3536 		}
3537 		else
3538 			Newdemo_vcr_state = ND_STATE_PAUSED;
3539 	}
3540 	else if (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD) {
3541 		if (!Newdemo_at_eof) {
3542 			level = Current_level_num;
3543 			if (newdemo_read_frame_information() == -1) {
3544 				if (!Newdemo_at_eof)
3545 					newdemo_stop_playback();
3546 			}
3547 			if (level != Current_level_num) {
3548 				if (newdemo_read_frame_information() == -1) {
3549 					if (!Newdemo_at_eof)
3550 						newdemo_stop_playback();
3551 				}
3552 			}
3553 			Newdemo_vcr_state = ND_STATE_PAUSED;
3554 		} else
3555 			Newdemo_vcr_state = ND_STATE_PAUSED;
3556 	}
3557 	else {
3558 
3559 		//  First, uptate the total playback time to date.  Then we check to see
3560 		//  if we need to change the playback style to interpolate frames or
3561 		//  skip frames based on where the playback time is relative to the
3562 		//  recorded time.
3563 
3564 		if (NewdemoFrameCount <= 0)
3565 			nd_playback_total = nd_recorded_total;      // baseline total playback time
3566 		else
3567 			nd_playback_total += FrameTime;
3568 		if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
3569 			if ((nd_playback_total * INTERPOL_FACTOR) < nd_recorded_total) {
3570 				playback_style = INTERPOLATE_PLAYBACK;
3571 				nd_playback_total = nd_recorded_total + FrameTime;  // baseline playback time
3572 				base_interpol_time = nd_recorded_total;
3573 				d_recorded = nd_recorded_time;                      // baseline delta recorded
3574 			}
3575 		if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
3576 			if (nd_playback_total > nd_recorded_total)
3577 				playback_style = SKIP_PLAYBACK;
3578 
3579 
3580 		if ((playback_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) {
3581 			fix d_play = 0;
3582 
3583 			if (nd_recorded_total - nd_playback_total < FrameTime) {
3584 				d_recorded = nd_recorded_total - nd_playback_total;
3585 
3586 				while (nd_recorded_total - nd_playback_total < FrameTime) {
3587 					object *cur_objs;
3588 					int i, j, num_objs, level;
3589 
3590 					num_objs = Highest_object_index;
3591 					cur_objs = (object *)d_malloc(sizeof(object) * (num_objs + 1));
3592 					if (cur_objs == NULL) {
3593 						Warning ("Couldn't get %d bytes for objects in interpolate playback\n", sizeof(object) * num_objs);
3594 						break;
3595 					}
3596 					for (i = 0; i <= num_objs; i++)
3597 						memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
3598 
3599 					level = Current_level_num;
3600 					if (newdemo_read_frame_information() == -1) {
3601 						d_free(cur_objs);
3602 						newdemo_stop_playback();
3603 						return;
3604 					}
3605 					if (level != Current_level_num) {
3606 						d_free(cur_objs);
3607 						if (newdemo_read_frame_information() == -1)
3608 							newdemo_stop_playback();
3609 						break;
3610 					}
3611 
3612 					//  for each new object in the frame just read in, determine if there is
3613 					//  a corresponding object that we have been interpolating.  If so, then
3614 					//  copy that interpolated object to the new Objects array so that the
3615 					//  interpolated position and orientation can be preserved.
3616 
3617 					for (i = 0; i <= num_objs; i++) {
3618 						for (j = 0; j <= Highest_object_index; j++) {
3619 							if (cur_objs[i].signature == Objects[j].signature) {
3620 								memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix));
3621 								memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector));
3622 								break;
3623 							}
3624 						}
3625 					}
3626 					d_free(cur_objs);
3627 					d_recorded += nd_recorded_time;
3628 					base_interpol_time = nd_playback_total - FrameTime;
3629 				}
3630 			}
3631 
3632 			d_play = nd_playback_total - base_interpol_time;
3633 			interpolate_frame(d_play, d_recorded);
3634 			return;
3635 		}
3636 		else {
3637 			//mprintf ((0, "*"));
3638 			if (newdemo_read_frame_information() == -1) {
3639 				newdemo_stop_playback();
3640 				return;
3641 			}
3642 			if (playback_style == SKIP_PLAYBACK) {
3643 				//mprintf ((0, "."));
3644 				while (nd_playback_total > nd_recorded_total) {
3645 					if (newdemo_read_frame_information() == -1) {
3646 						newdemo_stop_playback();
3647 						return;
3648 					}
3649 				}
3650 			}
3651 		}
3652 	}
3653 }
3654 
newdemo_start_recording()3655 void newdemo_start_recording()
3656 {
3657 #ifdef WINDOWS
3658 	Newdemo_size=GetFreeDiskSpace();
3659 	mprintf((0, "Free space = %d\n", Newdemo_size));
3660 #else
3661 	Newdemo_size = GetDiskFree();
3662 #endif
3663 
3664 	Newdemo_size -= 100000;
3665 
3666 	if ((Newdemo_size+100000) <  2000000000) {
3667 		if (((int)(Newdemo_size)) < 500000) {
3668 #ifndef MACINTOSH
3669 			nm_messagebox(NULL, 1, TXT_OK, TXT_DEMO_NO_SPACE);
3670 #else
3671 			nm_messagebox(NULL, 1, TXT_OK, "Not enough space on current\ndrive to start demo recording.");
3672 #endif
3673 			return;
3674 		}
3675 	}
3676 
3677 	Newdemo_num_written = 0;
3678 	Newdemo_no_space=0;
3679 	Newdemo_state = ND_STATE_RECORDING;
3680 	outfile = fopen( DEMO_FILENAME, "wb" );
3681 
3682 #ifndef MACINTOSH
3683 	if (outfile == NULL && errno == ENOENT) {   //dir doesn't exist?
3684 #else
3685 	if (outfile == NULL) {                      //dir doesn't exist and no errno on mac!
3686 #endif
3687 		d_mkdir(DEMO_DIR); //try making directory
3688 		outfile = fopen( DEMO_FILENAME, "wb" );
3689 	}
3690 
3691 	if (outfile == NULL)
3692 	{
3693 		nm_messagebox(NULL, 1, TXT_OK, "Cannot open demo temp file");
3694 		Newdemo_state = ND_STATE_NORMAL;
3695 	}
3696 	else
3697 		newdemo_record_start_demo();
3698 
3699 }
3700 
3701 char demoname_allowed_chars[] = "azAZ09__--";
3702 void newdemo_stop_recording()
3703 {
3704 	newmenu_item m[6];
3705 	int l, exit;
3706 	static char filename[15] = "", *s;
3707 	static ubyte tmpcnt = 0;
3708 	ubyte cloaked = 0;
3709 	char fullname[15+FILENAME_LEN] = DEMO_DIR;
3710 	unsigned short byte_count = 0;
3711 
3712 	exit = 0;
3713 
3714 	nd_write_byte(ND_EVENT_EOF);
3715 	nd_write_short(frame_bytes_written - 1);
3716 	if (Game_mode & GM_MULTI) {
3717 		for (l = 0; l < N_players; l++) {
3718 			if (Players[l].flags & PLAYER_FLAGS_CLOAKED)
3719 				cloaked |= (1 << l);
3720 		}
3721 		nd_write_byte(cloaked);
3722 		nd_write_byte(ND_EVENT_EOF);
3723 	} else {
3724 		nd_write_short(ND_EVENT_EOF);
3725 	}
3726 	nd_write_short(ND_EVENT_EOF);
3727 	nd_write_int(ND_EVENT_EOF);
3728 
3729 	byte_count += 10;       // from frame_bytes_written
3730 
3731 	nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
3732 	nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
3733 	nd_write_int(Players[Player_num].flags);        // be sure players flags are set
3734 	nd_write_byte((byte)Primary_weapon);
3735 	nd_write_byte((byte)Secondary_weapon);
3736 	byte_count += 8;
3737 
3738 	for (l = 0; l < MAX_PRIMARY_WEAPONS; l++)
3739 		nd_write_short((short)Players[Player_num].primary_ammo[l]);
3740 
3741 	for (l = 0; l < MAX_SECONDARY_WEAPONS; l++)
3742 		nd_write_short((short)Players[Player_num].secondary_ammo[l]);
3743 	byte_count += (sizeof(short) * (MAX_PRIMARY_WEAPONS + MAX_SECONDARY_WEAPONS));
3744 
3745 	nd_write_byte(Players[Player_num].laser_level);
3746 	byte_count++;
3747 
3748 	if (Game_mode & GM_MULTI) {
3749 		nd_write_byte((byte)N_players);
3750 		byte_count++;
3751 		for (l = 0; l < N_players; l++) {
3752 			nd_write_string(Players[l].callsign);
3753 			byte_count += (strlen(Players[l].callsign) + 2);
3754 			nd_write_byte(Players[l].connected);
3755 			if (Game_mode & GM_MULTI_COOP) {
3756 				nd_write_int(Players[l].score);
3757 				byte_count += 5;
3758 			} else {
3759 				nd_write_short((short)Players[l].net_killed_total);
3760 				nd_write_short((short)Players[l].net_kills_total);
3761 				byte_count += 5;
3762 			}
3763 		}
3764 	} else {
3765 		nd_write_int(Players[Player_num].score);
3766 		byte_count += 4;
3767 	}
3768 	nd_write_short(byte_count);
3769 
3770 	nd_write_byte(Current_level_num);
3771 	nd_write_byte(ND_EVENT_EOF);
3772 
3773 	l = ftell(outfile);
3774 	fclose(outfile);
3775 	outfile = NULL;
3776 	Newdemo_state = ND_STATE_NORMAL;
3777 	gr_palette_load( gr_palette );
3778 
3779 	if (filename[0] != '\0') {
3780 		int num, i = strlen(filename) - 1;
3781 		char newfile[15];
3782 
3783 		while (isdigit(filename[i])) {
3784 			i--;
3785 			if (i == -1)
3786 				break;
3787 		}
3788 		i++;
3789 		num = atoi(&(filename[i]));
3790 		num++;
3791 		filename[i] = '\0';
3792 		sprintf (newfile, "%s%d", filename, num);
3793 		strncpy(filename, newfile, 8);
3794 		filename[8] = '\0';
3795 	}
3796 
3797 try_again:
3798 	;
3799 
3800 	Newmenu_allowed_chars = demoname_allowed_chars;
3801 	if (!Newdemo_no_space) {
3802 		m[0].type=NM_TYPE_INPUT; m[0].text_len = 8; m[0].text = filename;
3803 		exit = newmenu_do( NULL, TXT_SAVE_DEMO_AS, 1, &(m[0]), NULL );
3804 	} else if (Newdemo_no_space == 1) {
3805 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_BAD;
3806 		m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3807 		exit = newmenu_do( NULL, NULL, 2, m, NULL );
3808 	} else if (Newdemo_no_space == 2) {
3809 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_NOSPACE;
3810 		m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3811 		exit = newmenu_do( NULL, NULL, 2, m, NULL );
3812 	}
3813 	Newmenu_allowed_chars = NULL;
3814 
3815 	if (exit == -2) {                   // got bumped out from network menu
3816 		char save_file[7+FILENAME_LEN];
3817 
3818 		if (filename[0] != '\0') {
3819 			strcpy(save_file, DEMO_DIR);
3820 			strcat(save_file, filename);
3821 			strcat(save_file, ".dem");
3822 		} else
3823 			sprintf (save_file, "%stmp%d.dem", DEMO_DIR, tmpcnt++);
3824 		remove(save_file);
3825 		rename(DEMO_FILENAME, save_file);
3826 		return;
3827 	}
3828 	if (exit == -1) {               // pressed ESC
3829 		remove(DEMO_FILENAME);      // might as well remove the file
3830 		return;                     // return without doing anything
3831 	}
3832 
3833 	if (filename[0]==0) //null string
3834 		goto try_again;
3835 
3836 	//check to make sure name is ok
3837 	for (s=filename;*s;s++)
3838 		if (!isalnum(*s) && *s!='_') {
3839 			nm_messagebox1(NULL, NULL,1,TXT_CONTINUE, TXT_DEMO_USE_LETTERS);
3840 			goto try_again;
3841 		}
3842 
3843 	if (Newdemo_no_space)
3844 		strcat(fullname, m[1].text);
3845 	else
3846 		strcat(fullname, m[0].text);
3847 	strcat(fullname, ".dem");
3848 	remove(fullname);
3849 	rename(DEMO_FILENAME, fullname);
3850 }
3851 
3852 //returns the number of demo files on the disk
3853 int newdemo_count_demos()
3854 {
3855 	FILEFINDSTRUCT find;
3856 	int NumFiles=0;
3857 
3858 	if( !FileFindFirst( DEMO_DIR "*.dem", &find ) ) {
3859 		do {
3860 			NumFiles++;
3861 		} while( !FileFindNext( &find ) );
3862 		FileFindClose();
3863 	}
3864 
3865 	if ( AltHogdir_initialized ) {
3866 		char search_name[PATH_MAX + 5];
3867 		strcpy(search_name, AltHogDir);
3868 		strcat(search_name, "/" DEMO_DIR "*.dem");
3869 		if( !FileFindFirst( search_name, &find ) ) {
3870 			do {
3871 				NumFiles++;
3872 			} while( !FileFindNext( &find ) );
3873 			FileFindClose();
3874 		}
3875 	}
3876 
3877 	return NumFiles;
3878 }
3879 
3880 void newdemo_start_playback(char * filename)
3881 {
3882 	FILEFINDSTRUCT find;
3883 	int rnd_demo = 0;
3884 	char filename2[PATH_MAX+FILENAME_LEN] = DEMO_DIR;
3885 
3886 #ifdef NETWORK
3887 	change_playernum_to(0);
3888 #endif
3889 	First_time_playback=1;
3890 	JasonPlaybackTotal=0;
3891 
3892 	if (filename==NULL) {
3893 		// Randomly pick a filename
3894 		int NumFiles = 0, RandFileNum;
3895 		rnd_demo = 1;
3896 
3897 		NumFiles = newdemo_count_demos();
3898 
3899 		if ( NumFiles == 0 ) {
3900 			return;     // No files found!
3901 		}
3902 		RandFileNum = d_rand() % NumFiles;
3903 		NumFiles = 0;
3904 		if( !FileFindFirst( DEMO_DIR "*.dem", &find ) ) {
3905 			do {
3906 				if ( NumFiles==RandFileNum ) {
3907 					filename = (char *)&find.name;
3908 					break;
3909 				}
3910 				NumFiles++;
3911 			} while( !FileFindNext( &find ) );
3912 			FileFindClose();
3913 		}
3914 
3915 		if ( filename == NULL && AltHogdir_initialized ) {
3916 			char search_name[PATH_MAX + 5];
3917 			strcpy(search_name, AltHogDir);
3918 			strcat(search_name, "/" DEMO_DIR "*.dem");
3919 			if( !FileFindFirst( search_name, &find ) ) {
3920 				do {
3921 					if ( NumFiles==RandFileNum ) {
3922 						filename = (char *)&find.name;
3923 						break;
3924 					}
3925 					NumFiles++;
3926 				} while( !FileFindNext( &find ) );
3927 				FileFindClose();
3928 			}
3929 		}
3930 
3931 		if ( filename==NULL) return;
3932 	}
3933 
3934 	if (!filename)
3935 		return;
3936 
3937 	strcat(filename2,filename);
3938 
3939 	infile = fopen( filename2, "rb" );
3940 
3941 	if (infile==NULL && AltHogdir_initialized) {
3942 		strcpy(filename2, AltHogDir);
3943 		strcat(filename2, "/" DEMO_DIR);
3944 		strcat(filename2, filename);
3945 		infile = fopen( filename2, "rb" );
3946 	}
3947 
3948 	if (infile==NULL) {
3949 		mprintf( (0, "Error reading '%s'\n", filename ));
3950 		return;
3951 	}
3952 
3953 	nd_bad_read = 0;
3954 #ifdef NETWORK
3955 	change_playernum_to(0);                 // force playernum to 0
3956 #endif
3957 	strncpy(nd_save_callsign, Players[Player_num].callsign, CALLSIGN_LEN);
3958 	Viewer = ConsoleObject = &Objects[0];   // play properly as if console player
3959 	if (newdemo_read_demo_start(rnd_demo)) {
3960 		fclose(infile);
3961 		return;
3962 	}
3963 
3964 	Game_mode = GM_NORMAL;
3965 	Newdemo_state = ND_STATE_PLAYBACK;
3966 	Newdemo_vcr_state = ND_STATE_PLAYBACK;
3967 	Newdemo_old_cockpit = Cockpit_mode;
3968 	Newdemo_size = filelength(fileno(infile));
3969 	nd_bad_read = 0;
3970 	Newdemo_at_eof = 0;
3971 	NewdemoFrameCount = 0;
3972 	Newdemo_players_cloaked = 0;
3973 	playback_style = NORMAL_PLAYBACK;
3974 	Function_mode = FMODE_GAME;
3975 	Cockpit_3d_view[0] = CV_NONE;       //turn off 3d views on cockpit
3976 	Cockpit_3d_view[1] = CV_NONE;       //turn off 3d views on cockpit
3977 	newdemo_playback_one_frame();       // this one loads new level
3978 	newdemo_playback_one_frame();       // get all of the objects to renderb game
3979 }
3980 
3981 void newdemo_stop_playback()
3982 {
3983 	fclose( infile );
3984 	Newdemo_state = ND_STATE_NORMAL;
3985 #ifdef NETWORK
3986 	change_playernum_to(0);             //this is reality
3987 #endif
3988 	strncpy(Players[Player_num].callsign, nd_save_callsign, CALLSIGN_LEN);
3989 	Cockpit_mode = Newdemo_old_cockpit;
3990 	Game_mode = GM_GAME_OVER;
3991 	Function_mode = FMODE_MENU;
3992 	longjmp(LeaveGame,0);               // Exit game loop
3993 }
3994 
3995 
3996 #ifndef NDEBUG
3997 
3998 #define BUF_SIZE 16384
3999 
4000 void newdemo_strip_frames(char *outname, int bytes_to_strip)
4001 {
4002 	FILE *outfile;
4003 	char *buf;
4004 	int total_size, bytes_done, read_elems, bytes_back;
4005 	int trailer_start, loc1, loc2, stop_loc, bytes_to_read;
4006 	short last_frame_length;
4007 
4008 	bytes_done = 0;
4009 	total_size = filelength(fileno(infile));
4010 	outfile = fopen(outname, "wb");
4011 	if (outfile == NULL) {
4012 		newmenu_item m[1];
4013 
4014 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't open output file";
4015 		newmenu_do( NULL, NULL, 1, m, NULL );
4016 		newdemo_stop_playback();
4017 		return;
4018 	}
4019 	buf = d_malloc(BUF_SIZE);
4020 	if (buf == NULL) {
4021 		newmenu_item m[1];
4022 
4023 		m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't malloc output buffer";
4024 		newmenu_do( NULL, NULL, 1, m, NULL );
4025 		fclose(outfile);
4026 		newdemo_stop_playback();
4027 		return;
4028 	}
4029 	newdemo_goto_end();
4030 	trailer_start = ftell(infile);
4031 	fseek(infile, 11, SEEK_CUR);
4032 	bytes_back = 0;
4033 	while (bytes_back < bytes_to_strip) {
4034 		loc1 = ftell(infile);
4035 		//fseek(infile, -10, SEEK_CUR);
4036 		//nd_read_short(&last_frame_length);
4037 		//fseek(infile, 8 - last_frame_length, SEEK_CUR);
4038 		newdemo_back_frames(1);
4039 		loc2 = ftell(infile);
4040 		bytes_back += (loc1 - loc2);
4041 	}
4042 	fseek(infile, -10, SEEK_CUR);
4043 	nd_read_short(&last_frame_length);
4044 	fseek(infile, -3, SEEK_CUR);
4045 	stop_loc = ftell(infile);
4046 	fseek(infile, 0, SEEK_SET);
4047 	while (stop_loc > 0) {
4048 		if (stop_loc < BUF_SIZE)
4049 			bytes_to_read = stop_loc;
4050 		else
4051 			bytes_to_read = BUF_SIZE;
4052 		read_elems = fread(buf, 1, bytes_to_read, infile);
4053 		fwrite(buf, 1, read_elems, outfile);
4054 		stop_loc -= read_elems;
4055 	}
4056 	stop_loc = ftell(outfile);
4057 	fseek(infile, trailer_start, SEEK_SET);
4058 	while ((read_elems = fread(buf, 1, BUF_SIZE, infile)) != 0)
4059 		fwrite(buf, 1, read_elems, outfile);
4060 	fseek(outfile, stop_loc, SEEK_SET);
4061 	fseek(outfile, 1, SEEK_CUR);
4062 	fwrite(&last_frame_length, 2, 1, outfile);
4063 	fclose(outfile);
4064 	newdemo_stop_playback();
4065 
4066 }
4067 
4068 #endif
4069 
4070 object DemoRightExtra,DemoLeftExtra;
4071 ubyte DemoDoRight=0,DemoDoLeft=0;
4072 
4073 void nd_render_extras (ubyte which,object *obj)
4074 {
4075 	ubyte w=which>>4;
4076 	ubyte type=which&15;
4077 
4078 	if (which==255)
4079 	{
4080 		Int3(); // how'd we get here?
4081 		do_cockpit_window_view(w,NULL,0,WBU_WEAPON,NULL);
4082 		return;
4083 	}
4084 
4085 	if (w)
4086 	{
4087 		memcpy (&DemoRightExtra,obj,sizeof(object));  DemoDoRight=type;
4088 	}
4089 	else
4090 	{
4091 		memcpy (&DemoLeftExtra,obj,sizeof(object)); DemoDoLeft=type;
4092 	}
4093 
4094 }
4095 
4096 void DoJasonInterpolate (fix recorded_time)
4097 {
4098 	fix the_delay;
4099 
4100 	JasonPlaybackTotal+=FrameTime;
4101 
4102 	if (!First_time_playback)
4103 	{
4104 		// get the difference between the recorded time and the playback time
4105 		the_delay=(recorded_time - FrameTime);
4106 		//mprintf ((0,"The delay=%d\n", f2i(the_delay)));
4107 		if (the_delay >= f0_0)
4108 		{
4109 			stop_time();
4110 			timer_delay(the_delay);
4111 			start_time();
4112 		}
4113 		else
4114 		{
4115 			while (JasonPlaybackTotal > nd_recorded_total)
4116 				if (newdemo_read_frame_information() == -1)
4117 				{
4118 					newdemo_stop_playback();
4119 					return;
4120 				}
4121 
4122 			//the_delay = nd_recorded_total - JasonPlaybackTotal;
4123 			//if (the_delay > f0_0)
4124 			//	timer_delay(the_delay);
4125 		}
4126 
4127 	}
4128 
4129 	First_time_playback=0;
4130 }
4131 
4132 #ifdef MACINTOSH
4133 #pragma global_optimizer reset
4134 #endif
4135 
4136