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