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