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