]> icculus.org git repositories - btb/d2x.git/blob - main/newdemo.c
more header cleanup
[btb/d2x.git] / main / newdemo.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Code to make a complete demo playback system.
17  *
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h> // for memset
29 #ifndef _WIN32_WCE
30 #include <errno.h>
31 #endif
32 #include <ctype.h>      /* for isdigit */
33 #include <limits.h>
34 #ifdef __unix__
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #endif
38
39 #include <physfs.h>
40
41 #include "u_mem.h"
42 #include "inferno.h"
43 #include "gr.h"
44 #include "stdlib.h"
45 #include "mono.h"
46 #include "3d.h"
47 #include "texmap.h"
48 #include "key.h"
49 #include "error.h"
50 #include "maths.h"
51 #include "args.h"
52 #include "timer.h"
53 #include "physfsx.h"
54 #ifdef EDITOR
55 #include "editor/editor.h"
56 #endif
57
58
59 #ifdef MACINTOSH
60 #pragma global_optimizer off        // pretty much sucks...need to look into this
61 #endif
62
63 void DoJasonInterpolate (fix recorded_time);
64
65 //#include "nocfile.h"
66
67 //Does demo start automatically?
68 int Auto_demo = 0;
69
70 sbyte WasRecorded [MAX_OBJECTS];
71 sbyte ViewWasRecorded[MAX_OBJECTS];
72 sbyte RenderingWasRecorded[32];
73
74 #define ND_EVENT_EOF                0   // EOF
75 #define ND_EVENT_START_DEMO         1   // Followed by 16 character, NULL terminated filename of .SAV file to use
76 #define ND_EVENT_START_FRAME        2   // Followed by integer frame number, then a fix FrameTime
77 #define ND_EVENT_VIEWER_OBJECT      3   // Followed by an object structure
78 #define ND_EVENT_RENDER_OBJECT      4   // Followed by an object structure
79 #define ND_EVENT_SOUND              5   // Followed by int soundum
80 #define ND_EVENT_SOUND_ONCE         6   // Followed by int soundum
81 #define ND_EVENT_SOUND_3D           7   // Followed by int soundum, int angle, int volume
82 #define ND_EVENT_WALL_HIT_PROCESS   8   // Followed by int segnum, int side, fix damage
83 #define ND_EVENT_TRIGGER            9   // Followed by int segnum, int side, int objnum
84 #define ND_EVENT_HOSTAGE_RESCUED    10  // Followed by int hostage_type
85 #define ND_EVENT_SOUND_3D_ONCE      11  // Followed by int soundum, int angle, int volume
86 #define ND_EVENT_MORPH_FRAME        12  // Followed by ? data
87 #define ND_EVENT_WALL_TOGGLE        13  // Followed by int seg, int side
88 #define ND_EVENT_HUD_MESSAGE        14  // Followed by char size, char * string (+null)
89 #define ND_EVENT_CONTROL_CENTER_DESTROYED 15 // Just a simple flag
90 #define ND_EVENT_PALETTE_EFFECT     16  // Followed by short r,g,b
91 #define ND_EVENT_PLAYER_ENERGY      17  // followed by byte energy
92 #define ND_EVENT_PLAYER_SHIELD      18  // followed by byte shields
93 #define ND_EVENT_PLAYER_FLAGS       19  // followed by player flags
94 #define ND_EVENT_PLAYER_WEAPON      20  // followed by weapon type and weapon number
95 #define ND_EVENT_EFFECT_BLOWUP      21  // followed by segment, side, and pnt
96 #define ND_EVENT_HOMING_DISTANCE    22  // followed by homing distance
97 #define ND_EVENT_LETTERBOX          23  // letterbox mode for death seq.
98 #define ND_EVENT_RESTORE_COCKPIT    24  // restore cockpit after death
99 #define ND_EVENT_REARVIEW           25  // going to rear view mode
100 #define ND_EVENT_WALL_SET_TMAP_NUM1 26  // Wall changed
101 #define ND_EVENT_WALL_SET_TMAP_NUM2 27  // Wall changed
102 #define ND_EVENT_NEW_LEVEL          28  // followed by level number
103 #define ND_EVENT_MULTI_CLOAK        29  // followed by player num
104 #define ND_EVENT_MULTI_DECLOAK      30  // followed by player num
105 #define ND_EVENT_RESTORE_REARVIEW   31  // restore cockpit after rearview mode
106 #define ND_EVENT_MULTI_DEATH        32  // with player number
107 #define ND_EVENT_MULTI_KILL         33  // with player number
108 #define ND_EVENT_MULTI_CONNECT      34  // with player number
109 #define ND_EVENT_MULTI_RECONNECT    35  // with player number
110 #define ND_EVENT_MULTI_DISCONNECT   36  // with player number
111 #define ND_EVENT_MULTI_SCORE        37  // playernum / score
112 #define ND_EVENT_PLAYER_SCORE       38  // followed by score
113 #define ND_EVENT_PRIMARY_AMMO       39  // with old/new ammo count
114 #define ND_EVENT_SECONDARY_AMMO     40  // with old/new ammo count
115 #define ND_EVENT_DOOR_OPENING       41  // with segment/side
116 #define ND_EVENT_LASER_LEVEL        42  // no data
117 #define ND_EVENT_PLAYER_AFTERBURNER 43  // followed by byte old ab, current ab
118 #define ND_EVENT_CLOAKING_WALL      44  // info changing while wall cloaking
119 #define ND_EVENT_CHANGE_COCKPIT     45  // change the cockpit
120 #define ND_EVENT_START_GUIDED       46  // switch to guided view
121 #define ND_EVENT_END_GUIDED         47  // stop guided view/return to ship
122 #define ND_EVENT_SECRET_THINGY      48  // 0/1 = secret exit functional/non-functional
123 #define ND_EVENT_LINK_SOUND_TO_OBJ  49  // record digi_link_sound_to_object3
124 #define ND_EVENT_KILL_SOUND_TO_OBJ  50  // record digi_kill_sound_linked_to_object
125
126
127 #define NORMAL_PLAYBACK         0
128 #define SKIP_PLAYBACK           1
129 #define INTERPOLATE_PLAYBACK    2
130 #define INTERPOL_FACTOR         (F1_0 + (F1_0/5))
131
132 #define DEMO_VERSION_D1_SHARE   5
133 #define DEMO_VERSION_D1         13
134 #define DEMO_VERSION_D2         15
135 #define DEMO_VERSION            DEMO_VERSION_D2
136
137 #define DEMO_GAME_TYPE_D1_SHARE 1
138 #define DEMO_GAME_TYPE_D1       2
139 #define DEMO_GAME_TYPE_D2       3
140 #define DEMO_GAME_TYPE          DEMO_GAME_TYPE_D2
141
142 #define DEMO_FILENAME           DEMO_DIR "tmpdemo.dem"
143
144 #define DEMO_MAX_LEVELS         29
145
146
147 char nd_save_callsign[CALLSIGN_LEN+1];
148 int Newdemo_state = 0;
149 int Newdemo_vcr_state = 0;
150 int Newdemo_start_frame = -1;
151 unsigned int Newdemo_size;
152 int Newdemo_num_written;
153 int Newdemo_game_mode;
154 sbyte Newdemo_game_type;
155 int Newdemo_old_cockpit;
156 int Newdemo_is_d2demo = 0;
157 sbyte Newdemo_no_space;
158 sbyte Newdemo_at_eof;
159 sbyte Newdemo_do_interpolate = 0; // 1
160 sbyte Newdemo_players_cloaked;
161 sbyte Newdemo_warning_given = 0;
162 sbyte Newdemo_cntrlcen_destroyed = 0;
163 static sbyte nd_bad_read;
164 int NewdemoFrameCount;
165 short frame_bytes_written = 0;
166 fix nd_playback_total;
167 fix nd_recorded_total;
168 fix nd_recorded_time;
169 sbyte playback_style;
170 sbyte First_time_playback=1;
171 fix JasonPlaybackTotal=0;
172
173
174 PHYSFS_file *infile;
175 PHYSFS_file *outfile = NULL;
176
177 int newdemo_get_percent_done() {
178         if ( Newdemo_state == ND_STATE_PLAYBACK ) {
179                 return ((unsigned int)PHYSFS_tell(infile) * 100) / Newdemo_size;
180         }
181         if ( Newdemo_state == ND_STATE_RECORDING ) {
182                 return (int)PHYSFS_tell(outfile);
183         }
184         return 0;
185 }
186
187 #define VEL_PRECISION 12
188
189 void my_extract_shortpos(object *objp, shortpos *spp)
190 {
191         int segnum;
192         sbyte *sp;
193
194         sp = spp->bytemat;
195         objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
196         objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
197         objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
198
199         objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
200         objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
201         objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
202
203         objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
204         objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
205         objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
206
207         segnum = spp->segment;
208         objp->segnum = segnum;
209
210         objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
211         objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
212         objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
213
214         objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
215         objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
216         objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
217 }
218
219 int newdemo_read( void *buffer, int elsize, int nelem )
220 {
221         int num_read;
222         num_read = (int)PHYSFS_read(infile, buffer, elsize, nelem);
223         if (num_read < nelem || PHYSFS_eof(infile))
224                 nd_bad_read = -1;
225
226         return num_read;
227 }
228
229 int newdemo_find_object( int signature )
230 {
231         int i;
232         object * objp;
233         objp = Objects;
234         for (i=0; i<=Highest_object_index; i++, objp++ ) {
235                 if ( (objp->type != OBJ_NONE) && (objp->signature == signature))
236                         return i;
237         }
238         return -1;
239 }
240
241 int newdemo_write( void *buffer, int elsize, int nelem )
242 {
243         int num_written, total_size;
244
245         total_size = elsize * nelem;
246         frame_bytes_written += total_size;
247         Newdemo_num_written += total_size;
248         Assert(outfile != NULL);
249         num_written = (int)PHYSFS_write(outfile, buffer, elsize, nelem);
250         //if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space) {
251         //      Newdemo_no_space=1;
252         //      newdemo_stop_recording();
253         //      return -1;
254         //}
255         if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space)
256                 Newdemo_no_space=1;
257         if (num_written == nelem && !Newdemo_no_space)
258                 return num_written;
259
260         Newdemo_no_space=2;
261         newdemo_stop_recording();
262         return -1;
263 }
264
265 /*
266  *  The next bunch of files taken from Matt's gamesave.c.  We have to modify
267  *  these since the demo must save more information about objects that
268  *  just a gamesave
269 */
270
271 static void nd_write_byte(sbyte b)
272 {
273         newdemo_write(&b, 1, 1);
274 }
275
276 static void nd_write_short(short s)
277 {
278         newdemo_write(&s, 2, 1);
279 }
280
281 static void nd_write_int(int i)
282 {
283         newdemo_write(&i, 4, 1);
284 }
285
286 static void nd_write_string(char *str)
287 {
288         nd_write_byte(strlen(str) + 1);
289         newdemo_write(str, (int)strlen(str) + 1, 1);
290 }
291
292 static void nd_write_fix(fix f)
293 {
294         newdemo_write(&f, sizeof(fix), 1);
295 }
296
297 static void nd_write_fixang(fixang f)
298 {
299         newdemo_write(&f, sizeof(fixang), 1);
300 }
301
302 static void nd_write_vector(vms_vector *v)
303 {
304         nd_write_fix(v->x);
305         nd_write_fix(v->y);
306         nd_write_fix(v->z);
307 }
308
309 static void nd_write_angvec(vms_angvec *v)
310 {
311         nd_write_fixang(v->p);
312         nd_write_fixang(v->b);
313         nd_write_fixang(v->h);
314 }
315
316 void nd_write_shortpos(object *obj)
317 {
318         int i;
319         shortpos sp;
320         ubyte render_type;
321
322         create_shortpos(&sp, obj, 0);
323
324         render_type = obj->render_type;
325         if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
326                 for (i = 0; i < 9; i++)
327                         nd_write_byte(sp.bytemat[i]);
328                 for (i = 0; i < 9; i++) {
329                         if (sp.bytemat[i] != 0)
330                                 break;
331                 }
332                 if (i == 9) {
333                         Int3();         // contact Allender about this.
334                 }
335         }
336
337         nd_write_short(sp.xo);
338         nd_write_short(sp.yo);
339         nd_write_short(sp.zo);
340         nd_write_short(sp.segment);
341         nd_write_short(sp.velx);
342         nd_write_short(sp.vely);
343         nd_write_short(sp.velz);
344 }
345
346 static void nd_read_byte(sbyte *b)
347 {
348         newdemo_read(b, 1, 1);
349 }
350
351 static void nd_read_short(short *s)
352 {
353         newdemo_read(s, 2, 1);
354 }
355
356 static void nd_read_int(int *i)
357 {
358         newdemo_read(i, 4, 1);
359 }
360
361 static void nd_read_string(char *str)
362 {
363         sbyte len;
364
365         nd_read_byte(&len);
366         newdemo_read(str, len, 1);
367 }
368
369 static void nd_read_fix(fix *f)
370 {
371         newdemo_read(f, sizeof(fix), 1);
372 }
373
374 static void nd_read_fixang(fixang *f)
375 {
376         newdemo_read(f, sizeof(fixang), 1);
377 }
378
379 static void nd_read_vector(vms_vector *v)
380 {
381         nd_read_fix(&(v->x));
382         nd_read_fix(&(v->y));
383         nd_read_fix(&(v->z));
384 }
385
386 static void nd_read_angvec(vms_angvec *v)
387 {
388         nd_read_fixang(&(v->p));
389         nd_read_fixang(&(v->b));
390         nd_read_fixang(&(v->h));
391 }
392
393 static void nd_read_shortpos(object *obj)
394 {
395         shortpos sp;
396         int i;
397         ubyte render_type;
398
399         render_type = obj->render_type;
400         if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
401                 for (i = 0; i < 9; i++)
402                         nd_read_byte(&(sp.bytemat[i]));
403         }
404
405         nd_read_short(&(sp.xo));
406         nd_read_short(&(sp.yo));
407         nd_read_short(&(sp.zo));
408         nd_read_short(&(sp.segment));
409         nd_read_short(&(sp.velx));
410         nd_read_short(&(sp.vely));
411         nd_read_short(&(sp.velz));
412
413         my_extract_shortpos(obj, &sp);
414         if ((obj->id == VCLIP_MORPHING_ROBOT) && (render_type == RT_FIREBALL) && (obj->control_type == CT_EXPLOSION))
415                 extract_orient_from_segment(&obj->orient,&Segments[obj->segnum]);
416
417 }
418
419 object *prev_obj=NULL;      //ptr to last object read in
420
421 void nd_read_object(object *obj)
422 {
423         memset(obj, 0, sizeof(object));
424
425         /*
426          * Do render type first, since with render_type == RT_NONE, we
427          * blow by all other object information
428          */
429         nd_read_byte((sbyte *) &(obj->render_type));
430         nd_read_byte((sbyte *) &(obj->type));
431         if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
432                 return;
433
434         nd_read_byte((sbyte *) &(obj->id));
435         nd_read_byte((sbyte *) &(obj->flags));
436         nd_read_short((short *)&(obj->signature));
437         nd_read_shortpos(obj);
438
439         if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
440                 Int3();
441
442         obj->attached_obj = -1;
443
444         switch(obj->type) {
445
446         case OBJ_HOSTAGE:
447                 obj->control_type = CT_POWERUP;
448                 obj->movement_type = MT_NONE;
449                 obj->size = HOSTAGE_SIZE;
450                 break;
451
452         case OBJ_ROBOT:
453                 obj->control_type = CT_AI;
454                 // (MarkA and MikeK said we should not do the crazy last secret stuff with multiple reactors...
455                 // This necessary code is our vindication. --MK, 2/15/96)
456                 if (obj->id != SPECIAL_REACTOR_ROBOT)
457                         obj->movement_type = MT_PHYSICS;
458                 else
459                         obj->movement_type = MT_NONE;
460                 obj->size = Polygon_models[Robot_info[obj->id].model_num].rad;
461                 obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
462                 obj->rtype.pobj_info.subobj_flags = 0;
463                 obj->ctype.ai_info.CLOAKED = (Robot_info[obj->id].cloak_type?1:0);
464                 break;
465
466         case OBJ_POWERUP:
467                 obj->control_type = CT_POWERUP;
468                 nd_read_byte((sbyte *) &(obj->movement_type));        // might have physics movement
469                 obj->size = Powerup_info[obj->id].size;
470                 break;
471
472         case OBJ_PLAYER:
473                 obj->control_type = CT_NONE;
474                 obj->movement_type = MT_PHYSICS;
475                 obj->size = Polygon_models[Player_ship->model_num].rad;
476                 obj->rtype.pobj_info.model_num = Player_ship->model_num;
477                 obj->rtype.pobj_info.subobj_flags = 0;
478                 break;
479
480         case OBJ_CLUTTER:
481                 obj->control_type = CT_NONE;
482                 obj->movement_type = MT_NONE;
483                 obj->size = Polygon_models[obj->id].rad;
484                 obj->rtype.pobj_info.model_num = obj->id;
485                 obj->rtype.pobj_info.subobj_flags = 0;
486                 break;
487
488         default:
489                 nd_read_byte((sbyte *) &(obj->control_type));
490                 nd_read_byte((sbyte *) &(obj->movement_type));
491                 nd_read_fix(&(obj->size));
492                 break;
493         }
494
495
496         nd_read_vector(&(obj->last_pos));
497         if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
498                 nd_read_fix(&(obj->lifeleft));
499         else {
500                 sbyte b;
501
502                 nd_read_byte(&b);
503                 obj->lifeleft = (fix)b;
504                 // MWA old way -- won't work with big endian machines       nd_read_byte((ubyte *)&(obj->lifeleft));
505                 obj->lifeleft = (fix)((int)obj->lifeleft << 12);
506         }
507
508         if (obj->type == OBJ_ROBOT) {
509                 if (Robot_info[obj->id].boss_flag) {
510                         sbyte cloaked;
511
512                         nd_read_byte(&cloaked);
513                         obj->ctype.ai_info.CLOAKED = cloaked;
514                 }
515         }
516
517         switch (obj->movement_type) {
518
519         case MT_PHYSICS:
520                 nd_read_vector(&(obj->mtype.phys_info.velocity));
521                 nd_read_vector(&(obj->mtype.phys_info.thrust));
522                 break;
523
524         case MT_SPINNING:
525                 nd_read_vector(&(obj->mtype.spin_rate));
526                 break;
527
528         case MT_NONE:
529                 break;
530
531         default:
532                 Int3();
533         }
534
535         switch (obj->control_type) {
536
537         case CT_EXPLOSION:
538
539                 nd_read_fix(&(obj->ctype.expl_info.spawn_time));
540                 nd_read_fix(&(obj->ctype.expl_info.delete_time));
541                 nd_read_short(&(obj->ctype.expl_info.delete_objnum));
542
543                 obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
544
545                 if (obj->flags & OF_ATTACHED) {     //attach to previous object
546                         Assert(prev_obj!=NULL);
547                         if (prev_obj->control_type == CT_EXPLOSION) {
548                                 if (prev_obj->flags & OF_ATTACHED && prev_obj->ctype.expl_info.attach_parent!=-1)
549                                         obj_attach(&Objects[prev_obj->ctype.expl_info.attach_parent],obj);
550                                 else
551                                         obj->flags &= ~OF_ATTACHED;
552                         }
553                         else
554                                 obj_attach(prev_obj,obj);
555                 }
556
557                 break;
558
559         case CT_LIGHT:
560                 nd_read_fix(&(obj->ctype.light_info.intensity));
561                 break;
562
563         case CT_AI:
564         case CT_WEAPON:
565         case CT_NONE:
566         case CT_FLYING:
567         case CT_DEBRIS:
568         case CT_POWERUP:
569         case CT_SLEW:
570         case CT_CNTRLCEN:
571         case CT_REMOTE:
572         case CT_MORPH:
573                 break;
574
575         case CT_FLYTHROUGH:
576         case CT_REPAIRCEN:
577         default:
578                 Int3();
579
580         }
581
582         switch (obj->render_type) {
583
584         case RT_NONE:
585                 break;
586
587         case RT_MORPH:
588         case RT_POLYOBJ: {
589                 int i, tmo;
590
591                 if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
592                         nd_read_int(&(obj->rtype.pobj_info.model_num));
593                         if (Newdemo_game_type == DEMO_GAME_TYPE_D1_SHARE)
594                                 obj->rtype.pobj_info.model_num = D1Share_Polymodel_map[obj->rtype.pobj_info.model_num];
595                         else if (Newdemo_game_type == DEMO_GAME_TYPE_D1)
596                                 obj->rtype.pobj_info.model_num = D1_Polymodel_map[obj->rtype.pobj_info.model_num];
597                         else if (Newdemo_is_d2demo)
598                                 obj->rtype.pobj_info.model_num = D2Demo_Polymodel_map[obj->rtype.pobj_info.model_num];
599                         if (obj->rtype.pobj_info.model_num < 0)
600                                 Int3();
601                         nd_read_int(&(obj->rtype.pobj_info.subobj_flags));
602                 }
603
604                 if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
605 #if 0
606                         for (i=0;i<MAX_SUBMODELS;i++)
607                                 nd_read_angvec(&(obj->pobj_info.anim_angles[i]));
608 #endif
609                 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
610                         nd_read_angvec(&obj->rtype.pobj_info.anim_angles[i]);
611
612                 nd_read_int(&tmo);
613
614 #ifndef EDITOR
615                 obj->rtype.pobj_info.tmap_override = tmo;
616 #else
617                 if (tmo==-1)
618                         obj->rtype.pobj_info.tmap_override = -1;
619                 else {
620                         int xlated_tmo = tmap_xlate_table[tmo];
621                         if (xlated_tmo < 0) {
622                                 //mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->pobj_info.model_num));
623                                 Int3();
624                                 xlated_tmo = 0;
625                         }
626                         obj->rtype.pobj_info.tmap_override = xlated_tmo;
627                 }
628 #endif
629
630                 break;
631         }
632
633         case RT_POWERUP:
634         case RT_WEAPON_VCLIP:
635         case RT_FIREBALL:
636         case RT_HOSTAGE:
637                 nd_read_int(&(obj->rtype.vclip_info.vclip_num));
638                 nd_read_fix(&(obj->rtype.vclip_info.frametime));
639                 nd_read_byte(&(obj->rtype.vclip_info.framenum));
640                 break;
641
642         case RT_LASER:
643                 break;
644
645         default:
646                 Int3();
647
648         }
649
650         prev_obj = obj;
651 }
652
653 void nd_write_object(object *obj)
654 {
655         int life;
656
657         if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
658                 Int3();
659
660         /*
661          * Do render_type first so on read, we can make determination of
662          * what else to read in
663          */
664         nd_write_byte(obj->render_type);
665         nd_write_byte(obj->type);
666         if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
667                 return;
668
669         nd_write_byte(obj->id);
670         nd_write_byte(obj->flags);
671         nd_write_short((short)obj->signature);
672         nd_write_shortpos(obj);
673
674         if ((obj->type != OBJ_HOSTAGE) && (obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_POWERUP) && (obj->type != OBJ_CLUTTER)) {
675                 nd_write_byte(obj->control_type);
676                 nd_write_byte(obj->movement_type);
677                 nd_write_fix(obj->size);
678         }
679         if (obj->type == OBJ_POWERUP)
680                 nd_write_byte(obj->movement_type);
681
682         nd_write_vector(&obj->last_pos);
683
684         if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
685                 nd_write_fix(obj->lifeleft);
686         else {
687                 life = (int)obj->lifeleft;
688                 life = life >> 12;
689                 if (life > 255)
690                         life = 255;
691                 nd_write_byte((ubyte)life);
692         }
693
694         if (obj->type == OBJ_ROBOT) {
695                 if (Robot_info[obj->id].boss_flag) {
696                         if ((GameTime > Boss_cloak_start_time) && (GameTime < Boss_cloak_end_time))
697                                 nd_write_byte(1);
698                         else
699                                 nd_write_byte(0);
700                 }
701         }
702
703         switch (obj->movement_type) {
704
705         case MT_PHYSICS:
706                 nd_write_vector(&obj->mtype.phys_info.velocity);
707                 nd_write_vector(&obj->mtype.phys_info.thrust);
708                 break;
709
710         case MT_SPINNING:
711                 nd_write_vector(&obj->mtype.spin_rate);
712                 break;
713
714         case MT_NONE:
715                 break;
716
717         default:
718                 Int3();
719         }
720
721         switch (obj->control_type) {
722
723         case CT_AI:
724                 break;
725
726         case CT_EXPLOSION:
727                 nd_write_fix(obj->ctype.expl_info.spawn_time);
728                 nd_write_fix(obj->ctype.expl_info.delete_time);
729                 nd_write_short(obj->ctype.expl_info.delete_objnum);
730                 break;
731
732         case CT_WEAPON:
733                 break;
734
735         case CT_LIGHT:
736
737                 nd_write_fix(obj->ctype.light_info.intensity);
738                 break;
739
740         case CT_NONE:
741         case CT_FLYING:
742         case CT_DEBRIS:
743         case CT_POWERUP:
744         case CT_SLEW:       //the player is generally saved as slew
745         case CT_CNTRLCEN:
746         case CT_REMOTE:
747         case CT_MORPH:
748                 break;
749
750         case CT_REPAIRCEN:
751         case CT_FLYTHROUGH:
752         default:
753                 Int3();
754
755         }
756
757         switch (obj->render_type) {
758
759         case RT_NONE:
760                 break;
761
762         case RT_MORPH:
763         case RT_POLYOBJ: {
764                 int i;
765
766                 if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
767                         nd_write_int(obj->rtype.pobj_info.model_num);
768                         nd_write_int(obj->rtype.pobj_info.subobj_flags);
769                 }
770
771                 if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
772 #if 0
773                         for (i=0;i<MAX_SUBMODELS;i++)
774                                 nd_write_angvec(&obj->pobj_info.anim_angles[i]);
775 #endif
776                 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
777                         nd_write_angvec(&obj->rtype.pobj_info.anim_angles[i]);
778
779                 nd_write_int(obj->rtype.pobj_info.tmap_override);
780
781                 break;
782         }
783
784         case RT_POWERUP:
785         case RT_WEAPON_VCLIP:
786         case RT_FIREBALL:
787         case RT_HOSTAGE:
788                 nd_write_int(obj->rtype.vclip_info.vclip_num);
789                 nd_write_fix(obj->rtype.vclip_info.frametime);
790                 nd_write_byte(obj->rtype.vclip_info.framenum);
791                 break;
792
793         case RT_LASER:
794                 break;
795
796         default:
797                 Int3();
798
799         }
800
801 }
802
803 int JustStartedRecording=0,JustStartedPlayback=0;
804
805 void newdemo_record_start_demo()
806 {
807         int i;
808
809         stop_time();
810         nd_write_byte(ND_EVENT_START_DEMO);
811         nd_write_byte(DEMO_VERSION);
812         nd_write_byte(DEMO_GAME_TYPE);
813         nd_write_fix(GameTime);
814
815 #ifdef NETWORK
816         if (Game_mode & GM_MULTI)
817                 nd_write_int(Game_mode | (Player_num << 16));
818         else
819 #endif
820                 // NOTE LINK TO ABOVE!!!
821                 nd_write_int(Game_mode);
822 #ifdef NETWORK
823
824         if (Game_mode & GM_TEAM) {
825                 nd_write_byte(Netgame.team_vector);
826                 nd_write_string(Netgame.team_name[0]);
827                 nd_write_string(Netgame.team_name[1]);
828         }
829
830         if (Game_mode & GM_MULTI) {
831                 nd_write_byte((sbyte)N_players);
832                 for (i = 0; i < N_players; i++) {
833                         nd_write_string(Players[i].callsign);
834                         nd_write_byte(Players[i].connected);
835
836                         if (Game_mode & GM_MULTI_COOP) {
837                                 nd_write_int(Players[i].score);
838                         } else {
839                                 nd_write_short((short)Players[i].net_killed_total);
840                                 nd_write_short((short)Players[i].net_kills_total);
841                         }
842                 }
843         } else
844 #endif
845                 // NOTE LINK TO ABOVE!!!
846                 nd_write_int(Players[Player_num].score);
847
848         for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
849                 nd_write_short((short)Players[Player_num].primary_ammo[i]);
850
851         for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
852                 nd_write_short((short)Players[Player_num].secondary_ammo[i]);
853
854         nd_write_byte((sbyte)Players[Player_num].laser_level);
855
856 //  Support for missions added here
857
858         nd_write_string(Current_mission_filename);
859
860         nd_write_byte((sbyte)(f2ir(Players[Player_num].energy)));
861         nd_write_byte((sbyte)(f2ir(Players[Player_num].shields)));
862         nd_write_int(Players[Player_num].flags);        // be sure players flags are set
863         nd_write_byte((sbyte)Primary_weapon);
864         nd_write_byte((sbyte)Secondary_weapon);
865         Newdemo_start_frame = FrameCount;
866         JustStartedRecording=1;
867
868         newdemo_set_new_level(Current_level_num);
869         start_time();
870
871 }
872
873 void newdemo_record_start_frame(int frame_number, fix frame_time )
874 {
875         int i;
876
877         if (Newdemo_no_space) {
878                 newdemo_stop_playback();
879                 return;
880         }
881
882         stop_time();
883
884         for (i=0;i<MAX_OBJECTS;i++)
885         {
886                 WasRecorded[i]=0;
887                 ViewWasRecorded[i]=0;
888         }
889         for (i=0;i<32;i++)
890                 RenderingWasRecorded[i]=0;
891
892         frame_number -= Newdemo_start_frame;
893
894         Assert(frame_number >= 0 );
895
896         nd_write_byte(ND_EVENT_START_FRAME);
897         nd_write_short(frame_bytes_written - 1);        // from previous frame
898         frame_bytes_written=3;
899         nd_write_int(frame_number);
900         nd_write_int(frame_time);
901         start_time();
902
903 }
904
905 void newdemo_record_render_object(object * obj)
906 {
907         if (ViewWasRecorded[OBJECT_NUMBER(obj)])
908                 return;
909
910         //if (obj==&Objects[Players[Player_num].objnum] && !Player_is_dead)
911         //      return;
912
913         stop_time();
914         nd_write_byte(ND_EVENT_RENDER_OBJECT);
915         nd_write_object(obj);
916         start_time();
917 }
918
919 extern ubyte RenderingType;
920
921 void newdemo_record_viewer_object(object * obj)
922 {
923
924         if (ViewWasRecorded[OBJECT_NUMBER(obj)] && (ViewWasRecorded[OBJECT_NUMBER(obj)] - 1) == RenderingType)
925                 return;
926         //if (WasRecorded[OBJECT_NUMBER(obj)])
927         //      return;
928         if (RenderingWasRecorded[RenderingType])
929                 return;
930
931         ViewWasRecorded[OBJECT_NUMBER(obj)] = RenderingType + 1;
932         RenderingWasRecorded[RenderingType]=1;
933         stop_time();
934         nd_write_byte(ND_EVENT_VIEWER_OBJECT);
935         nd_write_byte(RenderingType);
936         nd_write_object(obj);
937         start_time();
938 }
939
940 void newdemo_record_sound( int soundno )
941 {
942         stop_time();
943         nd_write_byte(ND_EVENT_SOUND);
944         nd_write_int( soundno );
945         start_time();
946 }
947
948 //--unused-- void newdemo_record_sound_once( int soundno ) {
949 //--unused--    stop_time();
950 //--unused--    nd_write_byte( ND_EVENT_SOUND_ONCE );
951 //--unused--    nd_write_int( soundno );
952 //--unused--    start_time();
953 //--unused-- }
954 //--unused--
955
956 void newdemo_record_cockpit_change (int mode)
957 {
958         stop_time();
959         nd_write_byte (ND_EVENT_CHANGE_COCKPIT);
960         nd_write_int(mode);
961         start_time();
962 }
963
964
965 void newdemo_record_sound_3d( int soundno, int angle, int volume )
966 {
967         stop_time();
968         nd_write_byte( ND_EVENT_SOUND_3D );
969         nd_write_int( soundno );
970         nd_write_int( angle );
971         nd_write_int( volume );
972         start_time();
973 }
974
975 void newdemo_record_sound_3d_once( int soundno, int angle, int volume )
976 {
977         stop_time();
978         nd_write_byte( ND_EVENT_SOUND_3D_ONCE );
979         nd_write_int( soundno );
980         nd_write_int( angle );
981         nd_write_int( volume );
982         start_time();
983 }
984
985
986 void newdemo_record_link_sound_to_object3( int soundno, short objnum, fix max_volume, fix  max_distance, int loop_start, int loop_end )
987 {
988         stop_time();
989         nd_write_byte( ND_EVENT_LINK_SOUND_TO_OBJ );
990         nd_write_int( soundno );
991         nd_write_int( Objects[objnum].signature );
992         nd_write_int( max_volume );
993         nd_write_int( max_distance );
994         nd_write_int( loop_start );
995         nd_write_int( loop_end );
996         start_time();
997 }
998
999 void newdemo_record_kill_sound_linked_to_object( int objnum )
1000 {
1001         stop_time();
1002         nd_write_byte( ND_EVENT_KILL_SOUND_TO_OBJ );
1003         nd_write_int( Objects[objnum].signature );
1004         start_time();
1005 }
1006
1007
1008 void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum )
1009 {
1010         stop_time();
1011         //segnum = segnum;
1012         //side = side;
1013         //damage = damage;
1014         //playernum = playernum;
1015         nd_write_byte( ND_EVENT_WALL_HIT_PROCESS );
1016         nd_write_int( segnum );
1017         nd_write_int( side );
1018         nd_write_int( damage );
1019         nd_write_int( playernum );
1020         start_time();
1021 }
1022
1023 void newdemo_record_guided_start ()
1024 {
1025         nd_write_byte (ND_EVENT_START_GUIDED);
1026 }
1027
1028 void newdemo_record_guided_end ()
1029 {
1030         nd_write_byte (ND_EVENT_END_GUIDED);
1031 }
1032
1033 void newdemo_record_secret_exit_blown(int truth)
1034 {
1035         stop_time();
1036         nd_write_byte( ND_EVENT_SECRET_THINGY );
1037         nd_write_int( truth );
1038         start_time();
1039 }
1040
1041 void newdemo_record_trigger( int segnum, int side, int objnum,int shot )
1042 {
1043         stop_time();
1044         nd_write_byte( ND_EVENT_TRIGGER );
1045         nd_write_int( segnum );
1046         nd_write_int( side );
1047         nd_write_int( objnum );
1048         nd_write_int(shot);
1049         start_time();
1050 }
1051
1052 void newdemo_record_hostage_rescued( int hostage_number ) {
1053         stop_time();
1054         nd_write_byte( ND_EVENT_HOSTAGE_RESCUED );
1055         nd_write_int( hostage_number );
1056         start_time();
1057 }
1058
1059 void newdemo_record_morph_frame(morph_data *md)
1060 {
1061         stop_time();
1062
1063         nd_write_byte( ND_EVENT_MORPH_FRAME );
1064 #if 0
1065         newdemo_write( md->morph_vecs, sizeof(md->morph_vecs), 1 );
1066         newdemo_write( md->submodel_active, sizeof(md->submodel_active), 1 );
1067         newdemo_write( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 );
1068 #endif
1069         nd_write_object( md->obj );
1070         start_time();
1071 }
1072
1073 void newdemo_record_wall_toggle( int segnum, int side )
1074 {
1075         stop_time();
1076         nd_write_byte( ND_EVENT_WALL_TOGGLE );
1077         nd_write_int( segnum );
1078         nd_write_int( side );
1079         start_time();
1080 }
1081
1082 void newdemo_record_control_center_destroyed()
1083 {
1084         stop_time();
1085         nd_write_byte( ND_EVENT_CONTROL_CENTER_DESTROYED );
1086         nd_write_int( Countdown_seconds_left );
1087         start_time();
1088 }
1089
1090 void newdemo_record_hud_message( char * message )
1091 {
1092         stop_time();
1093         nd_write_byte( ND_EVENT_HUD_MESSAGE );
1094         nd_write_string(message);
1095         start_time();
1096 }
1097
1098 void newdemo_record_palette_effect(short r, short g, short b )
1099 {
1100         stop_time();
1101         nd_write_byte( ND_EVENT_PALETTE_EFFECT );
1102         nd_write_short( r );
1103         nd_write_short( g );
1104         nd_write_short( b );
1105         start_time();
1106 }
1107
1108 void newdemo_record_player_energy(int old_energy, int energy)
1109 {
1110         stop_time();
1111         nd_write_byte( ND_EVENT_PLAYER_ENERGY );
1112         nd_write_byte((sbyte) old_energy);
1113         nd_write_byte((sbyte) energy);
1114         start_time();
1115 }
1116
1117 void newdemo_record_player_afterburner(fix old_afterburner, fix afterburner)
1118 {
1119         stop_time();
1120         nd_write_byte( ND_EVENT_PLAYER_AFTERBURNER );
1121         nd_write_byte((sbyte) (old_afterburner>>9));
1122         nd_write_byte((sbyte) (afterburner>>9));
1123         start_time();
1124 }
1125
1126 void newdemo_record_player_shields(int old_shield, int shield)
1127 {
1128         stop_time();
1129         nd_write_byte( ND_EVENT_PLAYER_SHIELD );
1130         nd_write_byte((sbyte)old_shield);
1131         nd_write_byte((sbyte)shield);
1132         start_time();
1133 }
1134
1135 void newdemo_record_player_flags(uint oflags, uint flags)
1136 {
1137         stop_time();
1138         nd_write_byte( ND_EVENT_PLAYER_FLAGS );
1139         nd_write_int(((short)oflags << 16) | (short)flags);
1140         start_time();
1141 }
1142
1143 void newdemo_record_player_weapon(int weapon_type, int weapon_num)
1144 {
1145         stop_time();
1146         nd_write_byte( ND_EVENT_PLAYER_WEAPON );
1147         nd_write_byte((sbyte)weapon_type);
1148         nd_write_byte((sbyte)weapon_num);
1149         if (weapon_type)
1150                 nd_write_byte((sbyte)Secondary_weapon);
1151         else
1152                 nd_write_byte((sbyte)Primary_weapon);
1153         start_time();
1154 }
1155
1156 void newdemo_record_effect_blowup(short segment, int side, vms_vector *pnt)
1157 {
1158         stop_time();
1159         nd_write_byte (ND_EVENT_EFFECT_BLOWUP);
1160         nd_write_short(segment);
1161         nd_write_byte((sbyte)side);
1162         nd_write_vector(pnt);
1163         start_time();
1164 }
1165
1166 void newdemo_record_homing_distance(fix distance)
1167 {
1168         stop_time();
1169         nd_write_byte(ND_EVENT_HOMING_DISTANCE);
1170         nd_write_short((short)(distance>>16));
1171         start_time();
1172 }
1173
1174 void newdemo_record_letterbox(void)
1175 {
1176         stop_time();
1177         nd_write_byte(ND_EVENT_LETTERBOX);
1178         start_time();
1179 }
1180
1181 void newdemo_record_rearview(void)
1182 {
1183         stop_time();
1184         nd_write_byte(ND_EVENT_REARVIEW);
1185         start_time();
1186 }
1187
1188 void newdemo_record_restore_cockpit(void)
1189 {
1190         stop_time();
1191         nd_write_byte(ND_EVENT_RESTORE_COCKPIT);
1192         start_time();
1193 }
1194
1195 void newdemo_record_restore_rearview(void)
1196 {
1197         stop_time();
1198         nd_write_byte(ND_EVENT_RESTORE_REARVIEW);
1199         start_time();
1200 }
1201
1202 void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1203 {
1204         stop_time();
1205         nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM1);
1206         nd_write_short(seg);
1207         nd_write_byte(side);
1208         nd_write_short(cseg);
1209         nd_write_byte(cside);
1210         nd_write_short(tmap);
1211         start_time();
1212 }
1213
1214 void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1215 {
1216         stop_time();
1217         nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM2);
1218         nd_write_short(seg);
1219         nd_write_byte(side);
1220         nd_write_short(cseg);
1221         nd_write_byte(cside);
1222         nd_write_short(tmap);
1223         start_time();
1224 }
1225
1226 void newdemo_record_multi_cloak(int pnum)
1227 {
1228         stop_time();
1229         nd_write_byte(ND_EVENT_MULTI_CLOAK);
1230         nd_write_byte((sbyte)pnum);
1231         start_time();
1232 }
1233
1234 void newdemo_record_multi_decloak(int pnum)
1235 {
1236         stop_time();
1237         nd_write_byte(ND_EVENT_MULTI_DECLOAK);
1238         nd_write_byte((sbyte)pnum);
1239         start_time();
1240 }
1241
1242 void newdemo_record_multi_death(int pnum)
1243 {
1244         stop_time();
1245         nd_write_byte(ND_EVENT_MULTI_DEATH);
1246         nd_write_byte((sbyte)pnum);
1247         start_time();
1248 }
1249
1250 void newdemo_record_multi_kill(int pnum, sbyte kill)
1251 {
1252         stop_time();
1253         nd_write_byte(ND_EVENT_MULTI_KILL);
1254         nd_write_byte((sbyte)pnum);
1255         nd_write_byte(kill);
1256         start_time();
1257 }
1258
1259 void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign)
1260 {
1261         stop_time();
1262         nd_write_byte(ND_EVENT_MULTI_CONNECT);
1263         nd_write_byte((sbyte)pnum);
1264         nd_write_byte((sbyte)new_player);
1265         if (!new_player) {
1266                 nd_write_string(Players[pnum].callsign);
1267                 nd_write_int(Players[pnum].net_killed_total);
1268                 nd_write_int(Players[pnum].net_kills_total);
1269         }
1270         nd_write_string(new_callsign);
1271         start_time();
1272 }
1273
1274 void newdemo_record_multi_reconnect(int pnum)
1275 {
1276         stop_time();
1277         nd_write_byte(ND_EVENT_MULTI_RECONNECT);
1278         nd_write_byte((sbyte)pnum);
1279         start_time();
1280 }
1281
1282 void newdemo_record_multi_disconnect(int pnum)
1283 {
1284         stop_time();
1285         nd_write_byte(ND_EVENT_MULTI_DISCONNECT);
1286         nd_write_byte((sbyte)pnum);
1287         start_time();
1288 }
1289
1290 void newdemo_record_player_score(int score)
1291 {
1292         stop_time();
1293         nd_write_byte(ND_EVENT_PLAYER_SCORE);
1294         nd_write_int(score);
1295         start_time();
1296 }
1297
1298 void newdemo_record_multi_score(int pnum, int score)
1299 {
1300         stop_time();
1301         nd_write_byte(ND_EVENT_MULTI_SCORE);
1302         nd_write_byte((sbyte)pnum);
1303         nd_write_int(score - Players[pnum].score);      // called before score is changed!!!!
1304         start_time();
1305 }
1306
1307 void newdemo_record_primary_ammo(int old_ammo, int new_ammo)
1308 {
1309         stop_time();
1310         nd_write_byte(ND_EVENT_PRIMARY_AMMO);
1311         if (old_ammo < 0)
1312                 nd_write_short((short)new_ammo);
1313         else
1314                 nd_write_short((short)old_ammo);
1315         nd_write_short((short)new_ammo);
1316         start_time();
1317 }
1318
1319 void newdemo_record_secondary_ammo(int old_ammo, int new_ammo)
1320 {
1321         stop_time();
1322         nd_write_byte(ND_EVENT_SECONDARY_AMMO);
1323         if (old_ammo < 0)
1324                 nd_write_short((short)new_ammo);
1325         else
1326                 nd_write_short((short)old_ammo);
1327         nd_write_short((short)new_ammo);
1328         start_time();
1329 }
1330
1331 void newdemo_record_door_opening(int segnum, int side)
1332 {
1333         stop_time();
1334         nd_write_byte(ND_EVENT_DOOR_OPENING);
1335         nd_write_short((short)segnum);
1336         nd_write_byte((sbyte)side);
1337         start_time();
1338 }
1339
1340 void newdemo_record_laser_level(sbyte old_level, sbyte new_level)
1341 {
1342         stop_time();
1343         nd_write_byte(ND_EVENT_LASER_LEVEL);
1344         nd_write_byte(old_level);
1345         nd_write_byte(new_level);
1346         start_time();
1347 }
1348
1349 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)
1350 {
1351         Assert(front_wall_num <= 255 && back_wall_num <= 255);
1352
1353         stop_time();
1354         nd_write_byte(ND_EVENT_CLOAKING_WALL);
1355         nd_write_byte(front_wall_num);
1356         nd_write_byte(back_wall_num);
1357         nd_write_byte(type);
1358         nd_write_byte(state);
1359         nd_write_byte(cloak_value);
1360         nd_write_short(l0>>8);
1361         nd_write_short(l1>>8);
1362         nd_write_short(l2>>8);
1363         nd_write_short(l3>>8);
1364         start_time();
1365 }
1366
1367 void newdemo_set_new_level(int level_num)
1368 {
1369         int i;
1370         int side;
1371         segment *seg;
1372
1373         stop_time();
1374         nd_write_byte(ND_EVENT_NEW_LEVEL);
1375         nd_write_byte((sbyte)level_num);
1376         nd_write_byte((sbyte)Current_level_num);
1377
1378         if (JustStartedRecording==1)
1379         {
1380                 nd_write_int(Num_walls);
1381                 for (i=0;i<Num_walls;i++)
1382                 {
1383                         nd_write_byte (Walls[i].type);
1384                         nd_write_byte (Walls[i].flags);
1385                         nd_write_byte (Walls[i].state);
1386
1387                         seg = &Segments[Walls[i].segnum];
1388                         side = Walls[i].sidenum;
1389                         nd_write_short (seg->sides[side].tmap_num);
1390                         nd_write_short (seg->sides[side].tmap_num2);
1391                         JustStartedRecording=0;
1392                 }
1393         }
1394
1395         start_time();
1396 }
1397
1398 int newdemo_read_demo_start(int rnd_demo)
1399 {
1400         sbyte i, version, laser_level;
1401         sbyte c, energy, shield;
1402         char text[128], current_mission[9] = "";
1403
1404         nd_read_byte(&c);
1405         if ((c != ND_EVENT_START_DEMO) || nd_bad_read) {
1406                 newmenu_item m[1];
1407
1408                 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_CORRUPT);
1409                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
1410                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
1411                 return 1;
1412         }
1413         nd_read_byte(&version);
1414         nd_read_byte(&Newdemo_game_type);
1415         if (Newdemo_game_type < DEMO_GAME_TYPE_D1_SHARE) {
1416                 newmenu_item m[2];
1417
1418                 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
1419                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
1420                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = "    In Descent: First Strike";
1421
1422                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
1423                 return 1;
1424         }
1425         if (Newdemo_game_type > DEMO_GAME_TYPE) {
1426                 newmenu_item m[2];
1427
1428                 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
1429                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
1430                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = "   In Unknown Descent version";
1431
1432                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
1433                 return 1;
1434         }
1435         if (version < DEMO_VERSION_D1_SHARE) {
1436                 if (!rnd_demo) {
1437                         newmenu_item m[1];
1438                         sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD);
1439                         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
1440                         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
1441                 }
1442                 return 1;
1443         }
1444         nd_read_fix(&GameTime);
1445         Boss_cloak_start_time=Boss_cloak_end_time=GameTime;
1446         JasonPlaybackTotal=0;
1447
1448         nd_read_int(&Newdemo_game_mode);
1449
1450 #ifdef NETWORK
1451         change_playernum_to((Newdemo_game_mode >> 16) & 0x7);
1452         if (Newdemo_game_mode & GM_TEAM) {
1453                 nd_read_byte((sbyte *) &(Netgame.team_vector));
1454
1455                 if (Newdemo_game_type >= DEMO_GAME_TYPE_D1) {
1456                         nd_read_string(Netgame.team_name[0]);
1457                         nd_read_string(Netgame.team_name[1]);
1458                 }
1459
1460         }
1461         if (Newdemo_game_mode & GM_MULTI) {
1462
1463                 multi_new_game();
1464                 nd_read_byte(&c);
1465                 N_players = (int)c;
1466                 // changed this to above two lines -- breaks on the mac because of
1467                 // endian issues
1468                 //              nd_read_byte((sbyte *)&N_players);
1469                 for (i = 0 ; i < N_players; i++) {
1470                         Players[i].cloak_time = 0;
1471                         Players[i].invulnerable_time = 0;
1472                         nd_read_string(Players[i].callsign);
1473                         nd_read_byte(&(Players[i].connected));
1474
1475                         if (Newdemo_game_mode & GM_MULTI_COOP) {
1476                                 nd_read_int(&(Players[i].score));
1477                         } else {
1478                                 nd_read_short((short *)&(Players[i].net_killed_total));
1479                                 nd_read_short((short *)&(Players[i].net_kills_total));
1480                         }
1481                 }
1482                 Game_mode = Newdemo_game_mode;
1483                 multi_sort_kill_list();
1484                 Game_mode = GM_NORMAL;
1485         } else
1486 #endif
1487                 if (Newdemo_game_type >= DEMO_GAME_TYPE_D1)
1488                         nd_read_int(&(Players[Player_num].score));      // Note link to above if!
1489
1490         if (Newdemo_game_type >= DEMO_GAME_TYPE_D1) {
1491                 for (i = 0; i < (Newdemo_game_type < DEMO_GAME_TYPE_D2 ? 5 : MAX_PRIMARY_WEAPONS); i++)
1492                         nd_read_short((short*)&(Players[Player_num].primary_ammo[i]));
1493
1494                 for (i = 0; i < (Newdemo_game_type < DEMO_GAME_TYPE_D2 ? 5 : MAX_SECONDARY_WEAPONS); i++)
1495                         nd_read_short((short*)&(Players[Player_num].secondary_ammo[i]));
1496
1497                 nd_read_byte(&laser_level);
1498                 if (laser_level != Players[Player_num].laser_level) {
1499                         Players[Player_num].laser_level = laser_level;
1500                         update_laser_weapon_info();
1501                 }
1502
1503                 // Support for missions
1504
1505                 nd_read_string(current_mission);
1506         }
1507         if (!strcmp(current_mission, ""))
1508                 strcpy(current_mission, "descent");
1509         if (!strcmp(current_mission, "d2demo") && !cfexist("d2demo.hog")) {
1510                 strcpy(current_mission, "d2");
1511                 Newdemo_is_d2demo = 1;
1512         }
1513         if (!load_mission_by_name(current_mission)) {
1514                 if (!rnd_demo) {
1515                         newmenu_item m[1];
1516
1517                         sprintf(text, TXT_NOMISSION4DEMO, current_mission);
1518                         m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
1519                         newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
1520                 }
1521                 return 1;
1522         }
1523
1524         nd_recorded_total = 0;
1525         nd_playback_total = 0;
1526         nd_read_byte(&energy);
1527         nd_read_byte(&shield);
1528
1529         nd_read_int((int *)&(Players[Player_num].flags));
1530         if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
1531                 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
1532                 Newdemo_players_cloaked |= (1 << Player_num);
1533         }
1534         if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
1535                 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
1536
1537         nd_read_byte((sbyte *)&Primary_weapon);
1538         nd_read_byte((sbyte *)&Secondary_weapon);
1539
1540         // Next bit of code to fix problem that I introduced between 1.0 and 1.1
1541         // check the next byte -- it _will_ be a load_new_level event.  If it is
1542         // not, then we must shift all bytes up by one.
1543
1544         if (Newdemo_game_type < DEMO_GAME_TYPE_D1)
1545         {
1546                 sbyte c;
1547
1548                 nd_read_byte(&c);
1549                 if (c != ND_EVENT_NEW_LEVEL) {
1550                         int flags;
1551
1552                         flags = Players[Player_num].flags;
1553                         energy = shield;
1554                         shield = (unsigned char)flags;
1555                         flags = (flags >> 8) & 0x00ffffff;
1556                         flags |= (Primary_weapon << 24);
1557                         Primary_weapon = Secondary_weapon;
1558                         Secondary_weapon = c;
1559                 } else
1560                         PHYSFS_seek(infile, PHYSFS_tell(infile) - 1);
1561         }
1562
1563         Players[Player_num].energy = i2f(energy);
1564         Players[Player_num].shields = i2f(shield);
1565         JustStartedPlayback=1;
1566         return 0;
1567 }
1568
1569 void newdemo_pop_ctrlcen_triggers()
1570 {
1571         int anim_num, n, i;
1572         int side, cside;
1573         segment *seg, *csegp;
1574
1575         for (i = 0; i < ControlCenterTriggers.num_links; i++) {
1576                 seg = &Segments[ControlCenterTriggers.seg[i]];
1577                 side = ControlCenterTriggers.side[i];
1578                 csegp = &Segments[seg->children[side]];
1579                 cside = find_connect_side(seg, csegp);
1580                 anim_num = Walls[seg->sides[side].wall_num].clip_num;
1581                 n = WallAnims[anim_num].num_frames;
1582                 if (WallAnims[anim_num].flags & WCF_TMAP1) {
1583                 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[n-1];
1584                 } else {
1585                         seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[n-1];
1586                 }
1587         }
1588 }
1589
1590 #define N_PLAYER_SHIP_TEXTURES 6
1591
1592 void nd_render_extras (ubyte,object *);
1593 extern void multi_apply_goal_textures ();
1594 ubyte Newdemo_flying_guided=0;
1595
1596 int newdemo_read_frame_information()
1597 {
1598         int done, segnum, side, objnum, soundno, angle, volume, i,shot;
1599         object *obj;
1600         sbyte c = 0, WhichWindow;
1601         static sbyte saved_letter_cockpit;
1602         static sbyte saved_rearview_cockpit;
1603         object extraobj;
1604         static char LastReadValue=101;
1605         segment *seg;
1606
1607         done = 0;
1608
1609         if (Newdemo_vcr_state != ND_STATE_PAUSED)
1610                 for (segnum=0; segnum <= Highest_segment_index; segnum++)
1611                         Segments[segnum].objects = -1;
1612
1613         reset_objects(1);
1614         Players[Player_num].homing_object_dist = -F1_0;
1615
1616         prev_obj = NULL;
1617
1618         while( !done ) {
1619                 nd_read_byte(&c);
1620                 if (nd_bad_read) { done = -1; break; }
1621
1622                 switch( c ) {
1623
1624                 case ND_EVENT_START_FRAME: {        // Followed by an integer frame number, then a fix FrameTime
1625                         short last_frame_length;
1626
1627                         done=1;
1628                         nd_read_short(&last_frame_length);
1629                         nd_read_int(&NewdemoFrameCount);
1630                         nd_read_int((int *)&nd_recorded_time);
1631                         if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
1632                                 nd_recorded_total += nd_recorded_time;
1633                         NewdemoFrameCount--;
1634
1635                         if (nd_bad_read) { done = -1; break; }
1636                         break;
1637                 }
1638
1639                 case ND_EVENT_VIEWER_OBJECT:        // Followed by an object structure
1640                         if (Newdemo_game_type <  DEMO_GAME_TYPE_D2)
1641                                 WhichWindow = 0;
1642                         else
1643                                 nd_read_byte (&WhichWindow);
1644                         if (WhichWindow&15)
1645                         {
1646                                 //mprintf ((0,"Reading extra!\n"));
1647                                 nd_read_object (&extraobj);
1648                                 if (Newdemo_vcr_state!=ND_STATE_PAUSED)
1649                                 {
1650                                         if (nd_bad_read) { done = -1; break; }
1651
1652                                         nd_render_extras (WhichWindow,&extraobj);
1653                                 }
1654                         }
1655                         else
1656                         {
1657                                 //mprintf ((0,"Reading viewer!\n"));
1658                                 //Viewer=&Objects[0];
1659                                 nd_read_object(Viewer);
1660
1661                                 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
1662                                         if (nd_bad_read) { done = -1; break; }
1663                                         segnum = Viewer->segnum;
1664                                         Viewer->next = Viewer->prev = Viewer->segnum = -1;
1665
1666                                         // HACK HACK HACK -- since we have multiple level recording, it can be the case
1667                                         // HACK HACK HACK -- that when rewinding the demo, the viewer is in a segment
1668                                         // HACK HACK HACK -- that is greater than the highest index of segments.  Bash
1669                                         // HACK HACK HACK -- the viewer to segment 0 for bogus view.
1670
1671                                         if (segnum > Highest_segment_index)
1672                                                 segnum = 0;
1673                                         obj_link(OBJECT_NUMBER(Viewer), segnum);
1674                                 }
1675                         }
1676                         break;
1677
1678                 case ND_EVENT_RENDER_OBJECT:       // Followed by an object structure
1679                         objnum = obj_allocate();
1680                         if (objnum==-1)
1681                                 break;
1682                         obj = &Objects[objnum];
1683                         nd_read_object(obj);
1684                         if (nd_bad_read) { done = -1; break; }
1685                         if (Newdemo_vcr_state != ND_STATE_PAUSED) {
1686                                 segnum = obj->segnum;
1687                                 obj->next = obj->prev = obj->segnum = -1;
1688
1689                                 // HACK HACK HACK -- don't render objects is segments greater than Highest_segment_index
1690                                 // HACK HACK HACK -- (see above)
1691
1692                                 if (segnum > Highest_segment_index)
1693                                         break;
1694
1695                                 obj_link(OBJECT_NUMBER(obj), segnum);
1696 #ifdef NETWORK
1697                                 if ((obj->type == OBJ_PLAYER) && (Newdemo_game_mode & GM_MULTI)) {
1698                                         int player;
1699
1700                                         if (Newdemo_game_mode & GM_TEAM)
1701                                                 player = get_team(obj->id);
1702                                         else
1703                                                 player = obj->id;
1704                                         if (player == 0)
1705                                                 break;
1706                                         player--;
1707
1708                                         for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
1709                                                 multi_player_textures[player][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[obj->rtype.pobj_info.model_num].first_texture+i]];
1710
1711                                         multi_player_textures[player][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2]];
1712                                         multi_player_textures[player][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2+1]];
1713                                         obj->rtype.pobj_info.alt_textures = player+1;
1714                                 }
1715 #endif
1716                         }
1717                         break;
1718
1719                 case ND_EVENT_SOUND:
1720                         nd_read_int(&soundno);
1721                         if (nd_bad_read) {done = -1; break; }
1722                         if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
1723                                 digi_play_sample( soundno, F1_0 );
1724                         break;
1725
1726                         //--unused              case ND_EVENT_SOUND_ONCE:
1727                         //--unused                      nd_read_int(&soundno);
1728                         //--unused                      if (nd_bad_read) { done = -1; break; }
1729                         //--unused                      if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
1730                         //--unused                              digi_play_sample_once( soundno, F1_0 );
1731                         //--unused                      break;
1732
1733                 case ND_EVENT_SOUND_3D:
1734                         nd_read_int(&soundno);
1735                         nd_read_int(&angle);
1736                         nd_read_int(&volume);
1737                         if (nd_bad_read) { done = -1; break; }
1738                         if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
1739                                 digi_play_sample_3d( soundno, angle, volume, 0 );
1740                         break;
1741
1742                 case ND_EVENT_SOUND_3D_ONCE:
1743                         nd_read_int(&soundno);
1744                         nd_read_int(&angle);
1745                         nd_read_int(&volume);
1746                         if (nd_bad_read) { done = -1; break; }
1747                         if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
1748                                 digi_play_sample_3d( soundno, angle, volume, 1 );
1749                         break;
1750
1751                 case ND_EVENT_LINK_SOUND_TO_OBJ:
1752                         {
1753                                 int soundno, objnum, max_volume, max_distance, loop_start, loop_end;
1754                                 int signature;
1755                                 nd_read_int( &soundno );
1756                                 nd_read_int( &signature );
1757                                 nd_read_int( &max_volume );
1758                                 nd_read_int( &max_distance );
1759                                 nd_read_int( &loop_start );
1760                                 nd_read_int( &loop_end );
1761                                 objnum = newdemo_find_object( signature );
1762                                 if ( objnum > -1 )  {   //  @mk, 2/22/96, John told me to.
1763                                         digi_link_sound_to_object3( soundno, objnum, 1, max_volume, max_distance, loop_start, loop_end );
1764                                 }
1765                         }
1766                         break;
1767
1768                 case ND_EVENT_KILL_SOUND_TO_OBJ:
1769                         {
1770                                 int objnum, signature;
1771                                 nd_read_int( &signature );
1772                                 objnum = newdemo_find_object( signature );
1773                                 if ( objnum > -1 )  {   //  @mk, 2/22/96, John told me to.
1774                                         digi_kill_sound_linked_to_object(objnum);
1775                                 }
1776                         }
1777                         break;
1778
1779                 case ND_EVENT_WALL_HIT_PROCESS: {
1780                         int player, segnum;
1781                         fix damage;
1782
1783                         nd_read_int(&segnum);
1784                         nd_read_int(&side);
1785                         nd_read_fix(&damage);
1786                         nd_read_int(&player);
1787                         if (nd_bad_read) { done = -1; break; }
1788                         if (Newdemo_vcr_state != ND_STATE_PAUSED)
1789                                 wall_hit_process(&Segments[segnum], side, damage, player, &(Objects[0]) );
1790                         break;
1791                 }
1792
1793                 case ND_EVENT_TRIGGER:
1794                         nd_read_int(&segnum);
1795                         nd_read_int(&side);
1796                         nd_read_int(&objnum);
1797                         nd_read_int(&shot);
1798                         if (nd_bad_read) { done = -1; break; }
1799                         if (Newdemo_vcr_state != ND_STATE_PAUSED)
1800                         {
1801                                 mprintf ((0,"EVENT TRIGGER! shot=%d\n",shot));
1802
1803                                 if (Triggers[Walls[Segments[segnum].sides[side].wall_num].trigger].type == TT_SECRET_EXIT) {
1804                                         int truth;
1805
1806                                         nd_read_byte(&c);
1807                                         Assert(c == ND_EVENT_SECRET_THINGY);
1808                                         nd_read_int(&truth);
1809                                         if (!truth)
1810                                                 check_trigger(&Segments[segnum], side, objnum,shot);
1811                                 } else
1812                                         check_trigger(&Segments[segnum], side, objnum,shot);
1813                         }
1814                         break;
1815
1816                 case ND_EVENT_HOSTAGE_RESCUED: {
1817                         int hostage_number;
1818
1819                         nd_read_int(&hostage_number);
1820                         if (nd_bad_read) { done = -1; break; }
1821                         if (Newdemo_vcr_state != ND_STATE_PAUSED)
1822                                 hostage_rescue( hostage_number );
1823                         break;
1824                 }
1825
1826                 case ND_EVENT_MORPH_FRAME: {
1827 #if 0
1828                         morph_data *md;
1829
1830                         md = &morph_objects[0];
1831                         if (newdemo_read( md->morph_vecs, sizeof(md->morph_vecs), 1 )!=1) { done=-1; break; }
1832                         if (newdemo_read( md->submodel_active, sizeof(md->submodel_active), 1 )!=1) { done=-1; break; }
1833                         if (newdemo_read( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 )!=1) { done=-1; break; }
1834 #endif
1835                         objnum = obj_allocate();
1836                         if (objnum==-1)
1837                                 break;
1838                         obj = &Objects[objnum];
1839                         nd_read_object(obj);
1840                         obj->render_type = RT_POLYOBJ;
1841                         if (Newdemo_vcr_state != ND_STATE_PAUSED) {
1842                                 if (nd_bad_read) { done = -1; break; }
1843                                 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
1844                                         segnum = obj->segnum;
1845                                         obj->next = obj->prev = obj->segnum = -1;
1846                                         obj_link(OBJECT_NUMBER(obj), segnum);
1847                                 }
1848                         }
1849                         break;
1850                 }
1851
1852                 case ND_EVENT_WALL_TOGGLE:
1853                         nd_read_int(&segnum);
1854                         nd_read_int(&side);
1855                         if (nd_bad_read) {done = -1; break; }
1856                         if (Newdemo_vcr_state != ND_STATE_PAUSED)
1857                                 wall_toggle(&Segments[segnum], side);
1858                         break;
1859
1860                 case ND_EVENT_CONTROL_CENTER_DESTROYED:
1861                         nd_read_int(&Countdown_seconds_left);
1862                         Control_center_destroyed = 1;
1863                         if (nd_bad_read) { done = -1; break; }
1864                         if (!Newdemo_cntrlcen_destroyed) {
1865                                 newdemo_pop_ctrlcen_triggers();
1866                                 Newdemo_cntrlcen_destroyed = 1;
1867                                 //do_controlcen_destroyed_stuff(NULL);
1868                         }
1869                         break;
1870
1871                 case ND_EVENT_HUD_MESSAGE: {
1872                         char hud_msg[60];
1873
1874                         nd_read_string(&(hud_msg[0]));
1875                         if (nd_bad_read) { done = -1; break; }
1876                         HUD_init_message( hud_msg );
1877                         break;
1878                         }
1879                 case ND_EVENT_START_GUIDED:
1880                         Newdemo_flying_guided=1;
1881                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
1882                                 Newdemo_flying_guided=0;
1883                         break;
1884                 case ND_EVENT_END_GUIDED:
1885                         Newdemo_flying_guided=0;
1886                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
1887                                 Newdemo_flying_guided=1;
1888                         break;
1889
1890                 case ND_EVENT_PALETTE_EFFECT: {
1891                         short r, g, b;
1892
1893                         nd_read_short(&r);
1894                         nd_read_short(&g);
1895                         nd_read_short(&b);
1896                         if (nd_bad_read) { done = -1; break; }
1897                         PALETTE_FLASH_SET(r,g,b);
1898                         break;
1899                 }
1900
1901                 case ND_EVENT_PLAYER_ENERGY: {
1902                         sbyte energy;
1903                         sbyte old_energy = 0;
1904
1905                         if (Newdemo_game_type >= DEMO_GAME_TYPE_D1)
1906                                 nd_read_byte(&old_energy);
1907                         nd_read_byte(&energy);
1908                         if (nd_bad_read) {done = -1; break; }
1909                         if ((Newdemo_game_type < DEMO_GAME_TYPE_D1) || (Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
1910                                 Players[Player_num].energy = i2f(energy);
1911                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
1912                                 if (old_energy != -128)
1913                                         Players[Player_num].energy = i2f(old_energy);
1914                         }
1915                         break;
1916                 }
1917
1918                 case ND_EVENT_PLAYER_AFTERBURNER: {
1919                         sbyte afterburner;
1920                         sbyte old_afterburner;
1921
1922                         nd_read_byte(&old_afterburner);
1923                         nd_read_byte(&afterburner);
1924                         if (nd_bad_read) {done = -1; break; }
1925                         if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
1926                                 Afterburner_charge = afterburner<<9;
1927                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
1928                                 if (old_afterburner != -128)
1929                                         Afterburner_charge = old_afterburner<<9;
1930                         }
1931                         break;
1932                 }
1933
1934                 case ND_EVENT_PLAYER_SHIELD: {
1935                         sbyte shield;
1936                         sbyte old_shield = 0;
1937
1938                         if (Newdemo_game_type >= DEMO_GAME_TYPE_D1)
1939                                 nd_read_byte(&old_shield);
1940                         nd_read_byte(&shield);
1941                         if (nd_bad_read) {done = -1; break; }
1942                         if ((Newdemo_game_type < DEMO_GAME_TYPE_D1) || (Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
1943                                 Players[Player_num].shields = i2f(shield);
1944                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
1945                                 if (old_shield != -128)
1946                                         Players[Player_num].shields = i2f(old_shield);
1947                         }
1948                         break;
1949                 }
1950
1951                 case ND_EVENT_PLAYER_FLAGS: {
1952                         uint oflags;
1953
1954                         nd_read_int((int *)&(Players[Player_num].flags));
1955                         if (nd_bad_read) {done = -1; break; }
1956
1957                         oflags = Players[Player_num].flags >> 16;
1958                         Players[Player_num].flags &= 0xffff;
1959
1960                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || ((Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) && (oflags != 0xffff)) ) {
1961                                 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
1962                                         Players[Player_num].cloak_time = 0;
1963                                         Newdemo_players_cloaked &= ~(1 << Player_num);
1964                                 }
1965                                 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
1966                                         Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
1967                                         Newdemo_players_cloaked |= (1 << Player_num);
1968                                 }
1969                                 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
1970                                         Players[Player_num].invulnerable_time = 0;
1971                                 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
1972                                         Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
1973                                 Players[Player_num].flags = oflags;
1974                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
1975                                 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
1976                                         Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
1977                                         Newdemo_players_cloaked |= (1 << Player_num);
1978                                 }
1979                                 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
1980                                         Players[Player_num].cloak_time = 0;
1981                                         Newdemo_players_cloaked &= ~(1 << Player_num);
1982                                 }
1983                                 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
1984                                         Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
1985                                 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
1986                                         Players[Player_num].invulnerable_time = 0;
1987                         }
1988                         update_laser_weapon_info();     // in case of quad laser change
1989                         break;
1990                 }
1991
1992                 case ND_EVENT_PLAYER_WEAPON: {
1993                         sbyte weapon_type, weapon_num;
1994                         sbyte old_weapon = 0;
1995
1996                         nd_read_byte(&weapon_type);
1997                         nd_read_byte(&weapon_num);
1998                         if (Newdemo_game_type >= DEMO_GAME_TYPE_D1)
1999                                 nd_read_byte(&old_weapon);
2000                         if ((Newdemo_game_type < DEMO_GAME_TYPE_D1) || (Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2001                                 if (weapon_type == 0)
2002                                         Primary_weapon = (int)weapon_num;
2003                                 else
2004                                         Secondary_weapon = (int)weapon_num;
2005                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2006                                 if (weapon_type == 0)
2007                                         Primary_weapon = (int)old_weapon;
2008                                 else
2009                                         Secondary_weapon = (int)old_weapon;
2010                         }
2011                         break;
2012                 }
2013
2014                 case ND_EVENT_EFFECT_BLOWUP: {
2015                         short segnum;
2016                         sbyte side;
2017                         vms_vector pnt;
2018                         object dummy;
2019
2020                         //create a dummy object which will be the weapon that hits
2021                         //the monitor. the blowup code wants to know who the parent of the
2022                         //laser is, so create a laser whose parent is the player
2023                         dummy.ctype.laser_info.parent_type = OBJ_PLAYER;
2024
2025                         nd_read_short(&segnum);
2026                         nd_read_byte(&side);
2027                         nd_read_vector(&pnt);
2028                         if (Newdemo_vcr_state != ND_STATE_PAUSED)
2029                                 check_effect_blowup(&(Segments[segnum]), side, &pnt, &dummy, 0);
2030                         break;
2031                 }
2032
2033                 case ND_EVENT_HOMING_DISTANCE: {
2034                         short distance;
2035
2036                         nd_read_short(&distance);
2037                         Players[Player_num].homing_object_dist = i2f((int)(distance << 16));
2038                         break;
2039                 }
2040
2041                 case ND_EVENT_LETTERBOX:
2042                         if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2043                                 saved_letter_cockpit = Cockpit_mode.intval;
2044                                 select_cockpit(CM_LETTERBOX);
2045                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2046                                 select_cockpit(saved_letter_cockpit);
2047                         break;
2048
2049                 case ND_EVENT_CHANGE_COCKPIT: {
2050                         int dummy;
2051
2052                         nd_read_int (&dummy);
2053                         select_cockpit (dummy);
2054
2055                         break;
2056                 }
2057                 case ND_EVENT_REARVIEW:
2058                         if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2059                                 saved_rearview_cockpit = Cockpit_mode.intval;
2060                                 if (Cockpit_mode.intval == CM_FULL_COCKPIT)
2061                                         select_cockpit(CM_REAR_VIEW);
2062                                 Rear_view=1;
2063                         } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2064                                 if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
2065                                         saved_rearview_cockpit = CM_FULL_COCKPIT;
2066                                 select_cockpit(saved_rearview_cockpit);
2067                                 Rear_view=0;
2068                         }
2069                         break;
2070
2071                 case ND_EVENT_RESTORE_COCKPIT:
2072                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2073                                 saved_letter_cockpit = Cockpit_mode.intval;
2074                                 select_cockpit(CM_LETTERBOX);
2075                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2076                                 select_cockpit(saved_letter_cockpit);
2077                         break;
2078
2079
2080                 case ND_EVENT_RESTORE_REARVIEW:
2081                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2082                                 saved_rearview_cockpit = Cockpit_mode.intval;
2083                                 if (Cockpit_mode.intval == CM_FULL_COCKPIT)
2084                                         select_cockpit(CM_REAR_VIEW);
2085                                 Rear_view=1;
2086                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2087                                 if (saved_rearview_cockpit == CM_REAR_VIEW)     // hack to be sure we get a good cockpit on restore
2088                                         saved_rearview_cockpit = CM_FULL_COCKPIT;
2089                                 select_cockpit(saved_rearview_cockpit);
2090                                 Rear_view=0;
2091                         }
2092                         break;
2093
2094
2095                 case ND_EVENT_WALL_SET_TMAP_NUM1: {
2096                         short seg, cseg, tmap;
2097                         sbyte side,cside;
2098
2099                         nd_read_short(&seg);
2100                         nd_read_byte(&side);
2101                         nd_read_short(&cseg);
2102                         nd_read_byte(&cside);
2103                         nd_read_short( &tmap );
2104                         if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD))
2105                                 Segments[seg].sides[side].tmap_num = Segments[cseg].sides[cside].tmap_num = tmap;
2106                         break;
2107                 }
2108
2109                 case ND_EVENT_WALL_SET_TMAP_NUM2: {
2110                         short seg, cseg, tmap;
2111                         sbyte side,cside;
2112
2113                         nd_read_short(&seg);
2114                         nd_read_byte(&side);
2115                         nd_read_short(&cseg);
2116                         nd_read_byte(&cside);
2117                         nd_read_short( &tmap );
2118                         if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) {
2119                                 Assert(tmap!=0 && Segments[seg].sides[side].tmap_num2!=0);
2120                                 Segments[seg].sides[side].tmap_num2 = Segments[cseg].sides[cside].tmap_num2 = tmap;
2121                         }
2122                         break;
2123                 }
2124
2125                 case ND_EVENT_MULTI_CLOAK: {
2126                         sbyte pnum;
2127
2128                         nd_read_byte(&pnum);
2129                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2130                                 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2131                                 Players[pnum].cloak_time = 0;
2132                                 Newdemo_players_cloaked &= ~(1 << pnum);
2133                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2134                                 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2135                                 Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
2136                                 Newdemo_players_cloaked |= (1 << pnum);
2137                         }
2138                         break;
2139                 }
2140
2141                 case ND_EVENT_MULTI_DECLOAK: {
2142                         sbyte pnum;
2143
2144                         nd_read_byte(&pnum);
2145
2146                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2147                                 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2148                                 Players[pnum].cloak_time = GameTime  - (CLOAK_TIME_MAX / 2);
2149                                 Newdemo_players_cloaked |= (1 << pnum);
2150                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2151                                 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2152                                 Players[pnum].cloak_time = 0;
2153                                 Newdemo_players_cloaked &= ~(1 << pnum);
2154                         }
2155                         break;
2156                 }
2157
2158                 case ND_EVENT_MULTI_DEATH: {
2159                         sbyte pnum;
2160
2161                         nd_read_byte(&pnum);
2162                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2163                                 Players[pnum].net_killed_total--;
2164                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2165                                 Players[pnum].net_killed_total++;
2166                         break;
2167                 }
2168
2169 #ifdef NETWORK
2170                 case ND_EVENT_MULTI_KILL: {
2171                         sbyte pnum, kill;
2172
2173                         nd_read_byte(&pnum);
2174                         nd_read_byte(&kill);
2175                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2176                                 Players[pnum].net_kills_total -= kill;
2177                                 if (Newdemo_game_mode & GM_TEAM)
2178                                         team_kills[get_team(pnum)] -= kill;
2179                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2180                                 Players[pnum].net_kills_total += kill;
2181                                 if (Newdemo_game_mode & GM_TEAM)
2182                                         team_kills[get_team(pnum)] += kill;
2183                         }
2184                         Game_mode = Newdemo_game_mode;
2185                         multi_sort_kill_list();
2186                         Game_mode = GM_NORMAL;
2187                         break;
2188                 }
2189
2190                 case ND_EVENT_MULTI_CONNECT: {
2191                         sbyte pnum, new_player;
2192                         int killed_total = 0, kills_total = 0;
2193                         char new_callsign[CALLSIGN_LEN+1], old_callsign[CALLSIGN_LEN+1];
2194
2195                         nd_read_byte(&pnum);
2196                         nd_read_byte(&new_player);
2197                         if (!new_player) {
2198                                 nd_read_string(old_callsign);
2199                                 nd_read_int(&killed_total);
2200                                 nd_read_int(&kills_total);
2201                         }
2202                         nd_read_string(new_callsign);
2203                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2204                                 Players[pnum].connected = 0;
2205                                 if (!new_player) {
2206                                         memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
2207                                         Players[pnum].net_killed_total = killed_total;
2208                                         Players[pnum].net_kills_total = kills_total;
2209                                 } else {
2210                                         N_players--;
2211                                 }
2212                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2213                                 Players[pnum].connected = 1;
2214                                 Players[pnum].net_kills_total = 0;
2215                                 Players[pnum].net_killed_total = 0;
2216                                 memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
2217                                 if (new_player)
2218                                         N_players++;
2219                         }
2220                         break;
2221                 }
2222
2223                 case ND_EVENT_MULTI_RECONNECT: {
2224                         sbyte pnum;
2225
2226                         nd_read_byte(&pnum);
2227                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2228                                 Players[pnum].connected = 0;
2229                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2230                                 Players[pnum].connected = 1;
2231                         break;
2232                 }
2233
2234                 case ND_EVENT_MULTI_DISCONNECT: {
2235                         sbyte pnum;
2236
2237                         nd_read_byte(&pnum);
2238                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2239                                 Players[pnum].connected = 1;
2240                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2241                                 Players[pnum].connected = 0;
2242                         break;
2243                 }
2244
2245                 case ND_EVENT_MULTI_SCORE: {
2246                         int score;
2247                         sbyte pnum;
2248
2249                         nd_read_byte(&pnum);
2250                         nd_read_int(&score);
2251                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2252                                 Players[pnum].score -= score;
2253                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2254                                 Players[pnum].score += score;
2255                         Game_mode = Newdemo_game_mode;
2256                         multi_sort_kill_list();
2257                         Game_mode = GM_NORMAL;
2258                         break;
2259                 }
2260
2261 #endif // NETWORK
2262                 case ND_EVENT_PLAYER_SCORE: {
2263                         int score;
2264
2265                         nd_read_int(&score);
2266                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2267                                 Players[Player_num].score -= score;
2268                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2269                                 Players[Player_num].score += score;
2270                         break;
2271                 }
2272
2273
2274                 case ND_EVENT_PRIMARY_AMMO: {
2275                         short old_ammo, new_ammo;
2276
2277                         nd_read_short(&old_ammo);
2278                         nd_read_short(&new_ammo);
2279
2280                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2281                                 Players[Player_num].primary_ammo[Primary_weapon] = old_ammo;
2282                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2283                                 Players[Player_num].primary_ammo[Primary_weapon] = new_ammo;
2284                         break;
2285                 }
2286
2287                 case ND_EVENT_SECONDARY_AMMO: {
2288                         short old_ammo, new_ammo;
2289
2290                         nd_read_short(&old_ammo);
2291                         nd_read_short(&new_ammo);
2292
2293                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2294                                 Players[Player_num].secondary_ammo[Secondary_weapon] = old_ammo;
2295                         else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2296                                 Players[Player_num].secondary_ammo[Secondary_weapon] = new_ammo;
2297                         break;
2298                 }
2299
2300                 case ND_EVENT_DOOR_OPENING: {
2301                         short segnum;
2302                         sbyte side;
2303
2304                         nd_read_short(&segnum);
2305                         nd_read_byte(&side);
2306                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2307                                 int anim_num;
2308                                 int cside;
2309                                 segment *segp, *csegp;
2310
2311                                 segp = &Segments[segnum];
2312                                 csegp = &Segments[segp->children[side]];
2313                                 cside = find_connect_side(segp, csegp);
2314                                 anim_num = Walls[segp->sides[side].wall_num].clip_num;
2315
2316                                 if (WallAnims[anim_num].flags & WCF_TMAP1) {
2317                                         segp->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[0];
2318                                 } else {
2319                                         segp->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[0];
2320                                 }
2321                         }
2322                         break;
2323                 }
2324
2325                 case ND_EVENT_LASER_LEVEL: {
2326                         sbyte old_level, new_level;
2327
2328                         nd_read_byte(&old_level);
2329                         nd_read_byte(&new_level);
2330                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2331                                 Players[Player_num].laser_level = old_level;
2332                                 update_laser_weapon_info();
2333                         } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2334                                 Players[Player_num].laser_level = new_level;
2335                                 update_laser_weapon_info();
2336                         }
2337                         break;
2338                 }
2339
2340                 case ND_EVENT_CLOAKING_WALL: {
2341                         sbyte back_wall_num,front_wall_num,type,state,cloak_value;
2342                         short l0,l1,l2,l3;
2343                         segment *segp;
2344                         int sidenum;
2345
2346                         nd_read_byte(&front_wall_num);
2347                         nd_read_byte(&back_wall_num);
2348                         nd_read_byte(&type);
2349                         nd_read_byte(&state);
2350                         nd_read_byte(&cloak_value);
2351                         nd_read_short(&l0);
2352                         nd_read_short(&l1);
2353                         nd_read_short(&l2);
2354                         nd_read_short(&l3);
2355
2356                         Walls[front_wall_num].type = type;
2357                         Walls[front_wall_num].state = state;
2358                         Walls[front_wall_num].cloak_value = cloak_value;
2359                         segp = &Segments[Walls[front_wall_num].segnum];
2360                         sidenum = Walls[front_wall_num].sidenum;
2361                         segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
2362                         segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
2363                         segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
2364                         segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
2365
2366                         Walls[back_wall_num].type = type;
2367                         Walls[back_wall_num].state = state;
2368                         Walls[back_wall_num].cloak_value = cloak_value;
2369                         segp = &Segments[Walls[back_wall_num].segnum];
2370                         sidenum = Walls[back_wall_num].sidenum;
2371                         segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
2372                         segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
2373                         segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
2374                         segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
2375
2376                         break;
2377                 }
2378
2379                 case ND_EVENT_NEW_LEVEL: {
2380                         sbyte new_level, old_level, loaded_level;
2381
2382                         nd_read_byte (&new_level);
2383                         nd_read_byte (&old_level);
2384                         if (Newdemo_vcr_state == ND_STATE_PAUSED)
2385                                 break;
2386
2387                         stop_time();
2388                         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2389                                 loaded_level = old_level;
2390                         else {
2391                                 loaded_level = new_level;
2392                                 for (i = 0; i < MAX_PLAYERS; i++) {
2393                                         Players[i].cloak_time = 0;
2394                                         Players[i].flags &= ~PLAYER_FLAGS_CLOAKED;
2395                                 }
2396                         }
2397                         if ((loaded_level < Last_secret_level) || (loaded_level > Last_level)) {
2398                                 newmenu_item m[3];
2399
2400                                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
2401                                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
2402                                 m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
2403                                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2404                                 return -1;
2405                         }
2406
2407                         LoadLevel((int)loaded_level,1);
2408                         Newdemo_cntrlcen_destroyed = 0;
2409
2410                         if (JustStartedPlayback && Newdemo_game_type >= DEMO_GAME_TYPE_D2)
2411                         {
2412                                 nd_read_int (&Num_walls);
2413                                 for (i=0;i<Num_walls;i++)    // restore the walls
2414                                 {
2415                                         nd_read_byte ((signed char *)&Walls[i].type);
2416                                         nd_read_byte ((signed char *)&Walls[i].flags);
2417                                         nd_read_byte ((signed char *)&Walls[i].state);
2418
2419                                         seg = &Segments[Walls[i].segnum];
2420                                         side = Walls[i].sidenum;
2421                                         nd_read_short (&seg->sides[side].tmap_num);
2422                                         nd_read_short (&seg->sides[side].tmap_num2);
2423                                 }
2424 #ifdef NETWORK
2425                                 if (Newdemo_game_mode & GM_CAPTURE)
2426                                         multi_apply_goal_textures ();
2427 #endif
2428                                 JustStartedPlayback=0;
2429                         }
2430
2431
2432                         // so says Rob H.!!!                    if (Newdemo_game_mode & GM_MULTI) {
2433                         // so says Rob H.!!!                            for (i = 0; i < Num_walls; i++) {
2434                         // so says Rob H.!!!                                    if (Walls[i].type == WALL_BLASTABLE)
2435                         // so says Rob H.!!!                                    {
2436                         // so says Rob H.!!!                                            int a, n;
2437                         // so says Rob H.!!!                                            int side;
2438                         // so says Rob H.!!!                                            segment *seg;
2439                         // so says Rob H.!!!
2440                         // so says Rob H.!!!                                            seg = &Segments[Walls[i].segnum];
2441                         // so says Rob H.!!!                                            side = Walls[i].sidenum;
2442                         // so says Rob H.!!!                                            a = Walls[i].clip_num;
2443                         // so says Rob H.!!!                                            n = WallAnims[a].num_frames;
2444                         // so says Rob H.!!!                                            seg->sides[side].tmap_num = WallAnims[a].frames[n-1];
2445                         // so says Rob H.!!!                                            Walls[i].flags |= WALL_BLASTED;
2446                         // so says Rob H.!!!                                    }
2447                         // so says Rob H.!!!                            }
2448                         // so says Rob H.!!!                    }
2449
2450                         reset_palette_add();                // get palette back to normal
2451                         start_time();
2452                         break;
2453                 }
2454
2455                 case ND_EVENT_EOF: {
2456                         done=-1;
2457                         PHYSFS_seek(infile, PHYSFS_tell(infile) - 1);        // get back to the EOF marker
2458                         Newdemo_at_eof = 1;
2459                         NewdemoFrameCount++;
2460                         break;
2461                 }
2462
2463                 default:
2464                         Int3();
2465                 }
2466         }
2467
2468         LastReadValue=c;
2469
2470         if (nd_bad_read) {
2471                 newmenu_item m[2];
2472
2473                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_ERR_READING;
2474                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_DEMO_OLD_CORRUPT;
2475                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2476         }
2477
2478         return done;
2479 }
2480
2481 void newdemo_goto_beginning()
2482 {
2483         //if (NewdemoFrameCount == 0)
2484         //      return;
2485         PHYSFS_seek(infile, 0);
2486         Newdemo_vcr_state = ND_STATE_PLAYBACK;
2487         if (newdemo_read_demo_start(0))
2488                 newdemo_stop_playback();
2489         if (newdemo_read_frame_information() == -1)
2490                 newdemo_stop_playback();
2491         if (newdemo_read_frame_information() == -1)
2492                 newdemo_stop_playback();
2493         Newdemo_vcr_state = ND_STATE_PAUSED;
2494         Newdemo_at_eof = 0;
2495 }
2496
2497 void newdemo_goto_end()
2498 {
2499         short frame_length, byte_count, bshort;
2500         sbyte level, bbyte, laser_level;
2501         sbyte energy, shield, c;
2502         int i, loc, bint;
2503
2504         PHYSFS_seek(infile, PHYSFS_fileLength(infile) - 2);
2505         nd_read_byte(&level);
2506
2507         if ((level < Last_secret_level) || (level > Last_level)) {
2508                 newmenu_item m[3];
2509
2510                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
2511                 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
2512                 m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
2513                 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2514                 newdemo_stop_playback();
2515                 return;
2516         }
2517         if (level != Current_level_num)
2518                 LoadLevel(level,1);
2519
2520         if (Newdemo_game_type >= DEMO_GAME_TYPE_D1) {
2521                 PHYSFS_seek(infile, PHYSFS_fileLength(infile) - 4);
2522                 nd_read_short(&byte_count);
2523                 PHYSFS_seek(infile, PHYSFS_tell(infile) - 2 - byte_count);
2524         } else
2525                 PHYSFS_seek(infile, PHYSFS_fileLength(infile) - 12);
2526
2527         nd_read_short(&frame_length);
2528         loc = (int)PHYSFS_tell(infile);
2529         if (Newdemo_game_mode & GM_MULTI)
2530                 nd_read_byte(&Newdemo_players_cloaked);
2531         else
2532                 nd_read_byte(&bbyte);
2533         nd_read_byte(&bbyte);
2534         nd_read_short(&bshort);
2535         nd_read_int(&bint);
2536
2537         nd_read_byte(&energy);
2538         nd_read_byte(&shield);
2539         Players[Player_num].energy = i2f(energy);
2540         Players[Player_num].shields = i2f(shield);
2541         nd_read_int((int *)&(Players[Player_num].flags));
2542         if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
2543                 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2544                 Newdemo_players_cloaked |= (1 << Player_num);
2545         }
2546         if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2547                 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2548         nd_read_byte((sbyte *)&Primary_weapon);
2549         nd_read_byte((sbyte *)&Secondary_weapon);
2550         for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
2551                 nd_read_short((short *)&(Players[Player_num].primary_ammo[i]));
2552         for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
2553                 nd_read_short((short *)&(Players[Player_num].secondary_ammo[i]));
2554         nd_read_byte(&laser_level);
2555         if (laser_level != Players[Player_num].laser_level) {
2556                 Players[Player_num].laser_level = laser_level;
2557                 update_laser_weapon_info();
2558         }
2559
2560         if (Newdemo_game_mode & GM_MULTI) {
2561                 nd_read_byte(&c);
2562                 N_players = (int)c;
2563                 // see newdemo_read_start_demo for explanation of
2564                 // why this is commented out
2565                 //              nd_read_byte((sbyte *)&N_players);
2566                 for (i = 0; i < N_players; i++) {
2567                         nd_read_string(Players[i].callsign);
2568                         nd_read_byte(&(Players[i].connected));
2569                         if (Newdemo_game_mode & GM_MULTI_COOP) {
2570                                 nd_read_int(&(Players[i].score));
2571                         } else {
2572                                 nd_read_short((short *)&(Players[i].net_killed_total));
2573                                 nd_read_short((short *)&(Players[i].net_kills_total));
2574                         }
2575                 }
2576         } else {
2577                 nd_read_int(&(Players[Player_num].score));
2578         }
2579
2580         PHYSFS_seek(infile, loc);
2581         PHYSFS_seek(infile, PHYSFS_tell(infile) - frame_length);
2582         nd_read_int(&NewdemoFrameCount);            // get the frame count
2583         NewdemoFrameCount--;
2584         PHYSFS_seek(infile, PHYSFS_tell(infile) + 4);
2585         Newdemo_vcr_state = ND_STATE_PLAYBACK;
2586         newdemo_read_frame_information();           // then the frame information
2587         Newdemo_vcr_state = ND_STATE_PAUSED;
2588         return;
2589 }
2590
2591 void newdemo_back_frames(int frames)
2592 {
2593         short last_frame_length;
2594         int i;
2595
2596         for (i = 0; i < frames; i++)
2597         {
2598                 PHYSFS_seek(infile, PHYSFS_tell(infile) - 10);
2599                 nd_read_short(&last_frame_length);
2600                 PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length);
2601
2602                 if (!Newdemo_at_eof && newdemo_read_frame_information() == -1) {
2603                         newdemo_stop_playback();
2604                         return;
2605                 }
2606                 if (Newdemo_at_eof)
2607                         Newdemo_at_eof = 0;
2608
2609                 PHYSFS_seek(infile, PHYSFS_tell(infile) - 10);
2610                 nd_read_short(&last_frame_length);
2611                 PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length);
2612         }
2613
2614 }
2615
2616 /*
2617  *  routine to interpolate the viewer position.  the current position is
2618  *  stored in the Viewer object.  Save this position, and read the next
2619  *  frame to get all objects read in.  Calculate the delta playback and
2620  *  the delta recording frame times between the two frames, then intepolate
2621  *  the viewers position accordingly.  nd_recorded_time is the time that it
2622  *  took the recording to render the frame that we are currently looking
2623  *  at.
2624 */
2625
2626 void interpolate_frame(fix d_play, fix d_recorded)
2627 {
2628         int i, j, num_cur_objs;
2629         fix factor;
2630         object *cur_objs;
2631
2632         factor = fixdiv(d_play, d_recorded);
2633         if (factor > F1_0)
2634                 factor = F1_0;
2635
2636         num_cur_objs = Highest_object_index;
2637         cur_objs = (object *)d_malloc(sizeof(object) * (num_cur_objs + 1));
2638         if (cur_objs == NULL) {
2639                 mprintf((0,"Couldn't get %d bytes for cur_objs in interpolate_frame\n", sizeof(object) * num_cur_objs));
2640                 Int3();
2641                 return;
2642         }
2643         for (i = 0; i <= num_cur_objs; i++)
2644                 memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
2645
2646         Newdemo_vcr_state = ND_STATE_PAUSED;
2647         if (newdemo_read_frame_information() == -1) {
2648                 d_free(cur_objs);
2649                 newdemo_stop_playback();
2650                 return;
2651         }
2652
2653         for (i = 0; i <= num_cur_objs; i++) {
2654                 for (j = 0; j <= Highest_object_index; j++) {
2655                         if (cur_objs[i].signature == Objects[j].signature) {
2656                                 sbyte render_type = cur_objs[i].render_type;
2657                                 //fix delta_p, delta_h, delta_b;
2658                                 fix delta_x, delta_y, delta_z;
2659                                 //vms_angvec cur_angles, dest_angles;
2660
2661                                 //  Extract the angles from the object orientation matrix.
2662                                 //  Some of this code taken from ai_turn_towards_vector
2663                                 //  Don't do the interpolation on certain render types which don't use an orientation matrix
2664
2665                                 if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) {
2666
2667                                         vms_vector  fvec1, fvec2, rvec1, rvec2;
2668                                         fix         mag1;
2669
2670                                         fvec1 = cur_objs[i].orient.fvec;
2671                                         vm_vec_scale(&fvec1, F1_0-factor);
2672                                         fvec2 = Objects[j].orient.fvec;
2673                                         vm_vec_scale(&fvec2, factor);
2674                                         vm_vec_add2(&fvec1, &fvec2);
2675                                         mag1 = vm_vec_normalize_quick(&fvec1);
2676                                         if (mag1 > F1_0/256) {
2677                                                 rvec1 = cur_objs[i].orient.rvec;
2678                                                 vm_vec_scale(&rvec1, F1_0-factor);
2679                                                 rvec2 = Objects[j].orient.rvec;
2680                                                 vm_vec_scale(&rvec2, factor);
2681                                                 vm_vec_add2(&rvec1, &rvec2);
2682                                                 vm_vec_normalize_quick(&rvec1); // Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1
2683                                                 vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
2684                                         }
2685
2686                                         //--old new way --      vms_vector fvec1, fvec2, rvec1, rvec2;
2687                                         //--old new way --
2688                                         //--old new way --      fvec1 = cur_objs[i].orient.fvec;
2689                                         //--old new way --      vm_vec_scale(&fvec1, F1_0-factor);
2690                                         //--old new way --      fvec2 = Objects[j].orient.fvec;
2691                                         //--old new way --      vm_vec_scale(&fvec2, factor);
2692                                         //--old new way --      vm_vec_add2(&fvec1, &fvec2);
2693                                         //--old new way --      vm_vec_normalize_quick(&fvec1);
2694                                         //--old new way --
2695                                         //--old new way --      rvec1 = cur_objs[i].orient.rvec;
2696                                         //--old new way --      vm_vec_scale(&rvec1, F1_0-factor);
2697                                         //--old new way --      rvec2 = Objects[j].orient.rvec;
2698                                         //--old new way --      vm_vec_scale(&rvec2, factor);
2699                                         //--old new way --      vm_vec_add2(&rvec1, &rvec2);
2700                                         //--old new way --      vm_vec_normalize_quick(&rvec1);
2701                                         //--old new way --
2702                                         //--old new way --      vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
2703
2704                                         // -- old fashioned way --                                      vm_extract_angles_matrix(&cur_angles, &(cur_objs[i].orient));
2705                                         // -- old fashioned way --                                      vm_extract_angles_matrix(&dest_angles, &(Objects[j].orient));
2706                                         // -- old fashioned way --
2707                                         // -- old fashioned way --                                      delta_p = (dest_angles.p - cur_angles.p);
2708                                         // -- old fashioned way --                                      delta_h = (dest_angles.h - cur_angles.h);
2709                                         // -- old fashioned way --                                      delta_b = (dest_angles.b - cur_angles.b);
2710                                         // -- old fashioned way --
2711                                         // -- old fashioned way --                                      if (delta_p != 0) {
2712                                         // -- old fashioned way --                                              if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
2713                                         // -- old fashioned way --                                              if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
2714                                         // -- old fashioned way --                                              delta_p = fixmul(delta_p, factor);
2715                                         // -- old fashioned way --                                              cur_angles.p += delta_p;
2716                                         // -- old fashioned way --                                      }
2717                                         // -- old fashioned way --                                      if (delta_h != 0) {
2718                                         // -- old fashioned way --                                              if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
2719                                         // -- old fashioned way --                                              if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
2720                                         // -- old fashioned way --                                              delta_h = fixmul(delta_h, factor);
2721                                         // -- old fashioned way --                                              cur_angles.h += delta_h;
2722                                         // -- old fashioned way --                                      }
2723                                         // -- old fashioned way --                                      if (delta_b != 0) {
2724                                         // -- old fashioned way --                                              if (delta_b > F1_0/2) delta_b = dest_angles.b - cur_angles.b - F1_0;
2725                                         // -- old fashioned way --                                              if (delta_b < -F1_0/2) delta_b = dest_angles.b - cur_angles.b + F1_0;
2726                                         // -- old fashioned way --                                              delta_b = fixmul(delta_b, factor);
2727                                         // -- old fashioned way --                                              cur_angles.b += delta_b;
2728                                         // -- old fashioned way --                                      }
2729                                 }
2730
2731                                 // Interpolate the object position.  This is just straight linear
2732                                 // interpolation.
2733
2734                                 delta_x = Objects[j].pos.x - cur_objs[i].pos.x;
2735                                 delta_y = Objects[j].pos.y - cur_objs[i].pos.y;
2736                                 delta_z = Objects[j].pos.z - cur_objs[i].pos.z;
2737
2738                                 delta_x = fixmul(delta_x, factor);
2739                                 delta_y = fixmul(delta_y, factor);
2740                                 delta_z = fixmul(delta_z, factor);
2741
2742                                 cur_objs[i].pos.x += delta_x;
2743                                 cur_objs[i].pos.y += delta_y;
2744                                 cur_objs[i].pos.z += delta_z;
2745
2746                                 // -- old fashioned way --// stuff the new angles back into the object structure
2747                                 // -- old fashioned way --                              vm_angles_2_matrix(&(cur_objs[i].orient), &cur_angles);
2748                         }
2749                 }
2750         }
2751
2752         // get back to original position in the demo file.  Reread the current
2753         // frame information again to reset all of the object stuff not covered
2754         // with Highest_object_index and the object array (previously rendered
2755         // objects, etc....)
2756
2757         newdemo_back_frames(1);
2758         newdemo_back_frames(1);
2759         if (newdemo_read_frame_information() == -1)
2760                 newdemo_stop_playback();
2761         Newdemo_vcr_state = ND_STATE_PLAYBACK;
2762
2763         for (i = 0; i <= num_cur_objs; i++)
2764                 memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object));
2765         Highest_object_index = num_cur_objs;
2766         d_free(cur_objs);
2767 }
2768
2769 void newdemo_playback_one_frame()
2770 {
2771         int frames_back, i, level;
2772         static fix base_interpol_time = 0;
2773         static fix d_recorded = 0;
2774
2775         for (i = 0; i < MAX_PLAYERS; i++)
2776                 if (Newdemo_players_cloaked & (1 << i))
2777                         Players[i].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2778
2779         if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2780                 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2781
2782         if (Newdemo_vcr_state == ND_STATE_PAUSED)       // render a frame or not
2783                 return;
2784
2785         if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2786                 DoJasonInterpolate(nd_recorded_time);
2787
2788         Control_center_destroyed = 0;
2789         Countdown_seconds_left = -1;
2790         PALETTE_FLASH_SET(0,0,0);       //clear flash
2791
2792         if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2793         {
2794                 level = Current_level_num;
2795                 if (NewdemoFrameCount == 0)
2796                         return;
2797                 else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (NewdemoFrameCount < 10)) {
2798                         newdemo_goto_beginning();
2799                         return;
2800                 }
2801                 if (Newdemo_vcr_state == ND_STATE_REWINDING)
2802                         frames_back = 10;
2803                 else
2804                         frames_back = 1;
2805                 if (Newdemo_at_eof) {
2806                         if (Newdemo_game_type == DEMO_GAME_TYPE_D1_SHARE)
2807                                 PHYSFS_seek(infile, PHYSFS_fileLength(infile) - 2);
2808                         else
2809                                 PHYSFS_seek(infile, PHYSFS_tell(infile) + 11);
2810                 }
2811                 newdemo_back_frames(frames_back);
2812
2813                 if (level != Current_level_num)
2814                         newdemo_pop_ctrlcen_triggers();
2815
2816                 if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) {
2817                         if (level != Current_level_num)
2818                                 newdemo_back_frames(1);
2819                         Newdemo_vcr_state = ND_STATE_PAUSED;
2820                 }
2821         }
2822         else if (Newdemo_vcr_state == ND_STATE_FASTFORWARD) {
2823                 if (!Newdemo_at_eof)
2824                 {
2825                         for (i = 0; i < 10; i++)
2826                         {
2827                                 if (newdemo_read_frame_information() == -1)
2828                                 {
2829                                         if (Newdemo_at_eof)
2830                                                 Newdemo_vcr_state = ND_STATE_PAUSED;
2831                                         else
2832                                                 newdemo_stop_playback();
2833                                         break;
2834                                 }
2835                         }
2836                 }
2837                 else
2838                         Newdemo_vcr_state = ND_STATE_PAUSED;
2839         }
2840         else if (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD) {
2841                 if (!Newdemo_at_eof) {
2842                         level = Current_level_num;
2843                         if (newdemo_read_frame_information() == -1) {
2844                                 if (!Newdemo_at_eof)
2845                                         newdemo_stop_playback();
2846                         }
2847                         if (level != Current_level_num) {
2848                                 if (newdemo_read_frame_information() == -1) {
2849                                         if (!Newdemo_at_eof)
2850                                                 newdemo_stop_playback();
2851                                 }
2852                         }
2853                         Newdemo_vcr_state = ND_STATE_PAUSED;
2854                 } else
2855                         Newdemo_vcr_state = ND_STATE_PAUSED;
2856         }
2857         else {
2858
2859                 //  First, uptate the total playback time to date.  Then we check to see
2860                 //  if we need to change the playback style to interpolate frames or
2861                 //  skip frames based on where the playback time is relative to the
2862                 //  recorded time.
2863
2864                 if (NewdemoFrameCount <= 0)
2865                         nd_playback_total = nd_recorded_total;      // baseline total playback time
2866                 else
2867                         nd_playback_total += FrameTime;
2868                 if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
2869                         if ((nd_playback_total * INTERPOL_FACTOR) < nd_recorded_total) {
2870                                 playback_style = INTERPOLATE_PLAYBACK;
2871                                 nd_playback_total = nd_recorded_total + FrameTime;  // baseline playback time
2872                                 base_interpol_time = nd_recorded_total;
2873                                 d_recorded = nd_recorded_time;                      // baseline delta recorded
2874                         }
2875                 if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
2876                         if (nd_playback_total > nd_recorded_total)
2877                                 playback_style = SKIP_PLAYBACK;
2878
2879
2880                 if ((playback_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) {
2881                         fix d_play = 0;
2882
2883                         if (nd_recorded_total - nd_playback_total < FrameTime) {
2884                                 d_recorded = nd_recorded_total - nd_playback_total;
2885
2886                                 while (nd_recorded_total - nd_playback_total < FrameTime) {
2887                                         object *cur_objs;
2888                                         int i, j, num_objs, level;
2889
2890                                         num_objs = Highest_object_index;
2891                                         cur_objs = (object *)d_malloc(sizeof(object) * (num_objs + 1));
2892                                         if (cur_objs == NULL) {
2893                                                 Warning ("Couldn't get %d bytes for objects in interpolate playback\n", sizeof(object) * num_objs);
2894                                                 break;
2895                                         }
2896                                         for (i = 0; i <= num_objs; i++)
2897                                                 memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
2898
2899                                         level = Current_level_num;
2900                                         if (newdemo_read_frame_information() == -1) {
2901                                                 d_free(cur_objs);
2902                                                 newdemo_stop_playback();
2903                                                 return;
2904                                         }
2905                                         if (level != Current_level_num) {
2906                                                 d_free(cur_objs);
2907                                                 if (newdemo_read_frame_information() == -1)
2908                                                         newdemo_stop_playback();
2909                                                 break;
2910                                         }
2911
2912                                         //  for each new object in the frame just read in, determine if there is
2913                                         //  a corresponding object that we have been interpolating.  If so, then
2914                                         //  copy that interpolated object to the new Objects array so that the
2915                                         //  interpolated position and orientation can be preserved.
2916
2917                                         for (i = 0; i <= num_objs; i++) {
2918                                                 for (j = 0; j <= Highest_object_index; j++) {
2919                                                         if (cur_objs[i].signature == Objects[j].signature) {
2920                                                                 memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix));
2921                                                                 memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector));
2922                                                                 break;
2923                                                         }
2924                                                 }
2925                                         }
2926                                         d_free(cur_objs);
2927                                         d_recorded += nd_recorded_time;
2928                                         base_interpol_time = nd_playback_total - FrameTime;
2929                                 }
2930                         }
2931
2932                         d_play = nd_playback_total - base_interpol_time;
2933                         interpolate_frame(d_play, d_recorded);
2934                         return;
2935                 }
2936                 else {
2937                         //mprintf ((0, "*"));
2938                         if (newdemo_read_frame_information() == -1) {
2939                                 newdemo_stop_playback();
2940                                 return;
2941                         }
2942                         if (playback_style == SKIP_PLAYBACK) {
2943                                 //mprintf ((0, "."));
2944                                 while (nd_playback_total > nd_recorded_total) {
2945                                         if (newdemo_read_frame_information() == -1) {
2946                                                 newdemo_stop_playback();
2947                                                 return;
2948                                         }
2949                                 }
2950                         }
2951                 }
2952         }
2953 }
2954
2955 void newdemo_start_recording()
2956 {
2957         Newdemo_size = (int)PHYSFSX_getFreeDiskSpace();
2958         con_printf(CON_VERBOSE, "Free space = %d\n", Newdemo_size);
2959
2960         Newdemo_size -= 100000;
2961
2962         if ((Newdemo_size+100000) <  2000000000) {
2963                 if (((int)(Newdemo_size)) < 500000) {
2964 #ifndef MACINTOSH
2965                         nm_messagebox(NULL, 1, TXT_OK, TXT_DEMO_NO_SPACE);
2966 #else
2967                         nm_messagebox(NULL, 1, TXT_OK, "Not enough space on current\ndrive to start demo recording.");
2968 #endif
2969                         return;
2970                 }
2971         }
2972
2973         Newdemo_num_written = 0;
2974         Newdemo_no_space=0;
2975         Newdemo_state = ND_STATE_RECORDING;
2976         outfile = PHYSFSX_openWriteBuffered(DEMO_FILENAME);
2977
2978 #if !defined(MACINTOSH) && !defined(_WIN32_WCE)
2979         if (outfile == NULL && errno == ENOENT)     //dir doesn't exist?
2980 #else
2981         if (outfile == NULL)                        //dir doesn't exist and no errno on mac!
2982 #endif
2983         {
2984                 PHYSFS_mkdir(DEMO_DIR); //try making directory
2985                 outfile = PHYSFSX_openWriteBuffered(DEMO_FILENAME);
2986         }
2987
2988         if (outfile == NULL)
2989         {
2990                 nm_messagebox(NULL, 1, TXT_OK, "Cannot open demo temp file");
2991                 Newdemo_state = ND_STATE_NORMAL;
2992         }
2993         else
2994                 newdemo_record_start_demo();
2995
2996 }
2997
2998 char demoname_allowed_chars[] = "azAZ09__--";
2999 void newdemo_stop_recording()
3000 {
3001         newmenu_item m[6];
3002         int l, exit;
3003         static char filename[15] = "", *s;
3004         static sbyte tmpcnt = 0;
3005         sbyte cloaked = 0;
3006         char fullname[15+FILENAME_LEN] = DEMO_DIR;
3007         unsigned short byte_count = 0;
3008
3009         exit = 0;
3010
3011         nd_write_byte(ND_EVENT_EOF);
3012         nd_write_short(frame_bytes_written - 1);
3013         if (Game_mode & GM_MULTI) {
3014                 for (l = 0; l < N_players; l++) {
3015                         if (Players[l].flags & PLAYER_FLAGS_CLOAKED)
3016                                 cloaked |= (1 << l);
3017                 }
3018                 nd_write_byte(cloaked);
3019                 nd_write_byte(ND_EVENT_EOF);
3020         } else {
3021                 nd_write_short(ND_EVENT_EOF);
3022         }
3023         nd_write_short(ND_EVENT_EOF);
3024         nd_write_int(ND_EVENT_EOF);
3025
3026         byte_count += 10;       // from frame_bytes_written
3027
3028         nd_write_byte((sbyte)(f2ir(Players[Player_num].energy)));
3029         nd_write_byte((sbyte)(f2ir(Players[Player_num].shields)));
3030         nd_write_int(Players[Player_num].flags);        // be sure players flags are set
3031         nd_write_byte((sbyte)Primary_weapon);
3032         nd_write_byte((sbyte)Secondary_weapon);
3033         byte_count += 8;
3034
3035         for (l = 0; l < MAX_PRIMARY_WEAPONS; l++)
3036                 nd_write_short((short)Players[Player_num].primary_ammo[l]);
3037
3038         for (l = 0; l < MAX_SECONDARY_WEAPONS; l++)
3039                 nd_write_short((short)Players[Player_num].secondary_ammo[l]);
3040         byte_count += (sizeof(short) * (MAX_PRIMARY_WEAPONS + MAX_SECONDARY_WEAPONS));
3041
3042         nd_write_byte(Players[Player_num].laser_level);
3043         byte_count++;
3044
3045         if (Game_mode & GM_MULTI) {
3046                 nd_write_byte((sbyte)N_players);
3047                 byte_count++;
3048                 for (l = 0; l < N_players; l++) {
3049                         nd_write_string(Players[l].callsign);
3050                         byte_count += (strlen(Players[l].callsign) + 2);
3051                         nd_write_byte(Players[l].connected);
3052                         if (Game_mode & GM_MULTI_COOP) {
3053                                 nd_write_int(Players[l].score);
3054                                 byte_count += 5;
3055                         } else {
3056                                 nd_write_short((short)Players[l].net_killed_total);
3057                                 nd_write_short((short)Players[l].net_kills_total);
3058                                 byte_count += 5;
3059                         }
3060                 }
3061         } else {
3062                 nd_write_int(Players[Player_num].score);
3063                 byte_count += 4;
3064         }
3065         nd_write_short(byte_count);
3066
3067         nd_write_byte(Current_level_num);
3068         nd_write_byte(ND_EVENT_EOF);
3069
3070         l = (int)PHYSFS_tell(outfile);
3071         PHYSFS_close(outfile);
3072         outfile = NULL;
3073         Newdemo_state = ND_STATE_NORMAL;
3074         gr_palette_load( gr_palette );
3075
3076         if (filename[0] != '\0') {
3077                 int num, i = (int)strlen(filename) - 1;
3078                 char newfile[15];
3079
3080                 while (isdigit(filename[i])) {
3081                         i--;
3082                         if (i == -1)
3083                                 break;
3084                 }
3085                 i++;
3086                 num = atoi(&(filename[i]));
3087                 num++;
3088                 filename[i] = '\0';
3089                 sprintf (newfile, "%s%d", filename, num);
3090                 strncpy(filename, newfile, 8);
3091                 filename[8] = '\0';
3092         }
3093
3094 try_again:
3095         ;
3096
3097         Newmenu_allowed_chars = demoname_allowed_chars;
3098         if (!Newdemo_no_space) {
3099                 m[0].type=NM_TYPE_INPUT; m[0].text_len = 8; m[0].text = filename;
3100                 exit = newmenu_do( NULL, TXT_SAVE_DEMO_AS, 1, &(m[0]), NULL );
3101         } else if (Newdemo_no_space == 1) {
3102                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_BAD;
3103                 m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3104                 exit = newmenu_do( NULL, NULL, 2, m, NULL );
3105         } else if (Newdemo_no_space == 2) {
3106                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_NOSPACE;
3107                 m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3108                 exit = newmenu_do( NULL, NULL, 2, m, NULL );
3109         }
3110         Newmenu_allowed_chars = NULL;
3111
3112         if (exit == -2) {                   // got bumped out from network menu
3113                 char save_file[7+FILENAME_LEN];
3114
3115                 if (filename[0] != '\0') {
3116                         strcpy(save_file, DEMO_DIR);
3117                         strcat(save_file, filename);
3118                         strcat(save_file, ".dem");
3119                 } else
3120                         sprintf (save_file, "%stmp%d.dem", DEMO_DIR, tmpcnt++);
3121                 remove(save_file);
3122                 PHYSFSX_rename(DEMO_FILENAME, save_file);
3123                 return;
3124         }
3125         if (exit == -1) {               // pressed ESC
3126                 PHYSFS_delete(DEMO_FILENAME);   // might as well remove the file
3127                 return;                     // return without doing anything
3128         }
3129
3130         if (filename[0]==0) //null string
3131                 goto try_again;
3132
3133         //check to make sure name is ok
3134         for (s=filename;*s;s++)
3135                 if (!isalnum(*s) && *s!='_') {
3136                         nm_messagebox1(NULL, NULL,1,TXT_CONTINUE, TXT_DEMO_USE_LETTERS);
3137                         goto try_again;
3138                 }
3139
3140         if (Newdemo_no_space)
3141                 strcat(fullname, m[1].text);
3142         else
3143                 strcat(fullname, m[0].text);
3144         strcat(fullname, ".dem");
3145         PHYSFS_delete(fullname);
3146         PHYSFSX_rename(DEMO_FILENAME, fullname);
3147 }
3148
3149
3150 extern char AltHogDir[64];
3151 extern char AltHogdir_initialized;
3152
3153 //returns the number of demo files on the disk
3154 int newdemo_count_demos()
3155 {
3156         char **find, **i;
3157         int NumFiles=0;
3158
3159         find = PHYSFS_enumerateFiles(DEMO_DIR);
3160
3161         for (i = find; *i != NULL; i++)
3162                 NumFiles++;
3163
3164         PHYSFS_freeList(find);
3165
3166         return NumFiles;
3167 }
3168
3169 void newdemo_start_playback(char * filename)
3170 {
3171         char **find = NULL, **i;
3172         int rnd_demo = 0;
3173         char filename2[PATH_MAX+FILENAME_LEN] = DEMO_DIR;
3174
3175 #ifdef NETWORK
3176         change_playernum_to(0);
3177 #endif
3178         First_time_playback=1;
3179         JasonPlaybackTotal=0;
3180
3181         if (filename)
3182                 strcat(filename2, filename);
3183         else
3184         {
3185                 // Randomly pick a filename
3186                 int NumFiles = 0, RandFileNum;
3187                 rnd_demo = 1;
3188
3189                 NumFiles = newdemo_count_demos();
3190
3191                 if ( NumFiles == 0 ) {
3192                         return;     // No files found!
3193                 }
3194                 RandFileNum = d_rand() % NumFiles;
3195                 NumFiles = 0;
3196
3197                 find = PHYSFS_enumerateFiles(DEMO_DIR);
3198
3199                 for (i = find; *i != NULL; i++)
3200                 {
3201                         if (NumFiles == RandFileNum)
3202                         {
3203                                 strcat(filename2, *i);
3204
3205                                 break;
3206                         }
3207                         NumFiles++;
3208                 }
3209                 PHYSFS_freeList(find);
3210
3211                 if (NumFiles > RandFileNum)
3212                         return;
3213         }
3214
3215         infile = PHYSFSX_openReadBuffered(filename2);
3216
3217         if (infile==NULL) {
3218                 mprintf( (0, "Error reading '%s'\n", filename ));
3219                 return;
3220         }
3221
3222         nd_bad_read = 0;
3223 #ifdef NETWORK
3224         change_playernum_to(0);                 // force playernum to 0
3225 #endif
3226         strncpy(nd_save_callsign, Players[Player_num].callsign, CALLSIGN_LEN);
3227         Viewer = ConsoleObject = &Objects[0];   // play properly as if console player
3228         if (newdemo_read_demo_start(rnd_demo)) {
3229                 PHYSFS_close(infile);
3230                 return;
3231         }
3232
3233         Game_mode = GM_NORMAL;
3234         Newdemo_state = ND_STATE_PLAYBACK;
3235         Newdemo_vcr_state = ND_STATE_PLAYBACK;
3236         Newdemo_old_cockpit = Cockpit_mode.intval;
3237         Newdemo_size = (unsigned int)PHYSFS_fileLength(infile);
3238         nd_bad_read = 0;
3239         Newdemo_at_eof = 0;
3240         NewdemoFrameCount = 0;
3241         Newdemo_players_cloaked = 0;
3242         playback_style = NORMAL_PLAYBACK;
3243         Function_mode = FMODE_GAME;
3244         cvar_setint(&Cockpit_3d_view[0], CV_NONE); // turn off 3d views on cockpit
3245         cvar_setint(&Cockpit_3d_view[1], CV_NONE); // turn off 3d views on cockpit
3246         newdemo_playback_one_frame();       // this one loads new level
3247         newdemo_playback_one_frame();       // get all of the objects to renderb game
3248 }
3249
3250 void newdemo_stop_playback()
3251 {
3252         PHYSFS_close(infile);
3253         Newdemo_state = ND_STATE_NORMAL;
3254 #ifdef NETWORK
3255         change_playernum_to(0);             //this is reality
3256 #endif
3257         strncpy(Players[Player_num].callsign, nd_save_callsign, CALLSIGN_LEN);
3258         cvar_setint(&Cockpit_mode, Newdemo_old_cockpit);
3259         Game_mode = GM_GAME_OVER;
3260         Function_mode = FMODE_MENU;
3261         longjmp(LeaveGame,0);               // Exit game loop
3262 }
3263
3264
3265 #ifndef NDEBUG
3266
3267 #define BUF_SIZE 16384
3268
3269 void newdemo_strip_frames(char *outname, int bytes_to_strip)
3270 {
3271         PHYSFS_file *outfile;
3272         char *buf;
3273         int total_size, bytes_done, read_elems, bytes_back;
3274         int trailer_start, loc1, loc2, stop_loc, bytes_to_read;
3275         short last_frame_length;
3276
3277         bytes_done = 0;
3278         total_size = (int)PHYSFS_fileLength(infile);
3279         outfile = PHYSFSX_openWriteBuffered(outname);
3280         if (outfile == NULL) {
3281                 newmenu_item m[1];
3282
3283                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't open output file";
3284                 newmenu_do( NULL, NULL, 1, m, NULL );
3285                 newdemo_stop_playback();
3286                 return;
3287         }
3288         buf = d_malloc(BUF_SIZE);
3289         if (buf == NULL) {
3290                 newmenu_item m[1];
3291
3292                 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't malloc output buffer";
3293                 newmenu_do( NULL, NULL, 1, m, NULL );
3294                 PHYSFS_close(outfile);
3295                 newdemo_stop_playback();
3296                 return;
3297         }
3298         newdemo_goto_end();
3299         trailer_start = (int)PHYSFS_tell(infile);
3300         PHYSFS_seek(infile, PHYSFS_tell(infile) + 11);
3301         bytes_back = 0;
3302         while (bytes_back < bytes_to_strip) {
3303                 loc1 = (int)PHYSFS_tell(infile);
3304                 //PHYSFS_seek(infile, PHYSFS_tell(infile) - 10);
3305                 //nd_read_short(&last_frame_length);
3306                 //PHYSFS_seek(infile, PHYSFS_tell(infile) + 8 - last_frame_length);
3307                 newdemo_back_frames(1);
3308                 loc2 = (int)PHYSFS_tell(infile);
3309                 bytes_back += (loc1 - loc2);
3310         }
3311         PHYSFS_seek(infile, PHYSFS_tell(infile) - 10);
3312         nd_read_short(&last_frame_length);
3313         PHYSFS_seek(infile, PHYSFS_tell(infile) - 3);
3314         stop_loc = (int)PHYSFS_tell(infile);
3315         PHYSFS_seek(infile, 0);
3316         while (stop_loc > 0) {
3317                 if (stop_loc < BUF_SIZE)
3318                         bytes_to_read = stop_loc;
3319                 else
3320                         bytes_to_read = BUF_SIZE;
3321                 read_elems = (int)PHYSFS_read(infile, buf, 1, bytes_to_read);
3322                 PHYSFS_write(outfile, buf, 1, read_elems);
3323                 stop_loc -= read_elems;
3324         }
3325         stop_loc = (int)PHYSFS_tell(outfile);
3326         PHYSFS_seek(infile, trailer_start);
3327         while ((read_elems = (int)PHYSFS_read(infile, buf, 1, BUF_SIZE)) != 0)
3328                 PHYSFS_write(outfile, buf, 1, read_elems);
3329         PHYSFS_seek(outfile, stop_loc);
3330         PHYSFS_seek(outfile, PHYSFS_tell(infile) + 1);
3331         PHYSFS_write(outfile, &last_frame_length, 2, 1);
3332         PHYSFS_close(outfile);
3333         newdemo_stop_playback();
3334
3335 }
3336
3337 #endif
3338
3339 object DemoRightExtra,DemoLeftExtra;
3340 ubyte DemoDoRight=0,DemoDoLeft=0;
3341
3342 void nd_render_extras (ubyte which,object *obj)
3343 {
3344         ubyte w=which>>4;
3345         ubyte type=which&15;
3346
3347         if (which==255)
3348         {
3349                 Int3(); // how'd we get here?
3350                 do_cockpit_window_view(w,NULL,0,WBU_WEAPON,NULL);
3351                 return;
3352         }
3353
3354         if (w)
3355         {
3356                 memcpy (&DemoRightExtra,obj,sizeof(object));  DemoDoRight=type;
3357         }
3358         else
3359         {
3360                 memcpy (&DemoLeftExtra,obj,sizeof(object)); DemoDoLeft=type;
3361         }
3362
3363 }
3364
3365 void DoJasonInterpolate (fix recorded_time)
3366 {
3367         fix the_delay;
3368
3369         JasonPlaybackTotal+=FrameTime;
3370
3371         if (!First_time_playback)
3372         {
3373                 // get the difference between the recorded time and the playback time
3374                 the_delay=(recorded_time - FrameTime);
3375                 //mprintf ((0,"The delay=%d\n", f2i(the_delay)));
3376                 if (the_delay >= f0_0)
3377                 {
3378                         stop_time();
3379                         timer_delay(the_delay);
3380                         start_time();
3381                 }
3382                 else
3383                 {
3384                         while (JasonPlaybackTotal > nd_recorded_total)
3385                                 if (newdemo_read_frame_information() == -1)
3386                                 {
3387                                         newdemo_stop_playback();
3388                                         return;
3389                                 }
3390
3391                         //the_delay = nd_recorded_total - JasonPlaybackTotal;
3392                         //if (the_delay > f0_0)
3393                         //      timer_delay(the_delay);
3394                 }
3395
3396         }
3397
3398         First_time_playback=0;
3399 }
3400
3401 #ifdef MACINTOSH
3402 #pragma global_optimizer reset
3403 #endif
3404