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