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