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