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