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