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