1 /* $Id: newdemo.c,v 1.12 2003/03/18 02:31:16 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 * $Log: newdemo.c,v $
20 * Revision 1.12 2003/03/18 02:31:16 btb
21 * simplify DEMO_FILENAME macro
22 *
23 * Revision 1.11 2003/03/17 07:59:11 btb
24 * also look in shared data dir for demos
25 *
26 * Revision 1.10 2003/03/17 07:10:21 btb
27 * comments/formatting
28 *
29 * Revision 1.12 1995/10/31 10:19:43 allender
30 * shareware stuff
31 *
32 * Revision 1.11 1995/10/17 13:19:16 allender
33 * close boxes for demo save
34 *
35 * Revision 1.10 1995/10/05 10:36:07 allender
36 * fixed calls to digi_play_sample to account for differing volume and angle calculations
37 *
38 * Revision 1.9 1995/09/12 15:49:13 allender
39 * define __useAppleExts__ if not already defined
40 *
41 * Revision 1.8 1995/09/05 14:28:32 allender
42 * fixed previous N_players bug in newdemo_goto_end
43 *
44 * Revision 1.7 1995/09/05 14:16:51 allender
45 * added space to allowable demo filename characters
46 * and fixed bug with netgame demos N_players got getting
47 * set correctly
48 *
49 * Revision 1.6 1995/09/01 16:10:47 allender
50 * fixed bug with reading in N_players variable on
51 * netgame demo playback
52 *
53 * Revision 1.5 1995/08/24 16:04:11 allender
54 * fix signed byte problem
55 *
56 * Revision 1.4 1995/08/12 12:21:59 allender
57 * made call to create_shortpos not swap the shortpos
58 * elements
59 *
60 * Revision 1.3 1995/08/01 16:04:19 allender
61 * made random picking of demo work
62 *
63 * Revision 1.2 1995/08/01 13:56:56 allender
64 * demo system working on the mac
65 *
66 * Revision 1.1 1995/05/16 15:28:59 allender
67 * Initial revision
68 *
69 * Revision 2.7 1995/05/26 16:16:06 john
70 * Split SATURN into define's for requiring cd, using cd, etc.
71 * Also started adding all the Rockwell stuff.
72 *
73 * Revision 2.6 1995/03/21 14:39:38 john
74 * Ifdef'd out the NETWORK code.
75 *
76 * Revision 2.5 1995/03/14 18:24:31 john
77 * Force Destination Saturn to use CD-ROM drive.
78 *
79 * Revision 2.4 1995/03/14 16:22:29 john
80 * Added cdrom alternate directory stuff.
81 *
82 * Revision 2.3 1995/03/10 12:58:33 allender
83 * only display rear view cockpit when cockpit mode was CM_FULL_COCKPIT.
84 *
85 * Revision 2.2 1995/03/08 16:12:15 allender
86 * changes for Destination Saturn
87 *
88 * Revision 2.1 1995/03/08 12:11:26 allender
89 * fix shortpos reading
90 *
91 * Revision 2.0 1995/02/27 11:29:40 john
92 * New version 2.0, which has no anonymous unions, builds with
93 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
94 *
95 * Revision 1.189 1995/02/22 14:53:42 allender
96 * missed some anonymous stuff
97 *
98 * Revision 1.188 1995/02/22 13:24:53 john
99 * Removed the vecmat anonymous unions.
100 *
101 * Revision 1.187 1995/02/22 13:13:54 allender
102 * remove anonymous unions from object structure
103 *
104 * Revision 1.186 1995/02/14 15:36:41 allender
105 * fix fix for morph effect
106 *
107 * Revision 1.185 1995/02/14 11:25:48 allender
108 * save cockpit mode and restore after playback. get orientation for morph
109 * effect when object is morph vclip
110 *
111 * Revision 1.184 1995/02/13 12:18:14 allender
112 * change to decide about interpolating or not
113 *
114 * Revision 1.183 1995/02/12 00:46:23 adam
115 * don't decide to skip frames until after at least 10 frames have
116 * passed -- allender
117 *
118 * Revision 1.182 1995/02/11 22:34:01 john
119 * Made textures page in for newdemos before playback time.
120 *
121 * Revision 1.181 1995/02/11 17:28:32 allender
122 * strip frames from end of demo
123 *
124 * Revision 1.180 1995/02/11 16:40:35 allender
125 * start of frame stripping debug code
126 *
127 * Revision 1.179 1995/02/10 17:40:06 allender
128 * put back in wall_hit_process code to fix door problem
129 *
130 * Revision 1.178 1995/02/10 17:17:24 adam
131 * allender } fix
132 *
133 * Revision 1.177 1995/02/10 17:16:24 allender
134 * fix possible tmap problems
135 *
136 * Revision 1.176 1995/02/10 15:54:37 allender
137 * changes for out of space on device.
138 *
139 * Revision 1.175 1995/02/09 19:55:00 allender
140 * fix bug with morph recording -- force rendertype to RT_POLYOBJ when
141 * playing back since it won't render until fully morphed otherwise
142 *
143 * Revision 1.174 1995/02/07 17:15:35 allender
144 * DOH!!!!!
145 *
146 * Revision 1.173 1995/02/07 17:14:21 allender
147 * immediately return when loading bogus level stuff when reading a frame
148 *
149 * Revision 1.172 1995/02/02 11:15:03 allender
150 * after loading new level, read next frame (forward or back) always because
151 * of co-op ships showing up when level is loaded
152 *
153 * Revision 1.171 1995/02/02 10:24:16 allender
154 * removed cfile stuff. Use standard FILE functions for demo playback
155 *
156 * Revision 1.170 1995/01/30 13:54:32 allender
157 * support for missions
158 *
159 * Revision 1.169 1995/01/27 16:27:35 allender
160 * put game mode to demo_game_mode when sorting multiplayer kill (and score)
161 * list
162 *
163 * Revision 1.168 1995/01/27 09:52:25 allender
164 * minor changes because of object/segment linking problems
165 *
166 * Revision 1.167 1995/01/27 09:22:28 allender
167 * changed way multi-player score is recorded. Record difference, not
168 * actual
169 *
170 * Revision 1.166 1995/01/25 14:32:44 allender
171 * changed with recorded player flags. More checks for paused state
172 * during interpolation reading of objects
173 *
174 * Revision 1.165 1995/01/25 11:23:32 allender
175 * found bug with out of disk space problem
176 *
177 * Revision 1.164 1995/01/25 11:11:33 allender
178 * coupla' things. Fix problem with objects apparently being linked in
179 * the wrong segment. Put an Int3 in to check why demos will write to
180 * end of space on drive. close demo file if demo doens't start playing
181 * back. Put obj->type == OBJ_ROBOT around checking for boss cloaking
182 *
183 * Revision 1.163 1995/01/24 19:44:30 allender
184 * fix obscure problem with rewinding and having the wrong object linked
185 * to the wrong segments. will investigate further.
186 *
187 * Revision 1.162 1995/01/23 09:31:28 allender
188 * add team score in team mode playback
189 *
190 * Revision 1.161 1995/01/20 22:47:39 matt
191 * Mission system implemented, though imcompletely
192 *
193 * Revision 1.160 1995/01/20 09:30:37 allender
194 * don't call LoadLevel with bogus data
195 *
196 * Revision 1.159 1995/01/20 09:13:23 allender
197 * *&^%&*%$ typo
198 *
199 * Revision 1.158 1995/01/20 09:12:04 allender
200 * record team names during demo recoring in GM_TEAM
201 *
202 * Revision 1.157 1995/01/19 16:31:09 allender
203 * forgot to bump demo version for new weapon change stuff
204 *
205 * Revision 1.156 1995/01/19 16:29:33 allender
206 * added new byte for weapon change (old weapon) so rewinding works
207 * correctly for weapon changes in registered
208 *
209 * Revision 1.155 1995/01/19 15:00:05 allender
210 * remove code to take away blastable walls in multiplayer demo playbacks
211 *
212 * Revision 1.154 1995/01/19 11:07:05 allender
213 * put in psuedo cloaking for boss robots. Problem is that cloaking is
214 * time based, and that don't get done in demos, so bosses just disappear.
215 * oh well
216 *
217 * Revision 1.153 1995/01/19 09:42:29 allender
218 * record laser levels in demos
219 *
220 * Revision 1.152 1995/01/18 20:43:12 allender
221 * fix laser level stuff on goto-beginning and goto-end
222 *
223 * Revision 1.151 1995/01/18 20:28:18 allender
224 * cloak robots now cloak (except maybe for boss........) Put in function
225 * to deal with control center triggers
226 *
227 * Revision 1.150 1995/01/18 18:55:07 allender
228 * bug fix
229 *
230 * Revision 1.149 1995/01/18 18:49:03 allender
231 * lots 'o stuff....record laser level. Record beginning of door opening
232 * sequence. Fix some problems with control center stuff. Control center
233 * triggers now work in reverse
234 *
235 * Revision 1.148 1995/01/18 08:51:40 allender
236 * forgot to record ammo counts at beginning of demo
237 *
238 * Revision 1.147 1995/01/17 17:42:07 allender
239 * added primary and secondary ammo counts. Changed goto_end routine
240 * to be more efficient
241 *
242 * Revision 1.146 1995/01/17 13:46:35 allender
243 * fix problem with destroyed control center and rewinding a demo.
244 * Save callsign and restore after demo playback
245 *
246 * Revision 1.145 1995/01/12 10:21:53 allender
247 * fixes for 1.0 to 1.1 demo incompatibility
248 *
249 * Revision 1.144 1995/01/05 13:51:43 allender
250 * fixed type of player num variable
251 *
252 * Revision 1.143 1995/01/04 16:58:28 allender
253 * bumped up demo version number
254 *
255 * Revision 1.142 1995/01/04 14:59:02 allender
256 * added more information to end of demo for registered. Forced game mode
257 * to be GM_NORMAL on demo playback
258 *
259 * Revision 1.141 1995/01/03 17:30:47 allender
260 * fixed logic problem with cloak stuf
261 *
262 * Revision 1.140 1995/01/03 17:12:23 allender
263 * fix for getting cloak stuff at end of demo for shareware
264 *
265 * Revision 1.139 1995/01/03 15:20:24 allender
266 * fix goto_end for shareware -- changes to goto_end for registered
267 *
268 * Revision 1.138 1995/01/03 13:13:26 allender
269 * add } I forgot
270 *
271 * Revision 1.137 1995/01/03 13:10:29 allender
272 * make score work forwards and backwards
273 *
274 * Revision 1.136 1995/01/03 11:45:20 allender
275 * added code to record players scores
276 *
277 * Revision 1.135 1994/12/30 10:03:57 allender
278 * put cloak stuff at end of demo for fast forward to the end
279 *
280 * Revision 1.134 1994/12/29 17:02:55 allender
281 * spelling fix on SHAREWARE
282 *
283 * Revision 1.133 1994/12/29 16:43:41 allender
284 * lots of new multiplayer stuff. wrapped much code with SHAREWARE defines
285 *
286 * Revision 1.132 1994/12/28 14:15:01 allender
287 * added routines to deal with connecting and reconnecting players when
288 * recording multiplayer demos
289 *
290 * Revision 1.131 1994/12/21 12:57:59 allender
291 * bug fix
292 *
293 * Revision 1.130 1994/12/21 12:46:53 allender
294 * record multi player deaths and kills
295 *
296 * Revision 1.129 1994/12/19 16:37:27 allender
297 * pick good filename when trying to save in network play and player
298 * gets bumped out of menu by multi-player code
299 *
300 * Revision 1.128 1994/12/14 10:49:01 allender
301 * reset bad_read variable when starting demo playback
302 *
303 * Revision 1.127 1994/12/14 08:53:06 allender
304 * lowered watermark for out of space
305 *
306 * Revision 1.126 1994/12/14 08:49:52 allender
307 * put up warning when starting demo recording if not enough space and
308 * not let them record
309 *
310 * Revision 1.125 1994/12/13 00:01:37 allender
311 * CLOAK FIX -- (I'm tempted to take cloak out of game because I can't
312 * seem to get it right in demo playback)
313 *
314 * Revision 1.124 1994/12/12 14:51:21 allender
315 * more fixed to multiplayer cloak stuff
316 *
317 * Revision 1.123 1994/12/12 11:33:11 allender
318 * fixed rearview mode to work again
319 *
320 * Revision 1.122 1994/12/12 11:00:16 matt
321 * Added code to handle confusion with attached objects
322 *
323 * Revision 1.121 1994/12/12 00:31:29 allender
324 * give better warning when out of space when recording. Don't record
325 * until no space left. We have 500K watermark when we now stop recording
326 *
327 * Revision 1.120 1994/12/10 16:44:54 matt
328 * Added debugging code to track down door that turns into rock
329 *
330 * Revision 1.119 1994/12/09 18:46:15 matt
331 * Added code to handle odd error condition
332 *
333 * Revision 1.118 1994/12/09 17:27:37 allender
334 * force playernum to 0 when demo is done playing
335 *
336 * Revision 1.117 1994/12/09 16:40:39 allender
337 * yet more cloak stuff. Assign cloak/invuln time when starting demo
338 * if flags are set. Check cloak and invuln time when demo
339 * even when paused
340 *
341 * Revision 1.116 1994/12/09 14:59:22 matt
342 * Added system to attach a fireball to another object for rendering purposes,
343 * so the fireball always renders on top of (after) the object.
344 *
345 * Revision 1.115 1994/12/09 12:21:45 allender
346 * only allow valid chars when typing in demo filename
347 *
348 * Revision 1.114 1994/12/08 23:19:02 allender
349 * final(?) fix for getting cloak gauge to work on demo playback
350 * with forward and reverse
351 *
352 * Revision 1.113 1994/12/08 21:34:38 allender
353 * record old and new player flags to accuratedly record cloaking and
354 * decloaking
355 * ./
356 *
357 * Revision 1.112 1994/12/08 18:04:47 allender
358 * bashed playernum right after reading it in demo header so shields
359 * and energy are put in right place
360 *
361 * Revision 1.111 1994/12/08 17:10:07 allender
362 * encode playernum in demo header. Bash viewer segment to 0 if in
363 * bogus segnum. Don't link render objs for same reason
364 *
365 * Revision 1.110 1994/12/08 15:36:12 allender
366 * cloak stuff works forwards and backwards
367 *
368 * Revision 1.109 1994/12/08 13:46:03 allender
369 * don't record rearview anymore, but leave in case statement for playback
370 * purposes. change the way letterbox <--> cockpit transitions happen
371 *
372 * Revision 1.108 1994/12/08 12:36:06 matt
373 * Added new object allocation & deallocation functions so other code
374 * could stop messing around with internal object data structures.
375 *
376 * Revision 1.107 1994/12/08 11:19:04 allender
377 * handle out of space (more) gracefully then before
378 *
379 * Revision 1.106 1994/12/08 00:29:49 allender
380 * fixed bug that didn't load level on goto_beginning
381 *
382 * Revision 1.105 1994/12/08 00:11:51 mike
383 * change matrix interpolation.
384 *
385 * Revision 1.104 1994/12/07 23:46:37 allender
386 * changed invulnerability and cloak to work (almost) correctly both
387 * in single and multi player
388 *
389 * Revision 1.103 1994/12/07 11:48:49 adam
390 * BY ALLENDER -- added dampening of interpolation factor to 1 if greater
391 * than 1 (although I have not seen this happen). this is attempt to
392 * get wobbling problem solved
393 *
394 * Revision 1.102 1994/12/07 11:23:56 allender
395 * attempt at getting rid of wobbling on demo playback
396 *
397 * Revision 1.101 1994/12/06 19:31:17 allender
398 * moved blastable wall stuff code to where we load level during demo
399 * playback
400 *
401 * Revision 1.100 1994/12/06 19:21:51 allender
402 * multi games, destroy blastable walls. Do wall toggle when control center
403 * destroyed
404 *
405 * Revision 1.99 1994/12/06 16:54:48 allender
406 * fixed code so if demo automatically started from menu, don't bring up
407 * message if demo is too old
408 *
409 * Revision 1.98 1994/12/06 13:55:15 matt
410 * Use new rounding func, f2ir()
411 *
412 * Revision 1.97 1994/12/06 13:44:45 allender
413 * suppressed compiler warnings
414 *
415 * Revision 1.96 1994/12/06 13:38:03 allender
416 * removed recording of wall hit process. I think that all bases are covered
417 * elsewhere
418 *
419 * Revision 1.95 1994/12/06 12:57:35 allender
420 * added recording of multi_decloaking. Fixed some other cloaking code so
421 * that cloak should last as long as player was cloaked. We will lose the
422 * guage effect, but the time is probably more important on playback
423 *
424 * Revision 1.94 1994/12/05 23:37:17 matt
425 * Took out calls to warning() function
426 *
427 * Revision 1.93 1994/12/03 17:52:04 yuan
428 * Localization 380ish
429 *
430 * Revision 1.92 1994/12/02 12:53:39 allender
431 * fixed goto_beginning and goto_end on demo playback
432 *
433 * Revision 1.91 1994/12/01 12:01:49 allender
434 * added multi player cloak stuff
435 *
436 * Revision 1.90 1994/11/30 09:33:58 allender
437 * added field in header to tell what version (shareware or registered)
438 * demo was recorded with. Don't allow demo recorded on one to playback
439 * on the other
440 *
441 * Revision 1.89 1994/11/29 00:31:01 allender
442 * major changes -- added level recording feature which records level
443 * advancement. Changes to internal code to handle this.
444 *
445 * Revision 1.88 1994/11/27 23:13:54 matt
446 * Made changes for new mprintf calling convention
447 *
448 * Revision 1.87 1994/11/27 23:07:35 allender
449 * starting on code to get all level transitions recorded. not done yet
450 *
451 * Revision 1.86 1994/11/27 17:39:47 matt
452 * Don't xlate tmap numbers when editor compiled out
453 *
454 * Revision 1.85 1994/11/23 09:27:21 allender
455 * put up info box with message if demo version is too old or level
456 * cannot be loaded
457 *
458 * Revision 1.84 1994/11/22 19:37:39 allender
459 * fix array mistake
460 *
461 * Revision 1.83 1994/11/22 19:35:09 allender
462 * record player ship colors in multiplayer demo recordings
463 *
464 * Revision 1.82 1994/11/19 15:36:42 mike
465 * fix fix.
466 *
467 * Revision 1.81 1994/11/19 15:23:21 mike
468 * rip out unused code
469 *
470 * Revision 1.80 1994/11/16 14:51:49 rob
471 * Fixed network/demo incompatibility.
472 *
473 * Revision 1.79 1994/11/15 10:55:48 allender
474 * made start of demo playback read initial demo information so
475 * level will get loaded. Made demo record to single file which
476 * will get renamed. Added numerics after old filename so
477 * sequential filenames would be defaulted to
478 *
479 * Revision 1.78 1994/11/15 09:46:06 allender
480 * added versioning. Fixed problems with trying to interpolating a completely
481 * 0 orientation matrix
482 *
483 * Revision 1.77 1994/11/14 14:34:31 matt
484 * Fixed up handling when textures can't be found during remap
485 *
486 * Revision 1.76 1994/11/14 09:15:29 allender
487 * make ESC from file save menu exit w/o saving. Fix letterbox, rear view,
488 * to normal cockpit mode transition to work correctly when skipping and
489 * interpolating frames
490 *
491 * Revision 1.75 1994/11/11 16:22:07 allender
492 * made morphing objects record only the object being morphed.
493 *
494 * Revision 1.74 1994/11/08 14:59:19 john
495 * Added code to respond to network while in menus.
496 *
497 * Revision 1.73 1994/11/08 14:52:20 adam
498 * *** empty log message ***
499 *
500 * Revision 1.72 1994/11/07 15:47:04 allender
501 * prompt for filename when done recording demo
502 *
503 * Revision 1.71 1994/11/07 11:47:19 allender
504 * when interpolating frames, delete weapon, fireball, and debris objects
505 * from an inpolated frame if they don't appear in the next recorded
506 * frame
507 *
508 * Revision 1.70 1994/11/07 11:02:41 allender
509 * more with interpolation. I believe that I have it right now
510 *
511 * Revision 1.69 1994/11/07 08:47:40 john
512 * Made wall state record.
513 *
514 * Revision 1.68 1994/11/05 17:22:51 john
515 * Fixed lots of sequencing problems with newdemo stuff.
516 *
517 * Revision 1.67 1994/11/04 20:11:52 john
518 * Neatening up palette stuff with demos.
519 *
520 * Revision 1.66 1994/11/04 16:49:44 allender
521 * changed newdemo_do_interpolate to default to on
522 *
523 * Revision 1.65 1994/11/04 16:44:51 allender
524 * added filename support for demo recording. more auto demo stuff
525 *
526 * Revision 1.64 1994/11/04 13:05:31 allender
527 * fixing the lifeleft variable again. (I think I got it right this time)
528 *
529 * Revision 1.63 1994/11/04 11:37:37 allender
530 * commented out fprintfs and fixed compiler warning
531 *
532 * Revision 1.62 1994/11/04 11:33:50 allender
533 * added OBJ_FLARE and OBJ_LIGHT to obj->lifeleft recording
534 *
535 * Revision 1.61 1994/11/04 11:29:21 allender
536 * more interpolation stuff -- not done yet. Fixed so hostage vclips
537 * render correctly. Changed lifeleft to full precision, but only
538 * write it when object is fireball or weapon type of object
539 *
540 * Revision 1.60 1994/11/03 10:00:11 allender
541 * fixed divide by zero in calculating render time. more interpolation
542 * stuff which isn't quite done
543 *
544 * Revision 1.59 1994/11/02 17:10:59 allender
545 * never play recorded frames when interpolation is occuring
546 *
547 * Revision 1.58 1994/11/02 14:28:58 allender
548 * profile total playback time and average frame render time
549 *
550 * Revision 1.57 1994/11/02 14:09:03 allender
551 * record rear view. start of playback interpolation code -- this
552 * is not yet done
553 *
554 * Revision 1.56 1994/11/01 13:25:30 allender
555 * drop frames if playing back demo on slower machine
556 *
557 * Revision 1.55 1994/10/31 16:10:40 allender
558 * record letterbox mode on death seq, and then restore
559 *
560 * Revision 1.54 1994/10/29 16:01:38 allender
561 * added ND_STATE_NODEMOS to indicate that there are no demos currently
562 * available for playback
563 *
564 * Revision 1.53 1994/10/29 15:38:42 allender
565 * in newdemo_start_playback, make Newdemo_at_eof = 0
566 *
567 * Revision 1.52 1994/10/28 14:45:28 john
568 * fixed typo from last checkin.
569 *
570 * Revision 1.51 1994/10/28 14:42:55 john
571 * Added sound volumes to all sound calls.
572 *
573 * Revision 1.50 1994/10/28 14:31:57 allender
574 * homing missle and autodemo stuff
575 *
576 * Revision 1.49 1994/10/28 12:42:14 allender
577 * record homing distance
578 *
579 * Revision 1.48 1994/10/27 16:57:54 allender
580 * changed demo vcr to be able to play any number of frames by storing
581 * frame length (in bytes) in the demo file. Added blowing up monitors
582 *
583 * Revision 1.47 1994/10/26 16:50:50 allender
584 * put two functions inside of VCR_MODE ifdef
585 *
586 * Revision 1.46 1994/10/26 15:20:32 allender
587 * added CT_REMOTE as valid control type for recording
588 *
589 * Revision 1.45 1994/10/26 14:45:35 allender
590 * completed hacked in vcr demo playback stuff
591 *
592 * Revision 1.44 1994/10/26 13:40:52 allender
593 * vcr playback of demo stuff
594 *
595 * Revision 1.43 1994/10/26 08:51:57 allender
596 * record player weapon change
597 *
598 * Revision 1.42 1994/10/25 15:48:01 allender
599 * add shields, energy, and player flags to demo recording.
600 * ,
601 *
602 * Revision 1.41 1994/10/24 08:19:35 allender
603 * fixed compilation errors
604 *
605 * Revision 1.40 1994/10/23 19:17:08 matt
606 * Fixed bug with "no key" messages
607 *
608 * Revision 1.39 1994/10/22 14:15:08 mike
609 * Suppress compiler warnings.
610 *
611 * Revision 1.38 1994/10/21 15:24:55 allender
612 * compressed writing of object structures with specialized code
613 * to write out only pertinent object structures.
614 *
615 * Revision 1.37 1994/10/20 13:03:17 matt
616 * Replaced old save files (MIN/SAV/HOT) with new LVL files
617 *
618 * Revision 1.36 1994/09/28 23:13:10 matt
619 * Macroized palette flash system
620 *
621 * Revision 1.35 1994/09/26 17:28:32 matt
622 * Made new multiple-object morph code work with the demo system
623 *
624 * Revision 1.34 1994/09/10 13:31:54 matt
625 * Made exploding walls a type of blastable walls.
626 * Cleaned up blastable walls, making them tmap2 bitmaps.
627 *
628 * Revision 1.33 1994/08/15 18:05:28 john
629 * *** empty log message ***
630 *
631 * Revision 1.32 1994/08/15 17:56:38 john
632 * ,
633 *
634 * Revision 1.31 1994/08/10 09:44:54 john
635 * *** empty log message ***
636 *
637 * Revision 1.30 1994/07/22 12:35:48 matt
638 * Cleaned up editor/game interactions some more.
639 *
640 * Revision 1.29 1994/07/21 13:06:45 matt
641 * Ripped out remants of old demo system, and added demo only system that
642 * disables object movement and game options from menu.
643 *
644 * Revision 1.28 1994/07/18 16:22:44 john
645 * Made all file read/writes call the same routine.
646 *
647 * Revision 1.27 1994/07/14 22:38:27 matt
648 * Added exploding doors
649 *
650 * Revision 1.26 1994/07/05 12:49:04 john
651 * Put functionality of New Hostage spec into code.
652 *
653 * Revision 1.25 1994/06/29 11:05:38 john
654 * Made demos read in compressed.
655 *
656 * Revision 1.24 1994/06/29 09:14:06 john
657 * Made files write out uncompressed and read in compressed.
658 *
659 * Revision 1.23 1994/06/28 11:55:28 john
660 * Made newdemo system record/play directly to/from disk, so
661 * we don't need the 4 MB buffer anymore.
662 *
663 * Revision 1.22 1994/06/27 15:52:38 john
664 * #define'd out the newdemo stuff
665 *
666 *
667 * Revision 1.21 1994/06/22 00:29:04 john
668 * Fixed bug with playing demo then playing game without
669 * loading new mine.
670 *
671 * Revision 1.20 1994/06/22 00:14:23 john
672 * Attempted to fix sign.
673 *
674 * Revision 1.19 1994/06/21 23:57:54 john
675 * Hopefully fixed bug with negative countdowns.
676 *
677 * Revision 1.18 1994/06/21 23:47:44 john
678 * MAde Malloc always 4*1024*1024.
679 *
680 * Revision 1.17 1994/06/21 22:58:47 john
681 * Added error if out of memory.
682 *
683 * Revision 1.16 1994/06/21 22:15:48 john
684 * Added % done to demo recording.
685 *
686 *
687 * Revision 1.15 1994/06/21 19:45:55 john
688 * Added palette effects to demo recording.
689 *
690 * Revision 1.14 1994/06/21 15:08:54 john
691 * Made demo record HUD message and cleaned up the HUD code.
692 *
693 * Revision 1.13 1994/06/21 14:20:08 john
694 * Put in hooks to record HUD messages.
695 *
696 * Revision 1.12 1994/06/20 11:50:15 john
697 * Made demo record flash effect, and control center triggers.
698 *
699 * Revision 1.11 1994/06/17 18:01:33 john
700 * A bunch of new stuff by John
701 *
702 * Revision 1.10 1994/06/17 12:13:31 john
703 * More newdemo stuff; made editor->game transition start in slew mode.
704 *
705 * Revision 1.9 1994/06/16 13:14:36 matt
706 * Fixed typo
707 *
708 * Revision 1.8 1994/06/16 13:02:07 john
709 * Added morph hooks.
710 *
711 * Revision 1.7 1994/06/15 19:01:33 john
712 * Added the capability to make 3d sounds play just once for the
713 * laser hit wall effects.
714 *
715 * Revision 1.6 1994/06/15 14:56:59 john
716 * Added triggers to demo recording.
717 *
718 * Revision 1.5 1994/06/14 20:42:15 john
719 * Made robot matztn cntr not work until no robots or player are
720 * in the segment.
721 *
722 * Revision 1.4 1994/06/14 14:43:27 john
723 * Made doors work with newdemo system.
724 *
725 * Revision 1.3 1994/06/14 11:32:29 john
726 * Made Newdemo record & restore the current mine.
727 *
728 * Revision 1.2 1994/06/13 21:02:43 john
729 * Initial version of new demo recording system.
730 *
731 * Revision 1.1 1994/06/13 11:09:00 john
732 * Initial revision
733 *
734 *
735 */
736
737
738 #ifdef HAVE_CONFIG_H
739 #include <conf.h>
740 #endif
741
742 #include <stdlib.h>
743 #include <stdio.h>
744 #include <stdarg.h>
745 #include <string.h> // for memset
746 #include <errno.h>
747 #include <ctype.h> /* for isdigit */
748 #include <limits.h>
749 #ifdef __unix__
750 #include <sys/stat.h>
751 #include <sys/types.h>
752 #endif
753
754 #include "u_mem.h"
755 #include "inferno.h"
756 #include "game.h"
757 #include "gr.h"
758 #include "stdlib.h"
759 #include "bm.h"
760 //#include "error.h"
761 #include "mono.h"
762 #include "3d.h"
763 #include "segment.h"
764 #include "texmap.h"
765 #include "laser.h"
766 #include "key.h"
767 #include "gameseg.h"
768
769 #include "object.h"
770 #include "physics.h"
771 #include "slew.h"
772 #include "render.h"
773 #include "wall.h"
774 #include "vclip.h"
775 #include "polyobj.h"
776 #include "fireball.h"
777 #include "laser.h"
778 #include "error.h"
779 #include "ai.h"
780 #include "hostage.h"
781 #include "morph.h"
782
783 #include "powerup.h"
784 #include "fuelcen.h"
785
786 #include "sounds.h"
787 #include "collide.h"
788
789 #include "lighting.h"
790 #include "newdemo.h"
791 #include "gameseq.h"
792 #include "gamesave.h"
793 #include "gamemine.h"
794 #include "switch.h"
795 #include "gauges.h"
796 #include "player.h"
797 #include "vecmat.h"
798 #include "newmenu.h"
799 #include "args.h"
800 #include "palette.h"
801 #include "multi.h"
802 #ifdef NETWORK
803 #include "network.h"
804 #endif
805 #include "text.h"
806 #include "cntrlcen.h"
807 #include "aistruct.h"
808 #include "mission.h"
809 #include "piggy.h"
810 #include "controls.h"
811 #include "d_io.h"
812 #include "timer.h"
813
814 #include "findfile.h"
815
816 #ifdef EDITOR
817 #include "editor/editor.h"
818 #endif
819
820 #ifdef MACINTOSH
821 #pragma global_optimizer off // pretty much sucks...need to look into this
822 #endif
823
824 void DoJasonInterpolate (fix recorded_time);
825
826 //#include "nocfile.h"
827
828 //Does demo start automatically?
829 int Auto_demo = 0;
830
831 byte WasRecorded [MAX_OBJECTS];
832 byte ViewWasRecorded[MAX_OBJECTS];
833 byte RenderingWasRecorded[32];
834
835 #define ND_EVENT_EOF 0 // EOF
836 #define ND_EVENT_START_DEMO 1 // Followed by 16 character, NULL terminated filename of .SAV file to use
837 #define ND_EVENT_START_FRAME 2 // Followed by integer frame number, then a fix FrameTime
838 #define ND_EVENT_VIEWER_OBJECT 3 // Followed by an object structure
839 #define ND_EVENT_RENDER_OBJECT 4 // Followed by an object structure
840 #define ND_EVENT_SOUND 5 // Followed by int soundum
841 #define ND_EVENT_SOUND_ONCE 6 // Followed by int soundum
842 #define ND_EVENT_SOUND_3D 7 // Followed by int soundum, int angle, int volume
843 #define ND_EVENT_WALL_HIT_PROCESS 8 // Followed by int segnum, int side, fix damage
844 #define ND_EVENT_TRIGGER 9 // Followed by int segnum, int side, int objnum
845 #define ND_EVENT_HOSTAGE_RESCUED 10 // Followed by int hostage_type
846 #define ND_EVENT_SOUND_3D_ONCE 11 // Followed by int soundum, int angle, int volume
847 #define ND_EVENT_MORPH_FRAME 12 // Followed by ? data
848 #define ND_EVENT_WALL_TOGGLE 13 // Followed by int seg, int side
849 #define ND_EVENT_HUD_MESSAGE 14 // Followed by char size, char * string (+null)
850 #define ND_EVENT_CONTROL_CENTER_DESTROYED 15 // Just a simple flag
851 #define ND_EVENT_PALETTE_EFFECT 16 // Followed by short r,g,b
852 #define ND_EVENT_PLAYER_ENERGY 17 // followed by byte energy
853 #define ND_EVENT_PLAYER_SHIELD 18 // followed by byte shields
854 #define ND_EVENT_PLAYER_FLAGS 19 // followed by player flags
855 #define ND_EVENT_PLAYER_WEAPON 20 // followed by weapon type and weapon number
856 #define ND_EVENT_EFFECT_BLOWUP 21 // followed by segment, side, and pnt
857 #define ND_EVENT_HOMING_DISTANCE 22 // followed by homing distance
858 #define ND_EVENT_LETTERBOX 23 // letterbox mode for death seq.
859 #define ND_EVENT_RESTORE_COCKPIT 24 // restore cockpit after death
860 #define ND_EVENT_REARVIEW 25 // going to rear view mode
861 #define ND_EVENT_WALL_SET_TMAP_NUM1 26 // Wall changed
862 #define ND_EVENT_WALL_SET_TMAP_NUM2 27 // Wall changed
863 #define ND_EVENT_NEW_LEVEL 28 // followed by level number
864 #define ND_EVENT_MULTI_CLOAK 29 // followed by player num
865 #define ND_EVENT_MULTI_DECLOAK 30 // followed by player num
866 #define ND_EVENT_RESTORE_REARVIEW 31 // restore cockpit after rearview mode
867 #define ND_EVENT_MULTI_DEATH 32 // with player number
868 #define ND_EVENT_MULTI_KILL 33 // with player number
869 #define ND_EVENT_MULTI_CONNECT 34 // with player number
870 #define ND_EVENT_MULTI_RECONNECT 35 // with player number
871 #define ND_EVENT_MULTI_DISCONNECT 36 // with player number
872 #define ND_EVENT_MULTI_SCORE 37 // playernum / score
873 #define ND_EVENT_PLAYER_SCORE 38 // followed by score
874 #define ND_EVENT_PRIMARY_AMMO 39 // with old/new ammo count
875 #define ND_EVENT_SECONDARY_AMMO 40 // with old/new ammo count
876 #define ND_EVENT_DOOR_OPENING 41 // with segment/side
877 #define ND_EVENT_LASER_LEVEL 42 // no data
878 #define ND_EVENT_PLAYER_AFTERBURNER 43 // followed by byte old ab, current ab
879 #define ND_EVENT_CLOAKING_WALL 44 // info changing while wall cloaking
880 #define ND_EVENT_CHANGE_COCKPIT 45 // change the cockpit
881 #define ND_EVENT_START_GUIDED 46 // switch to guided view
882 #define ND_EVENT_END_GUIDED 47 // stop guided view/return to ship
883 #define ND_EVENT_SECRET_THINGY 48 // 0/1 = secret exit functional/non-functional
884 #define ND_EVENT_LINK_SOUND_TO_OBJ 49 // record digi_link_sound_to_object3
885 #define ND_EVENT_KILL_SOUND_TO_OBJ 50 // record digi_kill_sound_linked_to_object
886
887
888 #define NORMAL_PLAYBACK 0
889 #define SKIP_PLAYBACK 1
890 #define INTERPOLATE_PLAYBACK 2
891 #define INTERPOL_FACTOR (F1_0 + (F1_0/5))
892
893 #define DEMO_VERSION 15 // last D1 version was 13
894 #define DEMO_GAME_TYPE 3 // 1 was shareware, 2 registered
895
896 #define DEMO_FILENAME DEMO_DIR "tmpdemo.dem"
897
898 #define DEMO_MAX_LEVELS 29
899
900
901 char nd_save_callsign[CALLSIGN_LEN+1];
902 int Newdemo_state = 0;
903 int Newdemo_vcr_state = 0;
904 int Newdemo_start_frame = -1;
905 unsigned int Newdemo_size;
906 int Newdemo_num_written;
907 int Newdemo_game_mode;
908 int Newdemo_old_cockpit;
909 byte Newdemo_no_space;
910 byte Newdemo_at_eof;
911 byte Newdemo_do_interpolate = 0; // 1
912 byte Newdemo_players_cloaked;
913 byte Newdemo_warning_given = 0;
914 byte Newdemo_cntrlcen_destroyed = 0;
915 static byte nd_bad_read;
916 int NewdemoFrameCount;
917 short frame_bytes_written = 0;
918 fix nd_playback_total;
919 fix nd_recorded_total;
920 fix nd_recorded_time;
921 byte playback_style;
922 byte First_time_playback=1;
923 fix JasonPlaybackTotal=0;
924
925
926 FILE *infile;
927 FILE *outfile=NULL;
928
newdemo_get_percent_done()929 int newdemo_get_percent_done() {
930 if ( Newdemo_state == ND_STATE_PLAYBACK ) {
931 return (ftell(infile)*100)/Newdemo_size;
932 }
933 if ( Newdemo_state == ND_STATE_RECORDING ) {
934 return ftell(outfile);
935 }
936 return 0;
937 }
938
939 #define VEL_PRECISION 12
940
my_extract_shortpos(object * objp,shortpos * spp)941 void my_extract_shortpos(object *objp, shortpos *spp)
942 {
943 int segnum;
944 byte *sp;
945
946 sp = spp->bytemat;
947 objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
948 objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
949 objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
950
951 objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
952 objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
953 objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
954
955 objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
956 objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
957 objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
958
959 segnum = spp->segment;
960 objp->segnum = segnum;
961
962 objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
963 objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
964 objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
965
966 objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
967 objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
968 objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
969 }
970
newdemo_read(void * buffer,int elsize,int nelem)971 int newdemo_read( void *buffer, int elsize, int nelem )
972 {
973 int num_read;
974 num_read = fread( buffer,elsize,nelem, infile );
975 if (ferror(infile) || feof(infile))
976 nd_bad_read = -1;
977
978 return num_read;
979 }
980
newdemo_find_object(int signature)981 int newdemo_find_object( int signature )
982 {
983 int i;
984 object * objp;
985 objp = Objects;
986 for (i=0; i<=Highest_object_index; i++, objp++ ) {
987 if ( (objp->type != OBJ_NONE) && (objp->signature == signature))
988 return i;
989 }
990 return -1;
991 }
992
newdemo_write(void * buffer,int elsize,int nelem)993 int newdemo_write( void *buffer, int elsize, int nelem )
994 {
995 int num_written, total_size;
996
997 total_size = elsize * nelem;
998 frame_bytes_written += total_size;
999 Newdemo_num_written += total_size;
1000 Assert(outfile != NULL);
1001 num_written = fwrite( buffer, elsize, nelem, outfile );
1002 //if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space) {
1003 // Newdemo_no_space=1;
1004 // newdemo_stop_recording();
1005 // return -1;
1006 //}
1007 if ((Newdemo_num_written > Newdemo_size) && !Newdemo_no_space)
1008 Newdemo_no_space=1;
1009 if (num_written == nelem && !Newdemo_no_space)
1010 return num_written;
1011
1012 Newdemo_no_space=2;
1013 newdemo_stop_recording();
1014 return -1;
1015 }
1016
1017 /*
1018 * The next bunch of files taken from Matt's gamesave.c. We have to modify
1019 * these since the demo must save more information about objects that
1020 * just a gamesave
1021 */
1022
nd_write_byte(byte b)1023 static void nd_write_byte(byte b)
1024 {
1025 newdemo_write(&b, 1, 1);
1026 }
1027
nd_write_short(short s)1028 static void nd_write_short(short s)
1029 {
1030 newdemo_write(&s, 2, 1);
1031 }
1032
nd_write_int(int i)1033 static void nd_write_int(int i)
1034 {
1035 newdemo_write(&i, 4, 1);
1036 }
1037
nd_write_string(char * str)1038 static void nd_write_string(char *str)
1039 {
1040 nd_write_byte(strlen(str) + 1);
1041 newdemo_write(str, strlen(str) + 1, 1);
1042 }
1043
nd_write_fix(fix f)1044 static void nd_write_fix(fix f)
1045 {
1046 newdemo_write(&f, sizeof(fix), 1);
1047 }
1048
nd_write_fixang(fixang f)1049 static void nd_write_fixang(fixang f)
1050 {
1051 newdemo_write(&f, sizeof(fixang), 1);
1052 }
1053
nd_write_vector(vms_vector * v)1054 static void nd_write_vector(vms_vector *v)
1055 {
1056 nd_write_fix(v->x);
1057 nd_write_fix(v->y);
1058 nd_write_fix(v->z);
1059 }
1060
nd_write_angvec(vms_angvec * v)1061 static void nd_write_angvec(vms_angvec *v)
1062 {
1063 nd_write_fixang(v->p);
1064 nd_write_fixang(v->b);
1065 nd_write_fixang(v->h);
1066 }
1067
nd_write_shortpos(object * obj)1068 void nd_write_shortpos(object *obj)
1069 {
1070 int i;
1071 shortpos sp;
1072 ubyte render_type;
1073
1074 create_shortpos(&sp, obj, 0);
1075
1076 render_type = obj->render_type;
1077 if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
1078 for (i = 0; i < 9; i++)
1079 nd_write_byte(sp.bytemat[i]);
1080 for (i = 0; i < 9; i++) {
1081 if (sp.bytemat[i] != 0)
1082 break;
1083 }
1084 if (i == 9) {
1085 Int3(); // contact Allender about this.
1086 }
1087 }
1088
1089 nd_write_short(sp.xo);
1090 nd_write_short(sp.yo);
1091 nd_write_short(sp.zo);
1092 nd_write_short(sp.segment);
1093 nd_write_short(sp.velx);
1094 nd_write_short(sp.vely);
1095 nd_write_short(sp.velz);
1096 }
1097
nd_read_byte(byte * b)1098 static void nd_read_byte(byte *b)
1099 {
1100 newdemo_read(b, 1, 1);
1101 }
1102
nd_read_short(short * s)1103 static void nd_read_short(short *s)
1104 {
1105 newdemo_read(s, 2, 1);
1106 }
1107
nd_read_int(int * i)1108 static void nd_read_int(int *i)
1109 {
1110 newdemo_read(i, 4, 1);
1111 }
1112
nd_read_string(char * str)1113 static void nd_read_string(char *str)
1114 {
1115 byte len;
1116
1117 nd_read_byte(&len);
1118 newdemo_read(str, len, 1);
1119 }
1120
nd_read_fix(fix * f)1121 static void nd_read_fix(fix *f)
1122 {
1123 newdemo_read(f, sizeof(fix), 1);
1124 }
1125
nd_read_fixang(fixang * f)1126 static void nd_read_fixang(fixang *f)
1127 {
1128 newdemo_read(f, sizeof(fixang), 1);
1129 }
1130
nd_read_vector(vms_vector * v)1131 static void nd_read_vector(vms_vector *v)
1132 {
1133 nd_read_fix(&(v->x));
1134 nd_read_fix(&(v->y));
1135 nd_read_fix(&(v->z));
1136 }
1137
nd_read_angvec(vms_angvec * v)1138 static void nd_read_angvec(vms_angvec *v)
1139 {
1140 nd_read_fixang(&(v->p));
1141 nd_read_fixang(&(v->b));
1142 nd_read_fixang(&(v->h));
1143 }
1144
nd_read_shortpos(object * obj)1145 static void nd_read_shortpos(object *obj)
1146 {
1147 shortpos sp;
1148 int i;
1149 ubyte render_type;
1150
1151 render_type = obj->render_type;
1152 if (((render_type == RT_POLYOBJ) || (render_type == RT_HOSTAGE) || (render_type == RT_MORPH)) || (obj->type == OBJ_CAMERA)) {
1153 for (i = 0; i < 9; i++)
1154 nd_read_byte(&(sp.bytemat[i]));
1155 }
1156
1157 nd_read_short(&(sp.xo));
1158 nd_read_short(&(sp.yo));
1159 nd_read_short(&(sp.zo));
1160 nd_read_short(&(sp.segment));
1161 nd_read_short(&(sp.velx));
1162 nd_read_short(&(sp.vely));
1163 nd_read_short(&(sp.velz));
1164
1165 my_extract_shortpos(obj, &sp);
1166 if ((obj->id == VCLIP_MORPHING_ROBOT) && (render_type == RT_FIREBALL) && (obj->control_type == CT_EXPLOSION))
1167 extract_orient_from_segment(&obj->orient,&Segments[obj->segnum]);
1168
1169 }
1170
1171 object *prev_obj=NULL; //ptr to last object read in
1172
nd_read_object(object * obj)1173 void nd_read_object(object *obj)
1174 {
1175 memset(obj, 0, sizeof(object));
1176
1177 /*
1178 * Do render type first, since with render_type == RT_NONE, we
1179 * blow by all other object information
1180 */
1181 nd_read_byte(&(obj->render_type));
1182 nd_read_byte(&(obj->type));
1183 if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
1184 return;
1185
1186 nd_read_byte(&(obj->id));
1187 nd_read_byte(&(obj->flags));
1188 nd_read_short((short *)&(obj->signature));
1189 nd_read_shortpos(obj);
1190
1191 if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
1192 Int3();
1193
1194 obj->attached_obj = -1;
1195
1196 switch(obj->type) {
1197
1198 case OBJ_HOSTAGE:
1199 obj->control_type = CT_POWERUP;
1200 obj->movement_type = MT_NONE;
1201 obj->size = HOSTAGE_SIZE;
1202 break;
1203
1204 case OBJ_ROBOT:
1205 obj->control_type = CT_AI;
1206 // (MarkA and MikeK said we should not do the crazy last secret stuff with multiple reactors...
1207 // This necessary code is our vindication. --MK, 2/15/96)
1208 if (obj->id != SPECIAL_REACTOR_ROBOT)
1209 obj->movement_type = MT_PHYSICS;
1210 else
1211 obj->movement_type = MT_NONE;
1212 obj->size = Polygon_models[Robot_info[obj->id].model_num].rad;
1213 obj->rtype.pobj_info.model_num = Robot_info[obj->id].model_num;
1214 obj->rtype.pobj_info.subobj_flags = 0;
1215 obj->ctype.ai_info.CLOAKED = (Robot_info[obj->id].cloak_type?1:0);
1216 break;
1217
1218 case OBJ_POWERUP:
1219 obj->control_type = CT_POWERUP;
1220 nd_read_byte(&(obj->movement_type)); // might have physics movement
1221 obj->size = Powerup_info[obj->id].size;
1222 break;
1223
1224 case OBJ_PLAYER:
1225 obj->control_type = CT_NONE;
1226 obj->movement_type = MT_PHYSICS;
1227 obj->size = Polygon_models[Player_ship->model_num].rad;
1228 obj->rtype.pobj_info.model_num = Player_ship->model_num;
1229 obj->rtype.pobj_info.subobj_flags = 0;
1230 break;
1231
1232 case OBJ_CLUTTER:
1233 obj->control_type = CT_NONE;
1234 obj->movement_type = MT_NONE;
1235 obj->size = Polygon_models[obj->id].rad;
1236 obj->rtype.pobj_info.model_num = obj->id;
1237 obj->rtype.pobj_info.subobj_flags = 0;
1238 break;
1239
1240 default:
1241 nd_read_byte(&(obj->control_type));
1242 nd_read_byte(&(obj->movement_type));
1243 nd_read_fix(&(obj->size));
1244 break;
1245 }
1246
1247
1248 nd_read_vector(&(obj->last_pos));
1249 if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
1250 nd_read_fix(&(obj->lifeleft));
1251 else {
1252 ubyte b;
1253
1254 nd_read_byte(&b);
1255 obj->lifeleft = (fix)b;
1256 // MWA old way -- won't work with big endian machines nd_read_byte((ubyte *)&(obj->lifeleft));
1257 obj->lifeleft = (fix)((int)obj->lifeleft << 12);
1258 }
1259
1260 if (obj->type == OBJ_ROBOT) {
1261 if (Robot_info[obj->id].boss_flag) {
1262 byte cloaked;
1263
1264 nd_read_byte(&cloaked);
1265 obj->ctype.ai_info.CLOAKED = cloaked;
1266 }
1267 }
1268
1269 switch (obj->movement_type) {
1270
1271 case MT_PHYSICS:
1272 nd_read_vector(&(obj->mtype.phys_info.velocity));
1273 nd_read_vector(&(obj->mtype.phys_info.thrust));
1274 break;
1275
1276 case MT_SPINNING:
1277 nd_read_vector(&(obj->mtype.spin_rate));
1278 break;
1279
1280 case MT_NONE:
1281 break;
1282
1283 default:
1284 Int3();
1285 }
1286
1287 switch (obj->control_type) {
1288
1289 case CT_EXPLOSION:
1290
1291 nd_read_fix(&(obj->ctype.expl_info.spawn_time));
1292 nd_read_fix(&(obj->ctype.expl_info.delete_time));
1293 nd_read_short(&(obj->ctype.expl_info.delete_objnum));
1294
1295 obj->ctype.expl_info.next_attach = obj->ctype.expl_info.prev_attach = obj->ctype.expl_info.attach_parent = -1;
1296
1297 if (obj->flags & OF_ATTACHED) { //attach to previous object
1298 Assert(prev_obj!=NULL);
1299 if (prev_obj->control_type == CT_EXPLOSION) {
1300 if (prev_obj->flags & OF_ATTACHED && prev_obj->ctype.expl_info.attach_parent!=-1)
1301 obj_attach(&Objects[prev_obj->ctype.expl_info.attach_parent],obj);
1302 else
1303 obj->flags &= ~OF_ATTACHED;
1304 }
1305 else
1306 obj_attach(prev_obj,obj);
1307 }
1308
1309 break;
1310
1311 case CT_LIGHT:
1312 nd_read_fix(&(obj->ctype.light_info.intensity));
1313 break;
1314
1315 case CT_AI:
1316 case CT_WEAPON:
1317 case CT_NONE:
1318 case CT_FLYING:
1319 case CT_DEBRIS:
1320 case CT_POWERUP:
1321 case CT_SLEW:
1322 case CT_CNTRLCEN:
1323 case CT_REMOTE:
1324 case CT_MORPH:
1325 break;
1326
1327 case CT_FLYTHROUGH:
1328 case CT_REPAIRCEN:
1329 default:
1330 Int3();
1331
1332 }
1333
1334 switch (obj->render_type) {
1335
1336 case RT_NONE:
1337 break;
1338
1339 case RT_MORPH:
1340 case RT_POLYOBJ: {
1341 int i, tmo;
1342
1343 if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
1344 nd_read_int(&(obj->rtype.pobj_info.model_num));
1345 nd_read_int(&(obj->rtype.pobj_info.subobj_flags));
1346 }
1347
1348 if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
1349 #if 0
1350 for (i=0;i<MAX_SUBMODELS;i++)
1351 nd_read_angvec(&(obj->pobj_info.anim_angles[i]));
1352 #endif
1353 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
1354 nd_read_angvec(&obj->rtype.pobj_info.anim_angles[i]);
1355
1356 nd_read_int(&tmo);
1357
1358 #ifndef EDITOR
1359 obj->rtype.pobj_info.tmap_override = tmo;
1360 #else
1361 if (tmo==-1)
1362 obj->rtype.pobj_info.tmap_override = -1;
1363 else {
1364 int xlated_tmo = tmap_xlate_table[tmo];
1365 if (xlated_tmo < 0) {
1366 //mprintf( (0, "Couldn't find texture for demo object, model_num = %d\n", obj->pobj_info.model_num));
1367 Int3();
1368 xlated_tmo = 0;
1369 }
1370 obj->rtype.pobj_info.tmap_override = xlated_tmo;
1371 }
1372 #endif
1373
1374 break;
1375 }
1376
1377 case RT_POWERUP:
1378 case RT_WEAPON_VCLIP:
1379 case RT_FIREBALL:
1380 case RT_HOSTAGE:
1381 nd_read_int(&(obj->rtype.vclip_info.vclip_num));
1382 nd_read_fix(&(obj->rtype.vclip_info.frametime));
1383 nd_read_byte(&(obj->rtype.vclip_info.framenum));
1384 break;
1385
1386 case RT_LASER:
1387 break;
1388
1389 default:
1390 Int3();
1391
1392 }
1393
1394 prev_obj = obj;
1395 }
1396
nd_write_object(object * obj)1397 void nd_write_object(object *obj)
1398 {
1399 int life;
1400
1401 if ((obj->type == OBJ_ROBOT) && (obj->id == SPECIAL_REACTOR_ROBOT))
1402 Int3();
1403
1404 /*
1405 * Do render_type first so on read, we can make determination of
1406 * what else to read in
1407 */
1408 nd_write_byte(obj->render_type);
1409 nd_write_byte(obj->type);
1410 if ((obj->render_type == RT_NONE) && (obj->type != OBJ_CAMERA))
1411 return;
1412
1413 nd_write_byte(obj->id);
1414 nd_write_byte(obj->flags);
1415 nd_write_short((short)obj->signature);
1416 nd_write_shortpos(obj);
1417
1418 if ((obj->type != OBJ_HOSTAGE) && (obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_POWERUP) && (obj->type != OBJ_CLUTTER)) {
1419 nd_write_byte(obj->control_type);
1420 nd_write_byte(obj->movement_type);
1421 nd_write_fix(obj->size);
1422 }
1423 if (obj->type == OBJ_POWERUP)
1424 nd_write_byte(obj->movement_type);
1425
1426 nd_write_vector(&obj->last_pos);
1427
1428 if ((obj->type == OBJ_WEAPON) && (obj->render_type == RT_WEAPON_VCLIP))
1429 nd_write_fix(obj->lifeleft);
1430 else {
1431 life = (int)obj->lifeleft;
1432 life = life >> 12;
1433 if (life > 255)
1434 life = 255;
1435 nd_write_byte((ubyte)life);
1436 }
1437
1438 if (obj->type == OBJ_ROBOT) {
1439 if (Robot_info[obj->id].boss_flag) {
1440 if ((GameTime > Boss_cloak_start_time) && (GameTime < Boss_cloak_end_time))
1441 nd_write_byte(1);
1442 else
1443 nd_write_byte(0);
1444 }
1445 }
1446
1447 switch (obj->movement_type) {
1448
1449 case MT_PHYSICS:
1450 nd_write_vector(&obj->mtype.phys_info.velocity);
1451 nd_write_vector(&obj->mtype.phys_info.thrust);
1452 break;
1453
1454 case MT_SPINNING:
1455 nd_write_vector(&obj->mtype.spin_rate);
1456 break;
1457
1458 case MT_NONE:
1459 break;
1460
1461 default:
1462 Int3();
1463 }
1464
1465 switch (obj->control_type) {
1466
1467 case CT_AI:
1468 break;
1469
1470 case CT_EXPLOSION:
1471 nd_write_fix(obj->ctype.expl_info.spawn_time);
1472 nd_write_fix(obj->ctype.expl_info.delete_time);
1473 nd_write_short(obj->ctype.expl_info.delete_objnum);
1474 break;
1475
1476 case CT_WEAPON:
1477 break;
1478
1479 case CT_LIGHT:
1480
1481 nd_write_fix(obj->ctype.light_info.intensity);
1482 break;
1483
1484 case CT_NONE:
1485 case CT_FLYING:
1486 case CT_DEBRIS:
1487 case CT_POWERUP:
1488 case CT_SLEW: //the player is generally saved as slew
1489 case CT_CNTRLCEN:
1490 case CT_REMOTE:
1491 case CT_MORPH:
1492 break;
1493
1494 case CT_REPAIRCEN:
1495 case CT_FLYTHROUGH:
1496 default:
1497 Int3();
1498
1499 }
1500
1501 switch (obj->render_type) {
1502
1503 case RT_NONE:
1504 break;
1505
1506 case RT_MORPH:
1507 case RT_POLYOBJ: {
1508 int i;
1509
1510 if ((obj->type != OBJ_ROBOT) && (obj->type != OBJ_PLAYER) && (obj->type != OBJ_CLUTTER)) {
1511 nd_write_int(obj->rtype.pobj_info.model_num);
1512 nd_write_int(obj->rtype.pobj_info.subobj_flags);
1513 }
1514
1515 if ((obj->type != OBJ_PLAYER) && (obj->type != OBJ_DEBRIS))
1516 #if 0
1517 for (i=0;i<MAX_SUBMODELS;i++)
1518 nd_write_angvec(&obj->pobj_info.anim_angles[i]);
1519 #endif
1520 for (i = 0; i < Polygon_models[obj->rtype.pobj_info.model_num].n_models; i++)
1521 nd_write_angvec(&obj->rtype.pobj_info.anim_angles[i]);
1522
1523 nd_write_int(obj->rtype.pobj_info.tmap_override);
1524
1525 break;
1526 }
1527
1528 case RT_POWERUP:
1529 case RT_WEAPON_VCLIP:
1530 case RT_FIREBALL:
1531 case RT_HOSTAGE:
1532 nd_write_int(obj->rtype.vclip_info.vclip_num);
1533 nd_write_fix(obj->rtype.vclip_info.frametime);
1534 nd_write_byte(obj->rtype.vclip_info.framenum);
1535 break;
1536
1537 case RT_LASER:
1538 break;
1539
1540 default:
1541 Int3();
1542
1543 }
1544
1545 }
1546
1547 int JustStartedRecording=0,JustStartedPlayback=0;
1548
newdemo_record_start_demo()1549 void newdemo_record_start_demo()
1550 {
1551 int i;
1552
1553 stop_time();
1554 nd_write_byte(ND_EVENT_START_DEMO);
1555 nd_write_byte(DEMO_VERSION);
1556 nd_write_byte(DEMO_GAME_TYPE);
1557 nd_write_fix(GameTime);
1558
1559 #ifdef NETWORK
1560 if (Game_mode & GM_MULTI)
1561 nd_write_int(Game_mode | (Player_num << 16));
1562 else
1563 #endif
1564 // NOTE LINK TO ABOVE!!!
1565 nd_write_int(Game_mode);
1566 #ifdef NETWORK
1567
1568 if (Game_mode & GM_TEAM) {
1569 nd_write_byte(Netgame.team_vector);
1570 nd_write_string(Netgame.team_name[0]);
1571 nd_write_string(Netgame.team_name[1]);
1572 }
1573
1574 if (Game_mode & GM_MULTI) {
1575 nd_write_byte((byte)N_players);
1576 for (i = 0; i < N_players; i++) {
1577 nd_write_string(Players[i].callsign);
1578 nd_write_byte(Players[i].connected);
1579
1580 if (Game_mode & GM_MULTI_COOP) {
1581 nd_write_int(Players[i].score);
1582 } else {
1583 nd_write_short((short)Players[i].net_killed_total);
1584 nd_write_short((short)Players[i].net_kills_total);
1585 }
1586 }
1587 } else
1588 #endif
1589 // NOTE LINK TO ABOVE!!!
1590 nd_write_int(Players[Player_num].score);
1591
1592 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
1593 nd_write_short((short)Players[Player_num].primary_ammo[i]);
1594
1595 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
1596 nd_write_short((short)Players[Player_num].secondary_ammo[i]);
1597
1598 nd_write_byte((byte)Players[Player_num].laser_level);
1599
1600 // Support for missions added here
1601
1602 nd_write_string(Current_mission_filename);
1603
1604 nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
1605 nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
1606 nd_write_int(Players[Player_num].flags); // be sure players flags are set
1607 nd_write_byte((byte)Primary_weapon);
1608 nd_write_byte((byte)Secondary_weapon);
1609 Newdemo_start_frame = FrameCount;
1610 JustStartedRecording=1;
1611
1612 newdemo_set_new_level(Current_level_num);
1613 start_time();
1614
1615 }
1616
newdemo_record_start_frame(int frame_number,fix frame_time)1617 void newdemo_record_start_frame(int frame_number, fix frame_time )
1618 {
1619 int i;
1620
1621 if (Newdemo_no_space) {
1622 newdemo_stop_playback();
1623 return;
1624 }
1625
1626 stop_time();
1627
1628 for (i=0;i<MAX_OBJECTS;i++)
1629 {
1630 WasRecorded[i]=0;
1631 ViewWasRecorded[i]=0;
1632 }
1633 for (i=0;i<32;i++)
1634 RenderingWasRecorded[i]=0;
1635
1636 frame_number -= Newdemo_start_frame;
1637
1638 Assert(frame_number >= 0 );
1639
1640 nd_write_byte(ND_EVENT_START_FRAME);
1641 nd_write_short(frame_bytes_written - 1); // from previous frame
1642 frame_bytes_written=3;
1643 nd_write_int(frame_number);
1644 nd_write_int(frame_time);
1645 start_time();
1646
1647 }
1648
newdemo_record_render_object(object * obj)1649 void newdemo_record_render_object(object * obj)
1650 {
1651 if (ViewWasRecorded[obj-Objects])
1652 return;
1653
1654 //if (obj==&Objects[Players[Player_num].objnum] && !Player_is_dead)
1655 // return;
1656
1657 stop_time();
1658 nd_write_byte(ND_EVENT_RENDER_OBJECT);
1659 nd_write_object(obj);
1660 start_time();
1661 }
1662
1663 extern ubyte RenderingType;
1664
newdemo_record_viewer_object(object * obj)1665 void newdemo_record_viewer_object(object * obj)
1666 {
1667
1668 if (ViewWasRecorded[obj-Objects] && (ViewWasRecorded[obj-Objects]-1)==RenderingType)
1669 return;
1670 //if (WasRecorded[obj-Objects])
1671 // return;
1672 if (RenderingWasRecorded[RenderingType])
1673 return;
1674
1675 ViewWasRecorded[obj-Objects]=RenderingType+1;
1676 RenderingWasRecorded[RenderingType]=1;
1677 stop_time();
1678 nd_write_byte(ND_EVENT_VIEWER_OBJECT);
1679 nd_write_byte(RenderingType);
1680 nd_write_object(obj);
1681 start_time();
1682 }
1683
newdemo_record_sound(int soundno)1684 void newdemo_record_sound( int soundno )
1685 {
1686 stop_time();
1687 nd_write_byte(ND_EVENT_SOUND);
1688 nd_write_int( soundno );
1689 start_time();
1690 }
1691
1692 //--unused-- void newdemo_record_sound_once( int soundno ) {
1693 //--unused-- stop_time();
1694 //--unused-- nd_write_byte( ND_EVENT_SOUND_ONCE );
1695 //--unused-- nd_write_int( soundno );
1696 //--unused-- start_time();
1697 //--unused-- }
1698 //--unused--
1699
newdemo_record_cockpit_change(int mode)1700 void newdemo_record_cockpit_change (int mode)
1701 {
1702 stop_time();
1703 nd_write_byte (ND_EVENT_CHANGE_COCKPIT);
1704 nd_write_int(mode);
1705 start_time();
1706 }
1707
1708
newdemo_record_sound_3d(int soundno,int angle,int volume)1709 void newdemo_record_sound_3d( int soundno, int angle, int volume )
1710 {
1711 stop_time();
1712 nd_write_byte( ND_EVENT_SOUND_3D );
1713 nd_write_int( soundno );
1714 nd_write_int( angle );
1715 nd_write_int( volume );
1716 start_time();
1717 }
1718
newdemo_record_sound_3d_once(int soundno,int angle,int volume)1719 void newdemo_record_sound_3d_once( int soundno, int angle, int volume )
1720 {
1721 stop_time();
1722 nd_write_byte( ND_EVENT_SOUND_3D_ONCE );
1723 nd_write_int( soundno );
1724 nd_write_int( angle );
1725 nd_write_int( volume );
1726 start_time();
1727 }
1728
1729
newdemo_record_link_sound_to_object3(int soundno,short objnum,fix max_volume,fix max_distance,int loop_start,int loop_end)1730 void newdemo_record_link_sound_to_object3( int soundno, short objnum, fix max_volume, fix max_distance, int loop_start, int loop_end )
1731 {
1732 stop_time();
1733 nd_write_byte( ND_EVENT_LINK_SOUND_TO_OBJ );
1734 nd_write_int( soundno );
1735 nd_write_int( Objects[objnum].signature );
1736 nd_write_int( max_volume );
1737 nd_write_int( max_distance );
1738 nd_write_int( loop_start );
1739 nd_write_int( loop_end );
1740 start_time();
1741 }
1742
newdemo_record_kill_sound_linked_to_object(int objnum)1743 void newdemo_record_kill_sound_linked_to_object( int objnum )
1744 {
1745 stop_time();
1746 nd_write_byte( ND_EVENT_KILL_SOUND_TO_OBJ );
1747 nd_write_int( Objects[objnum].signature );
1748 start_time();
1749 }
1750
1751
newdemo_record_wall_hit_process(int segnum,int side,int damage,int playernum)1752 void newdemo_record_wall_hit_process( int segnum, int side, int damage, int playernum )
1753 {
1754 stop_time();
1755 //segnum = segnum;
1756 //side = side;
1757 //damage = damage;
1758 //playernum = playernum;
1759 nd_write_byte( ND_EVENT_WALL_HIT_PROCESS );
1760 nd_write_int( segnum );
1761 nd_write_int( side );
1762 nd_write_int( damage );
1763 nd_write_int( playernum );
1764 start_time();
1765 }
1766
newdemo_record_guided_start()1767 void newdemo_record_guided_start ()
1768 {
1769 nd_write_byte (ND_EVENT_START_GUIDED);
1770 }
1771
newdemo_record_guided_end()1772 void newdemo_record_guided_end ()
1773 {
1774 nd_write_byte (ND_EVENT_END_GUIDED);
1775 }
1776
newdemo_record_secret_exit_blown(int truth)1777 void newdemo_record_secret_exit_blown(int truth)
1778 {
1779 stop_time();
1780 nd_write_byte( ND_EVENT_SECRET_THINGY );
1781 nd_write_int( truth );
1782 start_time();
1783 }
1784
newdemo_record_trigger(int segnum,int side,int objnum,int shot)1785 void newdemo_record_trigger( int segnum, int side, int objnum,int shot )
1786 {
1787 stop_time();
1788 nd_write_byte( ND_EVENT_TRIGGER );
1789 nd_write_int( segnum );
1790 nd_write_int( side );
1791 nd_write_int( objnum );
1792 nd_write_int(shot);
1793 start_time();
1794 }
1795
newdemo_record_hostage_rescued(int hostage_number)1796 void newdemo_record_hostage_rescued( int hostage_number ) {
1797 stop_time();
1798 nd_write_byte( ND_EVENT_HOSTAGE_RESCUED );
1799 nd_write_int( hostage_number );
1800 start_time();
1801 }
1802
newdemo_record_morph_frame(morph_data * md)1803 void newdemo_record_morph_frame(morph_data *md)
1804 {
1805 stop_time();
1806
1807 nd_write_byte( ND_EVENT_MORPH_FRAME );
1808 #if 0
1809 newdemo_write( md->morph_vecs, sizeof(md->morph_vecs), 1 );
1810 newdemo_write( md->submodel_active, sizeof(md->submodel_active), 1 );
1811 newdemo_write( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 );
1812 #endif
1813 nd_write_object( md->obj );
1814 start_time();
1815 }
1816
newdemo_record_wall_toggle(int segnum,int side)1817 void newdemo_record_wall_toggle( int segnum, int side )
1818 {
1819 stop_time();
1820 nd_write_byte( ND_EVENT_WALL_TOGGLE );
1821 nd_write_int( segnum );
1822 nd_write_int( side );
1823 start_time();
1824 }
1825
newdemo_record_control_center_destroyed()1826 void newdemo_record_control_center_destroyed()
1827 {
1828 stop_time();
1829 nd_write_byte( ND_EVENT_CONTROL_CENTER_DESTROYED );
1830 nd_write_int( Countdown_seconds_left );
1831 start_time();
1832 }
1833
newdemo_record_hud_message(char * message)1834 void newdemo_record_hud_message( char * message )
1835 {
1836 stop_time();
1837 nd_write_byte( ND_EVENT_HUD_MESSAGE );
1838 nd_write_string(message);
1839 start_time();
1840 }
1841
newdemo_record_palette_effect(short r,short g,short b)1842 void newdemo_record_palette_effect(short r, short g, short b )
1843 {
1844 stop_time();
1845 nd_write_byte( ND_EVENT_PALETTE_EFFECT );
1846 nd_write_short( r );
1847 nd_write_short( g );
1848 nd_write_short( b );
1849 start_time();
1850 }
1851
newdemo_record_player_energy(int old_energy,int energy)1852 void newdemo_record_player_energy(int old_energy, int energy)
1853 {
1854 stop_time();
1855 nd_write_byte( ND_EVENT_PLAYER_ENERGY );
1856 nd_write_byte((byte) old_energy);
1857 nd_write_byte((byte) energy);
1858 start_time();
1859 }
1860
newdemo_record_player_afterburner(fix old_afterburner,fix afterburner)1861 void newdemo_record_player_afterburner(fix old_afterburner, fix afterburner)
1862 {
1863 stop_time();
1864 nd_write_byte( ND_EVENT_PLAYER_AFTERBURNER );
1865 nd_write_byte((byte) (old_afterburner>>9));
1866 nd_write_byte((byte) (afterburner>>9));
1867 start_time();
1868 }
1869
newdemo_record_player_shields(int old_shield,int shield)1870 void newdemo_record_player_shields(int old_shield, int shield)
1871 {
1872 stop_time();
1873 nd_write_byte( ND_EVENT_PLAYER_SHIELD );
1874 nd_write_byte((byte)old_shield);
1875 nd_write_byte((byte)shield);
1876 start_time();
1877 }
1878
newdemo_record_player_flags(uint oflags,uint flags)1879 void newdemo_record_player_flags(uint oflags, uint flags)
1880 {
1881 stop_time();
1882 nd_write_byte( ND_EVENT_PLAYER_FLAGS );
1883 nd_write_int(((short)oflags << 16) | (short)flags);
1884 start_time();
1885 }
1886
newdemo_record_player_weapon(int weapon_type,int weapon_num)1887 void newdemo_record_player_weapon(int weapon_type, int weapon_num)
1888 {
1889 stop_time();
1890 nd_write_byte( ND_EVENT_PLAYER_WEAPON );
1891 nd_write_byte((byte)weapon_type);
1892 nd_write_byte((byte)weapon_num);
1893 if (weapon_type)
1894 nd_write_byte((byte)Secondary_weapon);
1895 else
1896 nd_write_byte((byte)Primary_weapon);
1897 start_time();
1898 }
1899
newdemo_record_effect_blowup(short segment,int side,vms_vector * pnt)1900 void newdemo_record_effect_blowup(short segment, int side, vms_vector *pnt)
1901 {
1902 stop_time();
1903 nd_write_byte (ND_EVENT_EFFECT_BLOWUP);
1904 nd_write_short(segment);
1905 nd_write_byte((byte)side);
1906 nd_write_vector(pnt);
1907 start_time();
1908 }
1909
newdemo_record_homing_distance(fix distance)1910 void newdemo_record_homing_distance(fix distance)
1911 {
1912 stop_time();
1913 nd_write_byte(ND_EVENT_HOMING_DISTANCE);
1914 nd_write_short((short)(distance>>16));
1915 start_time();
1916 }
1917
newdemo_record_letterbox(void)1918 void newdemo_record_letterbox(void)
1919 {
1920 stop_time();
1921 nd_write_byte(ND_EVENT_LETTERBOX);
1922 start_time();
1923 }
1924
newdemo_record_rearview(void)1925 void newdemo_record_rearview(void)
1926 {
1927 stop_time();
1928 nd_write_byte(ND_EVENT_REARVIEW);
1929 start_time();
1930 }
1931
newdemo_record_restore_cockpit(void)1932 void newdemo_record_restore_cockpit(void)
1933 {
1934 stop_time();
1935 nd_write_byte(ND_EVENT_RESTORE_COCKPIT);
1936 start_time();
1937 }
1938
newdemo_record_restore_rearview(void)1939 void newdemo_record_restore_rearview(void)
1940 {
1941 stop_time();
1942 nd_write_byte(ND_EVENT_RESTORE_REARVIEW);
1943 start_time();
1944 }
1945
newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)1946 void newdemo_record_wall_set_tmap_num1(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1947 {
1948 stop_time();
1949 nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM1);
1950 nd_write_short(seg);
1951 nd_write_byte(side);
1952 nd_write_short(cseg);
1953 nd_write_byte(cside);
1954 nd_write_short(tmap);
1955 start_time();
1956 }
1957
newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)1958 void newdemo_record_wall_set_tmap_num2(short seg,ubyte side,short cseg,ubyte cside,short tmap)
1959 {
1960 stop_time();
1961 nd_write_byte(ND_EVENT_WALL_SET_TMAP_NUM2);
1962 nd_write_short(seg);
1963 nd_write_byte(side);
1964 nd_write_short(cseg);
1965 nd_write_byte(cside);
1966 nd_write_short(tmap);
1967 start_time();
1968 }
1969
newdemo_record_multi_cloak(int pnum)1970 void newdemo_record_multi_cloak(int pnum)
1971 {
1972 stop_time();
1973 nd_write_byte(ND_EVENT_MULTI_CLOAK);
1974 nd_write_byte((byte)pnum);
1975 start_time();
1976 }
1977
newdemo_record_multi_decloak(int pnum)1978 void newdemo_record_multi_decloak(int pnum)
1979 {
1980 stop_time();
1981 nd_write_byte(ND_EVENT_MULTI_DECLOAK);
1982 nd_write_byte((byte)pnum);
1983 start_time();
1984 }
1985
newdemo_record_multi_death(int pnum)1986 void newdemo_record_multi_death(int pnum)
1987 {
1988 stop_time();
1989 nd_write_byte(ND_EVENT_MULTI_DEATH);
1990 nd_write_byte((byte)pnum);
1991 start_time();
1992 }
1993
newdemo_record_multi_kill(int pnum,byte kill)1994 void newdemo_record_multi_kill(int pnum, byte kill)
1995 {
1996 stop_time();
1997 nd_write_byte(ND_EVENT_MULTI_KILL);
1998 nd_write_byte((byte)pnum);
1999 nd_write_byte(kill);
2000 start_time();
2001 }
2002
newdemo_record_multi_connect(int pnum,int new_player,char * new_callsign)2003 void newdemo_record_multi_connect(int pnum, int new_player, char *new_callsign)
2004 {
2005 stop_time();
2006 nd_write_byte(ND_EVENT_MULTI_CONNECT);
2007 nd_write_byte((byte)pnum);
2008 nd_write_byte((byte)new_player);
2009 if (!new_player) {
2010 nd_write_string(Players[pnum].callsign);
2011 nd_write_int(Players[pnum].net_killed_total);
2012 nd_write_int(Players[pnum].net_kills_total);
2013 }
2014 nd_write_string(new_callsign);
2015 start_time();
2016 }
2017
newdemo_record_multi_reconnect(int pnum)2018 void newdemo_record_multi_reconnect(int pnum)
2019 {
2020 stop_time();
2021 nd_write_byte(ND_EVENT_MULTI_RECONNECT);
2022 nd_write_byte((byte)pnum);
2023 start_time();
2024 }
2025
newdemo_record_multi_disconnect(int pnum)2026 void newdemo_record_multi_disconnect(int pnum)
2027 {
2028 stop_time();
2029 nd_write_byte(ND_EVENT_MULTI_DISCONNECT);
2030 nd_write_byte((byte)pnum);
2031 start_time();
2032 }
2033
newdemo_record_player_score(int score)2034 void newdemo_record_player_score(int score)
2035 {
2036 stop_time();
2037 nd_write_byte(ND_EVENT_PLAYER_SCORE);
2038 nd_write_int(score);
2039 start_time();
2040 }
2041
newdemo_record_multi_score(int pnum,int score)2042 void newdemo_record_multi_score(int pnum, int score)
2043 {
2044 stop_time();
2045 nd_write_byte(ND_EVENT_MULTI_SCORE);
2046 nd_write_byte((byte)pnum);
2047 nd_write_int(score - Players[pnum].score); // called before score is changed!!!!
2048 start_time();
2049 }
2050
newdemo_record_primary_ammo(int old_ammo,int new_ammo)2051 void newdemo_record_primary_ammo(int old_ammo, int new_ammo)
2052 {
2053 stop_time();
2054 nd_write_byte(ND_EVENT_PRIMARY_AMMO);
2055 if (old_ammo < 0)
2056 nd_write_short((short)new_ammo);
2057 else
2058 nd_write_short((short)old_ammo);
2059 nd_write_short((short)new_ammo);
2060 start_time();
2061 }
2062
newdemo_record_secondary_ammo(int old_ammo,int new_ammo)2063 void newdemo_record_secondary_ammo(int old_ammo, int new_ammo)
2064 {
2065 stop_time();
2066 nd_write_byte(ND_EVENT_SECONDARY_AMMO);
2067 if (old_ammo < 0)
2068 nd_write_short((short)new_ammo);
2069 else
2070 nd_write_short((short)old_ammo);
2071 nd_write_short((short)new_ammo);
2072 start_time();
2073 }
2074
newdemo_record_door_opening(int segnum,int side)2075 void newdemo_record_door_opening(int segnum, int side)
2076 {
2077 stop_time();
2078 nd_write_byte(ND_EVENT_DOOR_OPENING);
2079 nd_write_short((short)segnum);
2080 nd_write_byte((byte)side);
2081 start_time();
2082 }
2083
newdemo_record_laser_level(byte old_level,byte new_level)2084 void newdemo_record_laser_level(byte old_level, byte new_level)
2085 {
2086 stop_time();
2087 nd_write_byte(ND_EVENT_LASER_LEVEL);
2088 nd_write_byte(old_level);
2089 nd_write_byte(new_level);
2090 start_time();
2091 }
2092
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)2093 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)
2094 {
2095 Assert(front_wall_num <= 255 && back_wall_num <= 255);
2096
2097 stop_time();
2098 nd_write_byte(ND_EVENT_CLOAKING_WALL);
2099 nd_write_byte(front_wall_num);
2100 nd_write_byte(back_wall_num);
2101 nd_write_byte(type);
2102 nd_write_byte(state);
2103 nd_write_byte(cloak_value);
2104 nd_write_short(l0>>8);
2105 nd_write_short(l1>>8);
2106 nd_write_short(l2>>8);
2107 nd_write_short(l3>>8);
2108 start_time();
2109 }
2110
newdemo_set_new_level(int level_num)2111 void newdemo_set_new_level(int level_num)
2112 {
2113 int i;
2114 int side;
2115 segment *seg;
2116
2117 stop_time();
2118 nd_write_byte(ND_EVENT_NEW_LEVEL);
2119 nd_write_byte((byte)level_num);
2120 nd_write_byte((byte)Current_level_num);
2121
2122 if (JustStartedRecording==1)
2123 {
2124 nd_write_int(Num_walls);
2125 for (i=0;i<Num_walls;i++)
2126 {
2127 nd_write_byte (Walls[i].type);
2128 nd_write_byte (Walls[i].flags);
2129 nd_write_byte (Walls[i].state);
2130
2131 seg = &Segments[Walls[i].segnum];
2132 side = Walls[i].sidenum;
2133 nd_write_short (seg->sides[side].tmap_num);
2134 nd_write_short (seg->sides[side].tmap_num2);
2135 JustStartedRecording=0;
2136 }
2137 }
2138
2139 start_time();
2140 }
2141
newdemo_read_demo_start(int rnd_demo)2142 int newdemo_read_demo_start(int rnd_demo)
2143 {
2144 byte i, version, game_type, laser_level;
2145 char c, energy, shield;
2146 char text[50], current_mission[9];
2147
2148 nd_read_byte(&c);
2149 if ((c != ND_EVENT_START_DEMO) || nd_bad_read) {
2150 newmenu_item m[1];
2151
2152 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_CORRUPT);
2153 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2154 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2155 return 1;
2156 }
2157 nd_read_byte(&version);
2158 nd_read_byte(&game_type);
2159 if (game_type < DEMO_GAME_TYPE) {
2160 newmenu_item m[2];
2161
2162 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
2163 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2164 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = " In Descent: First Strike";
2165
2166 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2167 return 1;
2168 }
2169 if (game_type != DEMO_GAME_TYPE) {
2170 newmenu_item m[2];
2171
2172 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_RECORDED);
2173 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2174 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = " In Unknown Descent version";
2175
2176 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2177 return 1;
2178 }
2179 if (version < DEMO_VERSION) {
2180 if (!rnd_demo) {
2181 newmenu_item m[1];
2182 sprintf(text, "%s %s", TXT_CANT_PLAYBACK, TXT_DEMO_OLD);
2183 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2184 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2185 }
2186 return 1;
2187 }
2188 nd_read_fix(&GameTime);
2189 Boss_cloak_start_time=Boss_cloak_end_time=GameTime;
2190 JasonPlaybackTotal=0;
2191
2192 nd_read_int(&Newdemo_game_mode);
2193
2194 #ifdef NETWORK
2195 change_playernum_to((Newdemo_game_mode >> 16) & 0x7);
2196 if (Newdemo_game_mode & GM_TEAM) {
2197 nd_read_byte(&(Netgame.team_vector));
2198 nd_read_string(Netgame.team_name[0]);
2199 nd_read_string(Netgame.team_name[1]);
2200 }
2201 if (Newdemo_game_mode & GM_MULTI) {
2202
2203 multi_new_game();
2204 nd_read_byte(&c);
2205 N_players = (int)c;
2206 // changed this to above two lines -- breaks on the mac because of
2207 // endian issues
2208 // nd_read_byte((byte *)&N_players);
2209 for (i = 0 ; i < N_players; i++) {
2210 Players[i].cloak_time = 0;
2211 Players[i].invulnerable_time = 0;
2212 nd_read_string(Players[i].callsign);
2213 nd_read_byte(&(Players[i].connected));
2214
2215 if (Newdemo_game_mode & GM_MULTI_COOP) {
2216 nd_read_int(&(Players[i].score));
2217 } else {
2218 nd_read_short((short *)&(Players[i].net_killed_total));
2219 nd_read_short((short *)&(Players[i].net_kills_total));
2220 }
2221 }
2222 Game_mode = Newdemo_game_mode;
2223 multi_sort_kill_list();
2224 Game_mode = GM_NORMAL;
2225 } else
2226 #endif
2227 nd_read_int(&(Players[Player_num].score)); // Note link to above if!
2228
2229 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
2230 nd_read_short((short*)&(Players[Player_num].primary_ammo[i]));
2231
2232 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
2233 nd_read_short((short*)&(Players[Player_num].secondary_ammo[i]));
2234
2235 nd_read_byte(&laser_level);
2236 if (laser_level != Players[Player_num].laser_level) {
2237 Players[Player_num].laser_level = laser_level;
2238 update_laser_weapon_info();
2239 }
2240
2241 // Support for missions
2242
2243 nd_read_string(current_mission);
2244 if (!load_mission_by_name(current_mission)) {
2245 if (!rnd_demo) {
2246 newmenu_item m[1];
2247
2248 sprintf(text, TXT_NOMISSION4DEMO, current_mission);
2249 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = text;
2250 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
2251 }
2252 return 1;
2253 }
2254
2255 nd_recorded_total = 0;
2256 nd_playback_total = 0;
2257 nd_read_byte(&energy);
2258 nd_read_byte(&shield);
2259
2260 nd_read_int((int *)&(Players[Player_num].flags));
2261 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
2262 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2263 Newdemo_players_cloaked |= (1 << Player_num);
2264 }
2265 if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
2266 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2267
2268 nd_read_byte((byte *)&Primary_weapon);
2269 nd_read_byte((byte *)&Secondary_weapon);
2270
2271 // Next bit of code to fix problem that I introduced between 1.0 and 1.1
2272 // check the next byte -- it _will_ be a load_new_level event. If it is
2273 // not, then we must shift all bytes up by one.
2274
2275 Players[Player_num].energy = i2f(energy);
2276 Players[Player_num].shields = i2f(shield);
2277 JustStartedPlayback=1;
2278 return 0;
2279 }
2280
newdemo_pop_ctrlcen_triggers()2281 void newdemo_pop_ctrlcen_triggers()
2282 {
2283 int anim_num, n, i;
2284 int side, cside;
2285 segment *seg, *csegp;
2286
2287 for (i = 0; i < ControlCenterTriggers.num_links; i++) {
2288 seg = &Segments[ControlCenterTriggers.seg[i]];
2289 side = ControlCenterTriggers.side[i];
2290 csegp = &Segments[seg->children[side]];
2291 cside = find_connect_side(seg, csegp);
2292 anim_num = Walls[seg->sides[side].wall_num].clip_num;
2293 n = WallAnims[anim_num].num_frames;
2294 if (WallAnims[anim_num].flags & WCF_TMAP1) {
2295 seg->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[n-1];
2296 } else {
2297 seg->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[n-1];
2298 }
2299 }
2300 }
2301
2302 #define N_PLAYER_SHIP_TEXTURES 6
2303
2304 void nd_render_extras (ubyte,object *);
2305 extern void multi_apply_goal_textures ();
2306 ubyte Newdemo_flying_guided=0;
2307
newdemo_read_frame_information()2308 int newdemo_read_frame_information()
2309 {
2310 int done, segnum, side, objnum, soundno, angle, volume, i,shot;
2311 object *obj;
2312 ubyte c,WhichWindow;
2313 static byte saved_letter_cockpit;
2314 static byte saved_rearview_cockpit;
2315 object extraobj;
2316 static char LastReadValue=101;
2317 segment *seg;
2318
2319 done = 0;
2320
2321 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2322 for (segnum=0; segnum <= Highest_segment_index; segnum++)
2323 Segments[segnum].objects = -1;
2324
2325 reset_objects(1);
2326 Players[Player_num].homing_object_dist = -F1_0;
2327
2328 prev_obj = NULL;
2329
2330 while( !done ) {
2331 nd_read_byte(&c);
2332 if (nd_bad_read) { done = -1; break; }
2333
2334 switch( c ) {
2335
2336 case ND_EVENT_START_FRAME: { // Followed by an integer frame number, then a fix FrameTime
2337 short last_frame_length;
2338
2339 done=1;
2340 nd_read_short(&last_frame_length);
2341 nd_read_int(&NewdemoFrameCount);
2342 nd_read_int((int *)&nd_recorded_time);
2343 if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2344 nd_recorded_total += nd_recorded_time;
2345 NewdemoFrameCount--;
2346
2347 if (nd_bad_read) { done = -1; break; }
2348 break;
2349 }
2350
2351 case ND_EVENT_VIEWER_OBJECT: // Followed by an object structure
2352 nd_read_byte (&WhichWindow);
2353 if (WhichWindow&15)
2354 {
2355 //mprintf ((0,"Reading extra!\n"));
2356 nd_read_object (&extraobj);
2357 if (Newdemo_vcr_state!=ND_STATE_PAUSED)
2358 {
2359 if (nd_bad_read) { done = -1; break; }
2360
2361 nd_render_extras (WhichWindow,&extraobj);
2362 }
2363 }
2364 else
2365 {
2366 //mprintf ((0,"Reading viewer!\n"));
2367 //Viewer=&Objects[0];
2368 nd_read_object(Viewer);
2369
2370 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2371 if (nd_bad_read) { done = -1; break; }
2372 segnum = Viewer->segnum;
2373 Viewer->next = Viewer->prev = Viewer->segnum = -1;
2374
2375 // HACK HACK HACK -- since we have multiple level recording, it can be the case
2376 // HACK HACK HACK -- that when rewinding the demo, the viewer is in a segment
2377 // HACK HACK HACK -- that is greater than the highest index of segments. Bash
2378 // HACK HACK HACK -- the viewer to segment 0 for bogus view.
2379
2380 if (segnum > Highest_segment_index)
2381 segnum = 0;
2382 obj_link(Viewer-Objects,segnum);
2383 }
2384 }
2385 break;
2386
2387 case ND_EVENT_RENDER_OBJECT: // Followed by an object structure
2388 objnum = obj_allocate();
2389 if (objnum==-1)
2390 break;
2391 obj = &Objects[objnum];
2392 nd_read_object(obj);
2393 if (nd_bad_read) { done = -1; break; }
2394 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2395 segnum = obj->segnum;
2396 obj->next = obj->prev = obj->segnum = -1;
2397
2398 // HACK HACK HACK -- don't render objects is segments greater than Highest_segment_index
2399 // HACK HACK HACK -- (see above)
2400
2401 if (segnum > Highest_segment_index)
2402 break;
2403
2404 obj_link(obj-Objects,segnum);
2405 #ifdef NETWORK
2406 if ((obj->type == OBJ_PLAYER) && (Newdemo_game_mode & GM_MULTI)) {
2407 int player;
2408
2409 if (Newdemo_game_mode & GM_TEAM)
2410 player = get_team(obj->id);
2411 else
2412 player = obj->id;
2413 if (player == 0)
2414 break;
2415 player--;
2416
2417 for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2418 multi_player_textures[player][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[obj->rtype.pobj_info.model_num].first_texture+i]];
2419
2420 multi_player_textures[player][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2]];
2421 multi_player_textures[player][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(player)*2+1]];
2422 obj->rtype.pobj_info.alt_textures = player+1;
2423 }
2424 #endif
2425 }
2426 break;
2427
2428 case ND_EVENT_SOUND:
2429 nd_read_int(&soundno);
2430 if (nd_bad_read) {done = -1; break; }
2431 if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2432 digi_play_sample( soundno, F1_0 );
2433 break;
2434
2435 //--unused case ND_EVENT_SOUND_ONCE:
2436 //--unused nd_read_int(&soundno);
2437 //--unused if (nd_bad_read) { done = -1; break; }
2438 //--unused if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2439 //--unused digi_play_sample_once( soundno, F1_0 );
2440 //--unused break;
2441
2442 case ND_EVENT_SOUND_3D:
2443 nd_read_int(&soundno);
2444 nd_read_int(&angle);
2445 nd_read_int(&volume);
2446 if (nd_bad_read) { done = -1; break; }
2447 if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2448 digi_play_sample_3d( soundno, angle, volume, 0 );
2449 break;
2450
2451 case ND_EVENT_SOUND_3D_ONCE:
2452 nd_read_int(&soundno);
2453 nd_read_int(&angle);
2454 nd_read_int(&volume);
2455 if (nd_bad_read) { done = -1; break; }
2456 if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
2457 digi_play_sample_3d( soundno, angle, volume, 1 );
2458 break;
2459
2460 case ND_EVENT_LINK_SOUND_TO_OBJ:
2461 {
2462 int soundno, objnum, max_volume, max_distance, loop_start, loop_end;
2463 int signature;
2464 nd_read_int( &soundno );
2465 nd_read_int( &signature );
2466 nd_read_int( &max_volume );
2467 nd_read_int( &max_distance );
2468 nd_read_int( &loop_start );
2469 nd_read_int( &loop_end );
2470 objnum = newdemo_find_object( signature );
2471 if ( objnum > -1 ) { // @mk, 2/22/96, John told me to.
2472 digi_link_sound_to_object3( soundno, objnum, 1, max_volume, max_distance, loop_start, loop_end );
2473 }
2474 }
2475 break;
2476
2477 case ND_EVENT_KILL_SOUND_TO_OBJ:
2478 {
2479 int objnum, signature;
2480 nd_read_int( &signature );
2481 objnum = newdemo_find_object( signature );
2482 if ( objnum > -1 ) { // @mk, 2/22/96, John told me to.
2483 digi_kill_sound_linked_to_object(objnum);
2484 }
2485 }
2486 break;
2487
2488 case ND_EVENT_WALL_HIT_PROCESS: {
2489 int player, segnum;
2490 fix damage;
2491
2492 nd_read_int(&segnum);
2493 nd_read_int(&side);
2494 nd_read_fix(&damage);
2495 nd_read_int(&player);
2496 if (nd_bad_read) { done = -1; break; }
2497 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2498 wall_hit_process(&Segments[segnum], side, damage, player, &(Objects[0]) );
2499 break;
2500 }
2501
2502 case ND_EVENT_TRIGGER:
2503 nd_read_int(&segnum);
2504 nd_read_int(&side);
2505 nd_read_int(&objnum);
2506 nd_read_int(&shot);
2507 if (nd_bad_read) { done = -1; break; }
2508 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2509 {
2510 mprintf ((0,"EVENT TRIGGER! shot=%d\n",shot));
2511
2512 if (Triggers[Walls[Segments[segnum].sides[side].wall_num].trigger].type == TT_SECRET_EXIT) {
2513 int truth;
2514
2515 nd_read_byte(&c);
2516 Assert(c == ND_EVENT_SECRET_THINGY);
2517 nd_read_int(&truth);
2518 if (!truth)
2519 check_trigger(&Segments[segnum], side, objnum,shot);
2520 } else
2521 check_trigger(&Segments[segnum], side, objnum,shot);
2522 }
2523 break;
2524
2525 case ND_EVENT_HOSTAGE_RESCUED: {
2526 int hostage_number;
2527
2528 nd_read_int(&hostage_number);
2529 if (nd_bad_read) { done = -1; break; }
2530 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2531 hostage_rescue( hostage_number );
2532 break;
2533 }
2534
2535 case ND_EVENT_MORPH_FRAME: {
2536 #if 0
2537 morph_data *md;
2538
2539 md = &morph_objects[0];
2540 if (newdemo_read( md->morph_vecs, sizeof(md->morph_vecs), 1 )!=1) { done=-1; break; }
2541 if (newdemo_read( md->submodel_active, sizeof(md->submodel_active), 1 )!=1) { done=-1; break; }
2542 if (newdemo_read( md->submodel_startpoints, sizeof(md->submodel_startpoints), 1 )!=1) { done=-1; break; }
2543 #endif
2544 objnum = obj_allocate();
2545 if (objnum==-1)
2546 break;
2547 obj = &Objects[objnum];
2548 nd_read_object(obj);
2549 obj->render_type = RT_POLYOBJ;
2550 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2551 if (nd_bad_read) { done = -1; break; }
2552 if (Newdemo_vcr_state != ND_STATE_PAUSED) {
2553 segnum = obj->segnum;
2554 obj->next = obj->prev = obj->segnum = -1;
2555 obj_link(obj-Objects,segnum);
2556 }
2557 }
2558 break;
2559 }
2560
2561 case ND_EVENT_WALL_TOGGLE:
2562 nd_read_int(&segnum);
2563 nd_read_int(&side);
2564 if (nd_bad_read) {done = -1; break; }
2565 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2566 wall_toggle(&Segments[segnum], side);
2567 break;
2568
2569 case ND_EVENT_CONTROL_CENTER_DESTROYED:
2570 nd_read_int(&Countdown_seconds_left);
2571 Control_center_destroyed = 1;
2572 if (nd_bad_read) { done = -1; break; }
2573 if (!Newdemo_cntrlcen_destroyed) {
2574 newdemo_pop_ctrlcen_triggers();
2575 Newdemo_cntrlcen_destroyed = 1;
2576 //do_controlcen_destroyed_stuff(NULL);
2577 }
2578 break;
2579
2580 case ND_EVENT_HUD_MESSAGE: {
2581 char hud_msg[60];
2582
2583 nd_read_string(&(hud_msg[0]));
2584 if (nd_bad_read) { done = -1; break; }
2585 HUD_init_message( hud_msg );
2586 break;
2587 }
2588 case ND_EVENT_START_GUIDED:
2589 Newdemo_flying_guided=1;
2590 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2591 Newdemo_flying_guided=0;
2592 break;
2593 case ND_EVENT_END_GUIDED:
2594 Newdemo_flying_guided=0;
2595 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2596 Newdemo_flying_guided=1;
2597 break;
2598
2599 case ND_EVENT_PALETTE_EFFECT: {
2600 short r, g, b;
2601
2602 nd_read_short(&r);
2603 nd_read_short(&g);
2604 nd_read_short(&b);
2605 if (nd_bad_read) { done = -1; break; }
2606 PALETTE_FLASH_SET(r,g,b);
2607 break;
2608 }
2609
2610 case ND_EVENT_PLAYER_ENERGY: {
2611 ubyte energy;
2612 ubyte old_energy;
2613
2614 nd_read_byte(&old_energy);
2615 nd_read_byte(&energy);
2616 if (nd_bad_read) {done = -1; break; }
2617 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2618 Players[Player_num].energy = i2f(energy);
2619 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2620 if (old_energy != 255)
2621 Players[Player_num].energy = i2f(old_energy);
2622 }
2623 break;
2624 }
2625
2626 case ND_EVENT_PLAYER_AFTERBURNER: {
2627 ubyte afterburner;
2628 ubyte old_afterburner;
2629
2630 nd_read_byte(&old_afterburner);
2631 nd_read_byte(&afterburner);
2632 if (nd_bad_read) {done = -1; break; }
2633 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2634 Afterburner_charge = afterburner<<9;
2635 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2636 if (old_afterburner != 255)
2637 Afterburner_charge = old_afterburner<<9;
2638 }
2639 break;
2640 }
2641
2642 case ND_EVENT_PLAYER_SHIELD: {
2643 ubyte shield;
2644 ubyte old_shield;
2645
2646 nd_read_byte(&old_shield);
2647 nd_read_byte(&shield);
2648 if (nd_bad_read) {done = -1; break; }
2649 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2650 Players[Player_num].shields = i2f(shield);
2651 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2652 if (old_shield != 255)
2653 Players[Player_num].shields = i2f(old_shield);
2654 }
2655 break;
2656 }
2657
2658 case ND_EVENT_PLAYER_FLAGS: {
2659 uint oflags;
2660
2661 nd_read_int((int *)&(Players[Player_num].flags));
2662 if (nd_bad_read) {done = -1; break; }
2663
2664 oflags = Players[Player_num].flags >> 16;
2665 Players[Player_num].flags &= 0xffff;
2666
2667 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || ((Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) && (oflags != 0xffff)) ) {
2668 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2669 Players[Player_num].cloak_time = 0;
2670 Newdemo_players_cloaked &= ~(1 << Player_num);
2671 }
2672 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2673 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2674 Newdemo_players_cloaked |= (1 << Player_num);
2675 }
2676 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2677 Players[Player_num].invulnerable_time = 0;
2678 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2679 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2680 Players[Player_num].flags = oflags;
2681 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2682 if (!(oflags & PLAYER_FLAGS_CLOAKED) && (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2683 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2684 Newdemo_players_cloaked |= (1 << Player_num);
2685 }
2686 if ((oflags & PLAYER_FLAGS_CLOAKED) && !(Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)) {
2687 Players[Player_num].cloak_time = 0;
2688 Newdemo_players_cloaked &= ~(1 << Player_num);
2689 }
2690 if (!(oflags & PLAYER_FLAGS_INVULNERABLE) && (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2691 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
2692 if ((oflags & PLAYER_FLAGS_INVULNERABLE) && !(Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE))
2693 Players[Player_num].invulnerable_time = 0;
2694 }
2695 update_laser_weapon_info(); // in case of quad laser change
2696 break;
2697 }
2698
2699 case ND_EVENT_PLAYER_WEAPON: {
2700 byte weapon_type, weapon_num;
2701 byte old_weapon;
2702
2703 nd_read_byte(&weapon_type);
2704 nd_read_byte(&weapon_num);
2705 nd_read_byte(&old_weapon);
2706 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2707 if (weapon_type == 0)
2708 Primary_weapon = (int)weapon_num;
2709 else
2710 Secondary_weapon = (int)weapon_num;
2711 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2712 if (weapon_type == 0)
2713 Primary_weapon = (int)old_weapon;
2714 else
2715 Secondary_weapon = (int)old_weapon;
2716 }
2717 break;
2718 }
2719
2720 case ND_EVENT_EFFECT_BLOWUP: {
2721 short segnum;
2722 byte side;
2723 vms_vector pnt;
2724 object dummy;
2725
2726 //create a dummy object which will be the weapon that hits
2727 //the monitor. the blowup code wants to know who the parent of the
2728 //laser is, so create a laser whose parent is the player
2729 dummy.ctype.laser_info.parent_type = OBJ_PLAYER;
2730
2731 nd_read_short(&segnum);
2732 nd_read_byte(&side);
2733 nd_read_vector(&pnt);
2734 if (Newdemo_vcr_state != ND_STATE_PAUSED)
2735 check_effect_blowup(&(Segments[segnum]), side, &pnt, &dummy, 0);
2736 break;
2737 }
2738
2739 case ND_EVENT_HOMING_DISTANCE: {
2740 short distance;
2741
2742 nd_read_short(&distance);
2743 Players[Player_num].homing_object_dist = i2f((int)(distance << 16));
2744 break;
2745 }
2746
2747 case ND_EVENT_LETTERBOX:
2748 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2749 saved_letter_cockpit = Cockpit_mode;
2750 select_cockpit(CM_LETTERBOX);
2751 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2752 select_cockpit(saved_letter_cockpit);
2753 break;
2754
2755 case ND_EVENT_CHANGE_COCKPIT: {
2756 int dummy;
2757
2758 nd_read_int (&dummy);
2759 select_cockpit (dummy);
2760
2761 break;
2762 }
2763 case ND_EVENT_REARVIEW:
2764 if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2765 saved_rearview_cockpit = Cockpit_mode;
2766 if (Cockpit_mode == CM_FULL_COCKPIT)
2767 select_cockpit(CM_REAR_VIEW);
2768 Rear_view=1;
2769 } else if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2770 if (saved_rearview_cockpit == CM_REAR_VIEW) // hack to be sure we get a good cockpit on restore
2771 saved_rearview_cockpit = CM_FULL_COCKPIT;
2772 select_cockpit(saved_rearview_cockpit);
2773 Rear_view=0;
2774 }
2775 break;
2776
2777 case ND_EVENT_RESTORE_COCKPIT:
2778 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2779 saved_letter_cockpit = Cockpit_mode;
2780 select_cockpit(CM_LETTERBOX);
2781 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2782 select_cockpit(saved_letter_cockpit);
2783 break;
2784
2785
2786 case ND_EVENT_RESTORE_REARVIEW:
2787 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2788 saved_rearview_cockpit = Cockpit_mode;
2789 if (Cockpit_mode == CM_FULL_COCKPIT)
2790 select_cockpit(CM_REAR_VIEW);
2791 Rear_view=1;
2792 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2793 if (saved_rearview_cockpit == CM_REAR_VIEW) // hack to be sure we get a good cockpit on restore
2794 saved_rearview_cockpit = CM_FULL_COCKPIT;
2795 select_cockpit(saved_rearview_cockpit);
2796 Rear_view=0;
2797 }
2798 break;
2799
2800
2801 case ND_EVENT_WALL_SET_TMAP_NUM1: {
2802 short seg, cseg, tmap;
2803 ubyte side,cside;
2804
2805 nd_read_short(&seg);
2806 nd_read_byte(&side);
2807 nd_read_short(&cseg);
2808 nd_read_byte(&cside);
2809 nd_read_short( &tmap );
2810 if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD))
2811 Segments[seg].sides[side].tmap_num = Segments[cseg].sides[cside].tmap_num = tmap;
2812 break;
2813 }
2814
2815 case ND_EVENT_WALL_SET_TMAP_NUM2: {
2816 short seg, cseg, tmap;
2817 ubyte side,cside;
2818
2819 nd_read_short(&seg);
2820 nd_read_byte(&side);
2821 nd_read_short(&cseg);
2822 nd_read_byte(&cside);
2823 nd_read_short( &tmap );
2824 if ((Newdemo_vcr_state != ND_STATE_PAUSED) && (Newdemo_vcr_state != ND_STATE_REWINDING) && (Newdemo_vcr_state != ND_STATE_ONEFRAMEBACKWARD)) {
2825 Assert(tmap!=0 && Segments[seg].sides[side].tmap_num2!=0);
2826 Segments[seg].sides[side].tmap_num2 = Segments[cseg].sides[cside].tmap_num2 = tmap;
2827 }
2828 break;
2829 }
2830
2831 case ND_EVENT_MULTI_CLOAK: {
2832 byte pnum;
2833
2834 nd_read_byte(&pnum);
2835 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2836 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2837 Players[pnum].cloak_time = 0;
2838 Newdemo_players_cloaked &= ~(1 << pnum);
2839 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2840 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2841 Players[pnum].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2842 Newdemo_players_cloaked |= (1 << pnum);
2843 }
2844 break;
2845 }
2846
2847 case ND_EVENT_MULTI_DECLOAK: {
2848 byte pnum;
2849
2850 nd_read_byte(&pnum);
2851
2852 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2853 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2854 Players[pnum].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
2855 Newdemo_players_cloaked |= (1 << pnum);
2856 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2857 Players[pnum].flags &= ~PLAYER_FLAGS_CLOAKED;
2858 Players[pnum].cloak_time = 0;
2859 Newdemo_players_cloaked &= ~(1 << pnum);
2860 }
2861 break;
2862 }
2863
2864 case ND_EVENT_MULTI_DEATH: {
2865 byte pnum;
2866
2867 nd_read_byte(&pnum);
2868 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2869 Players[pnum].net_killed_total--;
2870 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2871 Players[pnum].net_killed_total++;
2872 break;
2873 }
2874
2875 #ifdef NETWORK
2876 case ND_EVENT_MULTI_KILL: {
2877 byte pnum, kill;
2878
2879 nd_read_byte(&pnum);
2880 nd_read_byte(&kill);
2881 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2882 Players[pnum].net_kills_total -= kill;
2883 if (Newdemo_game_mode & GM_TEAM)
2884 team_kills[get_team(pnum)] -= kill;
2885 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2886 Players[pnum].net_kills_total += kill;
2887 if (Newdemo_game_mode & GM_TEAM)
2888 team_kills[get_team(pnum)] += kill;
2889 }
2890 Game_mode = Newdemo_game_mode;
2891 multi_sort_kill_list();
2892 Game_mode = GM_NORMAL;
2893 break;
2894 }
2895
2896 case ND_EVENT_MULTI_CONNECT: {
2897 byte pnum, new_player;
2898 int killed_total, kills_total;
2899 char new_callsign[CALLSIGN_LEN+1], old_callsign[CALLSIGN_LEN+1];
2900
2901 nd_read_byte(&pnum);
2902 nd_read_byte(&new_player);
2903 if (!new_player) {
2904 nd_read_string(old_callsign);
2905 nd_read_int(&killed_total);
2906 nd_read_int(&kills_total);
2907 }
2908 nd_read_string(new_callsign);
2909 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
2910 Players[pnum].connected = 0;
2911 if (!new_player) {
2912 memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
2913 Players[pnum].net_killed_total = killed_total;
2914 Players[pnum].net_kills_total = kills_total;
2915 } else {
2916 N_players--;
2917 }
2918 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
2919 Players[pnum].connected = 1;
2920 Players[pnum].net_kills_total = 0;
2921 Players[pnum].net_killed_total = 0;
2922 memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
2923 if (new_player)
2924 N_players++;
2925 }
2926 break;
2927 }
2928
2929 case ND_EVENT_MULTI_RECONNECT: {
2930 byte pnum;
2931
2932 nd_read_byte(&pnum);
2933 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2934 Players[pnum].connected = 0;
2935 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2936 Players[pnum].connected = 1;
2937 break;
2938 }
2939
2940 case ND_EVENT_MULTI_DISCONNECT: {
2941 byte pnum;
2942
2943 nd_read_byte(&pnum);
2944 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2945 Players[pnum].connected = 1;
2946 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2947 Players[pnum].connected = 0;
2948 break;
2949 }
2950
2951 case ND_EVENT_MULTI_SCORE: {
2952 int score;
2953 byte pnum;
2954
2955 nd_read_byte(&pnum);
2956 nd_read_int(&score);
2957 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2958 Players[pnum].score -= score;
2959 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2960 Players[pnum].score += score;
2961 Game_mode = Newdemo_game_mode;
2962 multi_sort_kill_list();
2963 Game_mode = GM_NORMAL;
2964 break;
2965 }
2966
2967 #endif // NETWORK
2968 case ND_EVENT_PLAYER_SCORE: {
2969 int score;
2970
2971 nd_read_int(&score);
2972 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2973 Players[Player_num].score -= score;
2974 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2975 Players[Player_num].score += score;
2976 break;
2977 }
2978
2979
2980 case ND_EVENT_PRIMARY_AMMO: {
2981 short old_ammo, new_ammo;
2982
2983 nd_read_short(&old_ammo);
2984 nd_read_short(&new_ammo);
2985
2986 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
2987 Players[Player_num].primary_ammo[Primary_weapon] = old_ammo;
2988 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
2989 Players[Player_num].primary_ammo[Primary_weapon] = new_ammo;
2990 break;
2991 }
2992
2993 case ND_EVENT_SECONDARY_AMMO: {
2994 short old_ammo, new_ammo;
2995
2996 nd_read_short(&old_ammo);
2997 nd_read_short(&new_ammo);
2998
2999 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3000 Players[Player_num].secondary_ammo[Secondary_weapon] = old_ammo;
3001 else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
3002 Players[Player_num].secondary_ammo[Secondary_weapon] = new_ammo;
3003 break;
3004 }
3005
3006 case ND_EVENT_DOOR_OPENING: {
3007 short segnum;
3008 byte side;
3009
3010 nd_read_short(&segnum);
3011 nd_read_byte(&side);
3012 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
3013 int anim_num;
3014 int cside;
3015 segment *segp, *csegp;
3016
3017 segp = &Segments[segnum];
3018 csegp = &Segments[segp->children[side]];
3019 cside = find_connect_side(segp, csegp);
3020 anim_num = Walls[segp->sides[side].wall_num].clip_num;
3021
3022 if (WallAnims[anim_num].flags & WCF_TMAP1) {
3023 segp->sides[side].tmap_num = csegp->sides[cside].tmap_num = WallAnims[anim_num].frames[0];
3024 } else {
3025 segp->sides[side].tmap_num2 = csegp->sides[cside].tmap_num2 = WallAnims[anim_num].frames[0];
3026 }
3027 }
3028 break;
3029 }
3030
3031 case ND_EVENT_LASER_LEVEL: {
3032 byte old_level, new_level;
3033
3034 nd_read_byte(&old_level);
3035 nd_read_byte(&new_level);
3036 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
3037 Players[Player_num].laser_level = old_level;
3038 update_laser_weapon_info();
3039 } else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
3040 Players[Player_num].laser_level = new_level;
3041 update_laser_weapon_info();
3042 }
3043 break;
3044 }
3045
3046 case ND_EVENT_CLOAKING_WALL: {
3047 ubyte back_wall_num,front_wall_num,type,state,cloak_value;
3048 short l0,l1,l2,l3;
3049 segment *segp;
3050 int sidenum;
3051
3052 nd_read_byte(&front_wall_num);
3053 nd_read_byte(&back_wall_num);
3054 nd_read_byte(&type);
3055 nd_read_byte(&state);
3056 nd_read_byte(&cloak_value);
3057 nd_read_short(&l0);
3058 nd_read_short(&l1);
3059 nd_read_short(&l2);
3060 nd_read_short(&l3);
3061
3062 Walls[front_wall_num].type = type;
3063 Walls[front_wall_num].state = state;
3064 Walls[front_wall_num].cloak_value = cloak_value;
3065 segp = &Segments[Walls[front_wall_num].segnum];
3066 sidenum = Walls[front_wall_num].sidenum;
3067 segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
3068 segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
3069 segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
3070 segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
3071
3072 Walls[back_wall_num].type = type;
3073 Walls[back_wall_num].state = state;
3074 Walls[back_wall_num].cloak_value = cloak_value;
3075 segp = &Segments[Walls[back_wall_num].segnum];
3076 sidenum = Walls[back_wall_num].sidenum;
3077 segp->sides[sidenum].uvls[0].l = ((int) l0) << 8;
3078 segp->sides[sidenum].uvls[1].l = ((int) l1) << 8;
3079 segp->sides[sidenum].uvls[2].l = ((int) l2) << 8;
3080 segp->sides[sidenum].uvls[3].l = ((int) l3) << 8;
3081
3082 break;
3083 }
3084
3085 case ND_EVENT_NEW_LEVEL: {
3086 byte new_level, old_level, loaded_level;
3087
3088 nd_read_byte (&new_level);
3089 nd_read_byte (&old_level);
3090 if (Newdemo_vcr_state == ND_STATE_PAUSED)
3091 break;
3092
3093 stop_time();
3094 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3095 loaded_level = old_level;
3096 else {
3097 loaded_level = new_level;
3098 for (i = 0; i < MAX_PLAYERS; i++) {
3099 Players[i].cloak_time = 0;
3100 Players[i].flags &= ~PLAYER_FLAGS_CLOAKED;
3101 }
3102 }
3103 if ((loaded_level < Last_secret_level) || (loaded_level > Last_level)) {
3104 newmenu_item m[3];
3105
3106 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
3107 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
3108 m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
3109 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3110 return -1;
3111 }
3112
3113 LoadLevel((int)loaded_level,1);
3114 Newdemo_cntrlcen_destroyed = 0;
3115
3116 if (JustStartedPlayback)
3117 {
3118 nd_read_int (&Num_walls);
3119 for (i=0;i<Num_walls;i++) // restore the walls
3120 {
3121 nd_read_byte (&Walls[i].type);
3122 nd_read_byte (&Walls[i].flags);
3123 nd_read_byte (&Walls[i].state);
3124
3125 seg = &Segments[Walls[i].segnum];
3126 side = Walls[i].sidenum;
3127 nd_read_short (&seg->sides[side].tmap_num);
3128 nd_read_short (&seg->sides[side].tmap_num2);
3129 }
3130 #ifdef NETWORK
3131 if (Newdemo_game_mode & GM_CAPTURE)
3132 multi_apply_goal_textures ();
3133 #endif
3134 JustStartedPlayback=0;
3135 }
3136
3137
3138 // so says Rob H.!!! if (Newdemo_game_mode & GM_MULTI) {
3139 // so says Rob H.!!! for (i = 0; i < Num_walls; i++) {
3140 // so says Rob H.!!! if (Walls[i].type == WALL_BLASTABLE)
3141 // so says Rob H.!!! {
3142 // so says Rob H.!!! int a, n;
3143 // so says Rob H.!!! int side;
3144 // so says Rob H.!!! segment *seg;
3145 // so says Rob H.!!!
3146 // so says Rob H.!!! seg = &Segments[Walls[i].segnum];
3147 // so says Rob H.!!! side = Walls[i].sidenum;
3148 // so says Rob H.!!! a = Walls[i].clip_num;
3149 // so says Rob H.!!! n = WallAnims[a].num_frames;
3150 // so says Rob H.!!! seg->sides[side].tmap_num = WallAnims[a].frames[n-1];
3151 // so says Rob H.!!! Walls[i].flags |= WALL_BLASTED;
3152 // so says Rob H.!!! }
3153 // so says Rob H.!!! }
3154 // so says Rob H.!!! }
3155
3156 reset_palette_add(); // get palette back to normal
3157 start_time();
3158 break;
3159 }
3160
3161 case ND_EVENT_EOF: {
3162 done=-1;
3163 fseek(infile, -1, SEEK_CUR); // get back to the EOF marker
3164 Newdemo_at_eof = 1;
3165 NewdemoFrameCount++;
3166 break;
3167 }
3168
3169 default:
3170 Int3();
3171 }
3172 }
3173
3174 LastReadValue=c;
3175
3176 if (nd_bad_read) {
3177 newmenu_item m[2];
3178
3179 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_ERR_READING;
3180 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_DEMO_OLD_CORRUPT;
3181 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3182 }
3183
3184 return done;
3185 }
3186
newdemo_goto_beginning()3187 void newdemo_goto_beginning()
3188 {
3189 //if (NewdemoFrameCount == 0)
3190 // return;
3191 fseek(infile, 0, SEEK_SET);
3192 Newdemo_vcr_state = ND_STATE_PLAYBACK;
3193 if (newdemo_read_demo_start(0))
3194 newdemo_stop_playback();
3195 if (newdemo_read_frame_information() == -1)
3196 newdemo_stop_playback();
3197 if (newdemo_read_frame_information() == -1)
3198 newdemo_stop_playback();
3199 Newdemo_vcr_state = ND_STATE_PAUSED;
3200 Newdemo_at_eof = 0;
3201 }
3202
newdemo_goto_end()3203 void newdemo_goto_end()
3204 {
3205 short frame_length, byte_count, bshort;
3206 byte level, bbyte, laser_level;
3207 ubyte energy, shield, c;
3208 int i, loc, bint;
3209
3210 fseek(infile, -2, SEEK_END);
3211 nd_read_byte(&level);
3212
3213 if ((level < Last_secret_level) || (level > Last_level)) {
3214 newmenu_item m[3];
3215
3216 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_CANT_PLAYBACK;
3217 m[ 1].type = NM_TYPE_TEXT; m[ 1].text = TXT_LEVEL_CANT_LOAD;
3218 m[ 2].type = NM_TYPE_TEXT; m[ 2].text = TXT_DEMO_OLD_CORRUPT;
3219 newmenu_do( NULL, NULL, sizeof(m)/sizeof(*m), m, NULL );
3220 newdemo_stop_playback();
3221 return;
3222 }
3223 if (level != Current_level_num)
3224 LoadLevel(level,1);
3225
3226 fseek(infile, -4, SEEK_END);
3227 nd_read_short(&byte_count);
3228 fseek(infile, -2 - byte_count, SEEK_CUR);
3229
3230 nd_read_short(&frame_length);
3231 loc = ftell(infile);
3232 if (Newdemo_game_mode & GM_MULTI)
3233 nd_read_byte(&Newdemo_players_cloaked);
3234 else
3235 nd_read_byte(&bbyte);
3236 nd_read_byte(&bbyte);
3237 nd_read_short(&bshort);
3238 nd_read_int(&bint);
3239
3240 nd_read_byte(&energy);
3241 nd_read_byte(&shield);
3242 Players[Player_num].energy = i2f(energy);
3243 Players[Player_num].shields = i2f(shield);
3244 nd_read_int((int *)&(Players[Player_num].flags));
3245 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) {
3246 Players[Player_num].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
3247 Newdemo_players_cloaked |= (1 << Player_num);
3248 }
3249 if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
3250 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
3251 nd_read_byte((byte *)&Primary_weapon);
3252 nd_read_byte((byte *)&Secondary_weapon);
3253 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3254 nd_read_short((short *)&(Players[Player_num].primary_ammo[i]));
3255 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3256 nd_read_short((short *)&(Players[Player_num].secondary_ammo[i]));
3257 nd_read_byte(&laser_level);
3258 if (laser_level != Players[Player_num].laser_level) {
3259 Players[Player_num].laser_level = laser_level;
3260 update_laser_weapon_info();
3261 }
3262
3263 if (Newdemo_game_mode & GM_MULTI) {
3264 nd_read_byte(&c);
3265 N_players = (int)c;
3266 // see newdemo_read_start_demo for explanation of
3267 // why this is commented out
3268 // nd_read_byte((byte *)&N_players);
3269 for (i = 0; i < N_players; i++) {
3270 nd_read_string(Players[i].callsign);
3271 nd_read_byte(&(Players[i].connected));
3272 if (Newdemo_game_mode & GM_MULTI_COOP) {
3273 nd_read_int(&(Players[i].score));
3274 } else {
3275 nd_read_short((short *)&(Players[i].net_killed_total));
3276 nd_read_short((short *)&(Players[i].net_kills_total));
3277 }
3278 }
3279 } else {
3280 nd_read_int(&(Players[Player_num].score));
3281 }
3282
3283 fseek(infile, loc, SEEK_SET);
3284 fseek(infile, -frame_length, SEEK_CUR);
3285 nd_read_int(&NewdemoFrameCount); // get the frame count
3286 NewdemoFrameCount--;
3287 fseek(infile, 4, SEEK_CUR);
3288 Newdemo_vcr_state = ND_STATE_PLAYBACK;
3289 newdemo_read_frame_information(); // then the frame information
3290 Newdemo_vcr_state = ND_STATE_PAUSED;
3291 return;
3292 }
3293
newdemo_back_frames(int frames)3294 void newdemo_back_frames(int frames)
3295 {
3296 short last_frame_length;
3297 int i;
3298
3299 for (i = 0; i < frames; i++)
3300 {
3301 fseek(infile, -10, SEEK_CUR);
3302 nd_read_short(&last_frame_length);
3303 fseek(infile, 8 - last_frame_length, SEEK_CUR);
3304
3305 if (!Newdemo_at_eof && newdemo_read_frame_information() == -1) {
3306 newdemo_stop_playback();
3307 return;
3308 }
3309 if (Newdemo_at_eof)
3310 Newdemo_at_eof = 0;
3311
3312 fseek(infile, -10, SEEK_CUR);
3313 nd_read_short(&last_frame_length);
3314 fseek(infile, 8 - last_frame_length, SEEK_CUR);
3315 }
3316
3317 }
3318
3319 /*
3320 * routine to interpolate the viewer position. the current position is
3321 * stored in the Viewer object. Save this position, and read the next
3322 * frame to get all objects read in. Calculate the delta playback and
3323 * the delta recording frame times between the two frames, then intepolate
3324 * the viewers position accordingly. nd_recorded_time is the time that it
3325 * took the recording to render the frame that we are currently looking
3326 * at.
3327 */
3328
interpolate_frame(fix d_play,fix d_recorded)3329 void interpolate_frame(fix d_play, fix d_recorded)
3330 {
3331 int i, j, num_cur_objs;
3332 fix factor;
3333 object *cur_objs;
3334
3335 factor = fixdiv(d_play, d_recorded);
3336 if (factor > F1_0)
3337 factor = F1_0;
3338
3339 num_cur_objs = Highest_object_index;
3340 cur_objs = (object *)d_malloc(sizeof(object) * (num_cur_objs + 1));
3341 if (cur_objs == NULL) {
3342 mprintf((0,"Couldn't get %d bytes for cur_objs in interpolate_frame\n", sizeof(object) * num_cur_objs));
3343 Int3();
3344 return;
3345 }
3346 for (i = 0; i <= num_cur_objs; i++)
3347 memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
3348
3349 Newdemo_vcr_state = ND_STATE_PAUSED;
3350 if (newdemo_read_frame_information() == -1) {
3351 d_free(cur_objs);
3352 newdemo_stop_playback();
3353 return;
3354 }
3355
3356 for (i = 0; i <= num_cur_objs; i++) {
3357 for (j = 0; j <= Highest_object_index; j++) {
3358 if (cur_objs[i].signature == Objects[j].signature) {
3359 ubyte render_type = cur_objs[i].render_type;
3360 //fix delta_p, delta_h, delta_b;
3361 fix delta_x, delta_y, delta_z;
3362 //vms_angvec cur_angles, dest_angles;
3363
3364 // Extract the angles from the object orientation matrix.
3365 // Some of this code taken from ai_turn_towards_vector
3366 // Don't do the interpolation on certain render types which don't use an orientation matrix
3367
3368 if (!((render_type == RT_LASER) || (render_type == RT_FIREBALL) || (render_type == RT_POWERUP))) {
3369
3370 vms_vector fvec1, fvec2, rvec1, rvec2;
3371 fix mag1;
3372
3373 fvec1 = cur_objs[i].orient.fvec;
3374 vm_vec_scale(&fvec1, F1_0-factor);
3375 fvec2 = Objects[j].orient.fvec;
3376 vm_vec_scale(&fvec2, factor);
3377 vm_vec_add2(&fvec1, &fvec2);
3378 mag1 = vm_vec_normalize_quick(&fvec1);
3379 if (mag1 > F1_0/256) {
3380 rvec1 = cur_objs[i].orient.rvec;
3381 vm_vec_scale(&rvec1, F1_0-factor);
3382 rvec2 = Objects[j].orient.rvec;
3383 vm_vec_scale(&rvec2, factor);
3384 vm_vec_add2(&rvec1, &rvec2);
3385 vm_vec_normalize_quick(&rvec1); // Note: Doesn't matter if this is null, if null, vm_vector_2_matrix will just use fvec1
3386 vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
3387 }
3388
3389 //--old new way -- vms_vector fvec1, fvec2, rvec1, rvec2;
3390 //--old new way --
3391 //--old new way -- fvec1 = cur_objs[i].orient.fvec;
3392 //--old new way -- vm_vec_scale(&fvec1, F1_0-factor);
3393 //--old new way -- fvec2 = Objects[j].orient.fvec;
3394 //--old new way -- vm_vec_scale(&fvec2, factor);
3395 //--old new way -- vm_vec_add2(&fvec1, &fvec2);
3396 //--old new way -- vm_vec_normalize_quick(&fvec1);
3397 //--old new way --
3398 //--old new way -- rvec1 = cur_objs[i].orient.rvec;
3399 //--old new way -- vm_vec_scale(&rvec1, F1_0-factor);
3400 //--old new way -- rvec2 = Objects[j].orient.rvec;
3401 //--old new way -- vm_vec_scale(&rvec2, factor);
3402 //--old new way -- vm_vec_add2(&rvec1, &rvec2);
3403 //--old new way -- vm_vec_normalize_quick(&rvec1);
3404 //--old new way --
3405 //--old new way -- vm_vector_2_matrix(&cur_objs[i].orient, &fvec1, NULL, &rvec1);
3406
3407 // -- old fashioned way -- vm_extract_angles_matrix(&cur_angles, &(cur_objs[i].orient));
3408 // -- old fashioned way -- vm_extract_angles_matrix(&dest_angles, &(Objects[j].orient));
3409 // -- old fashioned way --
3410 // -- old fashioned way -- delta_p = (dest_angles.p - cur_angles.p);
3411 // -- old fashioned way -- delta_h = (dest_angles.h - cur_angles.h);
3412 // -- old fashioned way -- delta_b = (dest_angles.b - cur_angles.b);
3413 // -- old fashioned way --
3414 // -- old fashioned way -- if (delta_p != 0) {
3415 // -- old fashioned way -- if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
3416 // -- old fashioned way -- if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
3417 // -- old fashioned way -- delta_p = fixmul(delta_p, factor);
3418 // -- old fashioned way -- cur_angles.p += delta_p;
3419 // -- old fashioned way -- }
3420 // -- old fashioned way -- if (delta_h != 0) {
3421 // -- old fashioned way -- if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
3422 // -- old fashioned way -- if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
3423 // -- old fashioned way -- delta_h = fixmul(delta_h, factor);
3424 // -- old fashioned way -- cur_angles.h += delta_h;
3425 // -- old fashioned way -- }
3426 // -- old fashioned way -- if (delta_b != 0) {
3427 // -- old fashioned way -- if (delta_b > F1_0/2) delta_b = dest_angles.b - cur_angles.b - F1_0;
3428 // -- old fashioned way -- if (delta_b < -F1_0/2) delta_b = dest_angles.b - cur_angles.b + F1_0;
3429 // -- old fashioned way -- delta_b = fixmul(delta_b, factor);
3430 // -- old fashioned way -- cur_angles.b += delta_b;
3431 // -- old fashioned way -- }
3432 }
3433
3434 // Interpolate the object position. This is just straight linear
3435 // interpolation.
3436
3437 delta_x = Objects[j].pos.x - cur_objs[i].pos.x;
3438 delta_y = Objects[j].pos.y - cur_objs[i].pos.y;
3439 delta_z = Objects[j].pos.z - cur_objs[i].pos.z;
3440
3441 delta_x = fixmul(delta_x, factor);
3442 delta_y = fixmul(delta_y, factor);
3443 delta_z = fixmul(delta_z, factor);
3444
3445 cur_objs[i].pos.x += delta_x;
3446 cur_objs[i].pos.y += delta_y;
3447 cur_objs[i].pos.z += delta_z;
3448
3449 // -- old fashioned way --// stuff the new angles back into the object structure
3450 // -- old fashioned way -- vm_angles_2_matrix(&(cur_objs[i].orient), &cur_angles);
3451 }
3452 }
3453 }
3454
3455 // get back to original position in the demo file. Reread the current
3456 // frame information again to reset all of the object stuff not covered
3457 // with Highest_object_index and the object array (previously rendered
3458 // objects, etc....)
3459
3460 newdemo_back_frames(1);
3461 newdemo_back_frames(1);
3462 if (newdemo_read_frame_information() == -1)
3463 newdemo_stop_playback();
3464 Newdemo_vcr_state = ND_STATE_PLAYBACK;
3465
3466 for (i = 0; i <= num_cur_objs; i++)
3467 memcpy(&(Objects[i]), &(cur_objs[i]), sizeof(object));
3468 Highest_object_index = num_cur_objs;
3469 d_free(cur_objs);
3470 }
3471
newdemo_playback_one_frame()3472 void newdemo_playback_one_frame()
3473 {
3474 int frames_back, i, level;
3475 static fix base_interpol_time = 0;
3476 static fix d_recorded = 0;
3477
3478 for (i = 0; i < MAX_PLAYERS; i++)
3479 if (Newdemo_players_cloaked & (1 << i))
3480 Players[i].cloak_time = GameTime - (CLOAK_TIME_MAX / 2);
3481
3482 if (Players[Player_num].flags & PLAYER_FLAGS_INVULNERABLE)
3483 Players[Player_num].invulnerable_time = GameTime - (INVULNERABLE_TIME_MAX / 2);
3484
3485 if (Newdemo_vcr_state == ND_STATE_PAUSED) // render a frame or not
3486 return;
3487
3488 if (Newdemo_vcr_state == ND_STATE_PLAYBACK)
3489 DoJasonInterpolate(nd_recorded_time);
3490
3491 Control_center_destroyed = 0;
3492 Countdown_seconds_left = -1;
3493 PALETTE_FLASH_SET(0,0,0); //clear flash
3494
3495 if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
3496 {
3497 level = Current_level_num;
3498 if (NewdemoFrameCount == 0)
3499 return;
3500 else if ((Newdemo_vcr_state == ND_STATE_REWINDING) && (NewdemoFrameCount < 10)) {
3501 newdemo_goto_beginning();
3502 return;
3503 }
3504 if (Newdemo_vcr_state == ND_STATE_REWINDING)
3505 frames_back = 10;
3506 else
3507 frames_back = 1;
3508 if (Newdemo_at_eof) {
3509 fseek(infile, 11, SEEK_CUR);
3510 }
3511 newdemo_back_frames(frames_back);
3512
3513 if (level != Current_level_num)
3514 newdemo_pop_ctrlcen_triggers();
3515
3516 if (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD) {
3517 if (level != Current_level_num)
3518 newdemo_back_frames(1);
3519 Newdemo_vcr_state = ND_STATE_PAUSED;
3520 }
3521 }
3522 else if (Newdemo_vcr_state == ND_STATE_FASTFORWARD) {
3523 if (!Newdemo_at_eof)
3524 {
3525 for (i = 0; i < 10; i++)
3526 {
3527 if (newdemo_read_frame_information() == -1)
3528 {
3529 if (Newdemo_at_eof)
3530 Newdemo_vcr_state = ND_STATE_PAUSED;
3531 else
3532 newdemo_stop_playback();
3533 break;
3534 }
3535 }
3536 }
3537 else
3538 Newdemo_vcr_state = ND_STATE_PAUSED;
3539 }
3540 else if (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD) {
3541 if (!Newdemo_at_eof) {
3542 level = Current_level_num;
3543 if (newdemo_read_frame_information() == -1) {
3544 if (!Newdemo_at_eof)
3545 newdemo_stop_playback();
3546 }
3547 if (level != Current_level_num) {
3548 if (newdemo_read_frame_information() == -1) {
3549 if (!Newdemo_at_eof)
3550 newdemo_stop_playback();
3551 }
3552 }
3553 Newdemo_vcr_state = ND_STATE_PAUSED;
3554 } else
3555 Newdemo_vcr_state = ND_STATE_PAUSED;
3556 }
3557 else {
3558
3559 // First, uptate the total playback time to date. Then we check to see
3560 // if we need to change the playback style to interpolate frames or
3561 // skip frames based on where the playback time is relative to the
3562 // recorded time.
3563
3564 if (NewdemoFrameCount <= 0)
3565 nd_playback_total = nd_recorded_total; // baseline total playback time
3566 else
3567 nd_playback_total += FrameTime;
3568 if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
3569 if ((nd_playback_total * INTERPOL_FACTOR) < nd_recorded_total) {
3570 playback_style = INTERPOLATE_PLAYBACK;
3571 nd_playback_total = nd_recorded_total + FrameTime; // baseline playback time
3572 base_interpol_time = nd_recorded_total;
3573 d_recorded = nd_recorded_time; // baseline delta recorded
3574 }
3575 if ((playback_style == NORMAL_PLAYBACK) && (NewdemoFrameCount > 10))
3576 if (nd_playback_total > nd_recorded_total)
3577 playback_style = SKIP_PLAYBACK;
3578
3579
3580 if ((playback_style == INTERPOLATE_PLAYBACK) && Newdemo_do_interpolate) {
3581 fix d_play = 0;
3582
3583 if (nd_recorded_total - nd_playback_total < FrameTime) {
3584 d_recorded = nd_recorded_total - nd_playback_total;
3585
3586 while (nd_recorded_total - nd_playback_total < FrameTime) {
3587 object *cur_objs;
3588 int i, j, num_objs, level;
3589
3590 num_objs = Highest_object_index;
3591 cur_objs = (object *)d_malloc(sizeof(object) * (num_objs + 1));
3592 if (cur_objs == NULL) {
3593 Warning ("Couldn't get %d bytes for objects in interpolate playback\n", sizeof(object) * num_objs);
3594 break;
3595 }
3596 for (i = 0; i <= num_objs; i++)
3597 memcpy(&(cur_objs[i]), &(Objects[i]), sizeof(object));
3598
3599 level = Current_level_num;
3600 if (newdemo_read_frame_information() == -1) {
3601 d_free(cur_objs);
3602 newdemo_stop_playback();
3603 return;
3604 }
3605 if (level != Current_level_num) {
3606 d_free(cur_objs);
3607 if (newdemo_read_frame_information() == -1)
3608 newdemo_stop_playback();
3609 break;
3610 }
3611
3612 // for each new object in the frame just read in, determine if there is
3613 // a corresponding object that we have been interpolating. If so, then
3614 // copy that interpolated object to the new Objects array so that the
3615 // interpolated position and orientation can be preserved.
3616
3617 for (i = 0; i <= num_objs; i++) {
3618 for (j = 0; j <= Highest_object_index; j++) {
3619 if (cur_objs[i].signature == Objects[j].signature) {
3620 memcpy(&(Objects[j].orient), &(cur_objs[i].orient), sizeof(vms_matrix));
3621 memcpy(&(Objects[j].pos), &(cur_objs[i].pos), sizeof(vms_vector));
3622 break;
3623 }
3624 }
3625 }
3626 d_free(cur_objs);
3627 d_recorded += nd_recorded_time;
3628 base_interpol_time = nd_playback_total - FrameTime;
3629 }
3630 }
3631
3632 d_play = nd_playback_total - base_interpol_time;
3633 interpolate_frame(d_play, d_recorded);
3634 return;
3635 }
3636 else {
3637 //mprintf ((0, "*"));
3638 if (newdemo_read_frame_information() == -1) {
3639 newdemo_stop_playback();
3640 return;
3641 }
3642 if (playback_style == SKIP_PLAYBACK) {
3643 //mprintf ((0, "."));
3644 while (nd_playback_total > nd_recorded_total) {
3645 if (newdemo_read_frame_information() == -1) {
3646 newdemo_stop_playback();
3647 return;
3648 }
3649 }
3650 }
3651 }
3652 }
3653 }
3654
newdemo_start_recording()3655 void newdemo_start_recording()
3656 {
3657 #ifdef WINDOWS
3658 Newdemo_size=GetFreeDiskSpace();
3659 mprintf((0, "Free space = %d\n", Newdemo_size));
3660 #else
3661 Newdemo_size = GetDiskFree();
3662 #endif
3663
3664 Newdemo_size -= 100000;
3665
3666 if ((Newdemo_size+100000) < 2000000000) {
3667 if (((int)(Newdemo_size)) < 500000) {
3668 #ifndef MACINTOSH
3669 nm_messagebox(NULL, 1, TXT_OK, TXT_DEMO_NO_SPACE);
3670 #else
3671 nm_messagebox(NULL, 1, TXT_OK, "Not enough space on current\ndrive to start demo recording.");
3672 #endif
3673 return;
3674 }
3675 }
3676
3677 Newdemo_num_written = 0;
3678 Newdemo_no_space=0;
3679 Newdemo_state = ND_STATE_RECORDING;
3680 outfile = fopen( DEMO_FILENAME, "wb" );
3681
3682 #ifndef MACINTOSH
3683 if (outfile == NULL && errno == ENOENT) { //dir doesn't exist?
3684 #else
3685 if (outfile == NULL) { //dir doesn't exist and no errno on mac!
3686 #endif
3687 d_mkdir(DEMO_DIR); //try making directory
3688 outfile = fopen( DEMO_FILENAME, "wb" );
3689 }
3690
3691 if (outfile == NULL)
3692 {
3693 nm_messagebox(NULL, 1, TXT_OK, "Cannot open demo temp file");
3694 Newdemo_state = ND_STATE_NORMAL;
3695 }
3696 else
3697 newdemo_record_start_demo();
3698
3699 }
3700
3701 char demoname_allowed_chars[] = "azAZ09__--";
3702 void newdemo_stop_recording()
3703 {
3704 newmenu_item m[6];
3705 int l, exit;
3706 static char filename[15] = "", *s;
3707 static ubyte tmpcnt = 0;
3708 ubyte cloaked = 0;
3709 char fullname[15+FILENAME_LEN] = DEMO_DIR;
3710 unsigned short byte_count = 0;
3711
3712 exit = 0;
3713
3714 nd_write_byte(ND_EVENT_EOF);
3715 nd_write_short(frame_bytes_written - 1);
3716 if (Game_mode & GM_MULTI) {
3717 for (l = 0; l < N_players; l++) {
3718 if (Players[l].flags & PLAYER_FLAGS_CLOAKED)
3719 cloaked |= (1 << l);
3720 }
3721 nd_write_byte(cloaked);
3722 nd_write_byte(ND_EVENT_EOF);
3723 } else {
3724 nd_write_short(ND_EVENT_EOF);
3725 }
3726 nd_write_short(ND_EVENT_EOF);
3727 nd_write_int(ND_EVENT_EOF);
3728
3729 byte_count += 10; // from frame_bytes_written
3730
3731 nd_write_byte((byte)(f2ir(Players[Player_num].energy)));
3732 nd_write_byte((byte)(f2ir(Players[Player_num].shields)));
3733 nd_write_int(Players[Player_num].flags); // be sure players flags are set
3734 nd_write_byte((byte)Primary_weapon);
3735 nd_write_byte((byte)Secondary_weapon);
3736 byte_count += 8;
3737
3738 for (l = 0; l < MAX_PRIMARY_WEAPONS; l++)
3739 nd_write_short((short)Players[Player_num].primary_ammo[l]);
3740
3741 for (l = 0; l < MAX_SECONDARY_WEAPONS; l++)
3742 nd_write_short((short)Players[Player_num].secondary_ammo[l]);
3743 byte_count += (sizeof(short) * (MAX_PRIMARY_WEAPONS + MAX_SECONDARY_WEAPONS));
3744
3745 nd_write_byte(Players[Player_num].laser_level);
3746 byte_count++;
3747
3748 if (Game_mode & GM_MULTI) {
3749 nd_write_byte((byte)N_players);
3750 byte_count++;
3751 for (l = 0; l < N_players; l++) {
3752 nd_write_string(Players[l].callsign);
3753 byte_count += (strlen(Players[l].callsign) + 2);
3754 nd_write_byte(Players[l].connected);
3755 if (Game_mode & GM_MULTI_COOP) {
3756 nd_write_int(Players[l].score);
3757 byte_count += 5;
3758 } else {
3759 nd_write_short((short)Players[l].net_killed_total);
3760 nd_write_short((short)Players[l].net_kills_total);
3761 byte_count += 5;
3762 }
3763 }
3764 } else {
3765 nd_write_int(Players[Player_num].score);
3766 byte_count += 4;
3767 }
3768 nd_write_short(byte_count);
3769
3770 nd_write_byte(Current_level_num);
3771 nd_write_byte(ND_EVENT_EOF);
3772
3773 l = ftell(outfile);
3774 fclose(outfile);
3775 outfile = NULL;
3776 Newdemo_state = ND_STATE_NORMAL;
3777 gr_palette_load( gr_palette );
3778
3779 if (filename[0] != '\0') {
3780 int num, i = strlen(filename) - 1;
3781 char newfile[15];
3782
3783 while (isdigit(filename[i])) {
3784 i--;
3785 if (i == -1)
3786 break;
3787 }
3788 i++;
3789 num = atoi(&(filename[i]));
3790 num++;
3791 filename[i] = '\0';
3792 sprintf (newfile, "%s%d", filename, num);
3793 strncpy(filename, newfile, 8);
3794 filename[8] = '\0';
3795 }
3796
3797 try_again:
3798 ;
3799
3800 Newmenu_allowed_chars = demoname_allowed_chars;
3801 if (!Newdemo_no_space) {
3802 m[0].type=NM_TYPE_INPUT; m[0].text_len = 8; m[0].text = filename;
3803 exit = newmenu_do( NULL, TXT_SAVE_DEMO_AS, 1, &(m[0]), NULL );
3804 } else if (Newdemo_no_space == 1) {
3805 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_BAD;
3806 m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3807 exit = newmenu_do( NULL, NULL, 2, m, NULL );
3808 } else if (Newdemo_no_space == 2) {
3809 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = TXT_DEMO_SAVE_NOSPACE;
3810 m[ 1].type = NM_TYPE_INPUT;m[ 1].text_len = 8; m[1].text = filename;
3811 exit = newmenu_do( NULL, NULL, 2, m, NULL );
3812 }
3813 Newmenu_allowed_chars = NULL;
3814
3815 if (exit == -2) { // got bumped out from network menu
3816 char save_file[7+FILENAME_LEN];
3817
3818 if (filename[0] != '\0') {
3819 strcpy(save_file, DEMO_DIR);
3820 strcat(save_file, filename);
3821 strcat(save_file, ".dem");
3822 } else
3823 sprintf (save_file, "%stmp%d.dem", DEMO_DIR, tmpcnt++);
3824 remove(save_file);
3825 rename(DEMO_FILENAME, save_file);
3826 return;
3827 }
3828 if (exit == -1) { // pressed ESC
3829 remove(DEMO_FILENAME); // might as well remove the file
3830 return; // return without doing anything
3831 }
3832
3833 if (filename[0]==0) //null string
3834 goto try_again;
3835
3836 //check to make sure name is ok
3837 for (s=filename;*s;s++)
3838 if (!isalnum(*s) && *s!='_') {
3839 nm_messagebox1(NULL, NULL,1,TXT_CONTINUE, TXT_DEMO_USE_LETTERS);
3840 goto try_again;
3841 }
3842
3843 if (Newdemo_no_space)
3844 strcat(fullname, m[1].text);
3845 else
3846 strcat(fullname, m[0].text);
3847 strcat(fullname, ".dem");
3848 remove(fullname);
3849 rename(DEMO_FILENAME, fullname);
3850 }
3851
3852 //returns the number of demo files on the disk
3853 int newdemo_count_demos()
3854 {
3855 FILEFINDSTRUCT find;
3856 int NumFiles=0;
3857
3858 if( !FileFindFirst( DEMO_DIR "*.dem", &find ) ) {
3859 do {
3860 NumFiles++;
3861 } while( !FileFindNext( &find ) );
3862 FileFindClose();
3863 }
3864
3865 if ( AltHogdir_initialized ) {
3866 char search_name[PATH_MAX + 5];
3867 strcpy(search_name, AltHogDir);
3868 strcat(search_name, "/" DEMO_DIR "*.dem");
3869 if( !FileFindFirst( search_name, &find ) ) {
3870 do {
3871 NumFiles++;
3872 } while( !FileFindNext( &find ) );
3873 FileFindClose();
3874 }
3875 }
3876
3877 return NumFiles;
3878 }
3879
3880 void newdemo_start_playback(char * filename)
3881 {
3882 FILEFINDSTRUCT find;
3883 int rnd_demo = 0;
3884 char filename2[PATH_MAX+FILENAME_LEN] = DEMO_DIR;
3885
3886 #ifdef NETWORK
3887 change_playernum_to(0);
3888 #endif
3889 First_time_playback=1;
3890 JasonPlaybackTotal=0;
3891
3892 if (filename==NULL) {
3893 // Randomly pick a filename
3894 int NumFiles = 0, RandFileNum;
3895 rnd_demo = 1;
3896
3897 NumFiles = newdemo_count_demos();
3898
3899 if ( NumFiles == 0 ) {
3900 return; // No files found!
3901 }
3902 RandFileNum = d_rand() % NumFiles;
3903 NumFiles = 0;
3904 if( !FileFindFirst( DEMO_DIR "*.dem", &find ) ) {
3905 do {
3906 if ( NumFiles==RandFileNum ) {
3907 filename = (char *)&find.name;
3908 break;
3909 }
3910 NumFiles++;
3911 } while( !FileFindNext( &find ) );
3912 FileFindClose();
3913 }
3914
3915 if ( filename == NULL && AltHogdir_initialized ) {
3916 char search_name[PATH_MAX + 5];
3917 strcpy(search_name, AltHogDir);
3918 strcat(search_name, "/" DEMO_DIR "*.dem");
3919 if( !FileFindFirst( search_name, &find ) ) {
3920 do {
3921 if ( NumFiles==RandFileNum ) {
3922 filename = (char *)&find.name;
3923 break;
3924 }
3925 NumFiles++;
3926 } while( !FileFindNext( &find ) );
3927 FileFindClose();
3928 }
3929 }
3930
3931 if ( filename==NULL) return;
3932 }
3933
3934 if (!filename)
3935 return;
3936
3937 strcat(filename2,filename);
3938
3939 infile = fopen( filename2, "rb" );
3940
3941 if (infile==NULL && AltHogdir_initialized) {
3942 strcpy(filename2, AltHogDir);
3943 strcat(filename2, "/" DEMO_DIR);
3944 strcat(filename2, filename);
3945 infile = fopen( filename2, "rb" );
3946 }
3947
3948 if (infile==NULL) {
3949 mprintf( (0, "Error reading '%s'\n", filename ));
3950 return;
3951 }
3952
3953 nd_bad_read = 0;
3954 #ifdef NETWORK
3955 change_playernum_to(0); // force playernum to 0
3956 #endif
3957 strncpy(nd_save_callsign, Players[Player_num].callsign, CALLSIGN_LEN);
3958 Viewer = ConsoleObject = &Objects[0]; // play properly as if console player
3959 if (newdemo_read_demo_start(rnd_demo)) {
3960 fclose(infile);
3961 return;
3962 }
3963
3964 Game_mode = GM_NORMAL;
3965 Newdemo_state = ND_STATE_PLAYBACK;
3966 Newdemo_vcr_state = ND_STATE_PLAYBACK;
3967 Newdemo_old_cockpit = Cockpit_mode;
3968 Newdemo_size = filelength(fileno(infile));
3969 nd_bad_read = 0;
3970 Newdemo_at_eof = 0;
3971 NewdemoFrameCount = 0;
3972 Newdemo_players_cloaked = 0;
3973 playback_style = NORMAL_PLAYBACK;
3974 Function_mode = FMODE_GAME;
3975 Cockpit_3d_view[0] = CV_NONE; //turn off 3d views on cockpit
3976 Cockpit_3d_view[1] = CV_NONE; //turn off 3d views on cockpit
3977 newdemo_playback_one_frame(); // this one loads new level
3978 newdemo_playback_one_frame(); // get all of the objects to renderb game
3979 }
3980
3981 void newdemo_stop_playback()
3982 {
3983 fclose( infile );
3984 Newdemo_state = ND_STATE_NORMAL;
3985 #ifdef NETWORK
3986 change_playernum_to(0); //this is reality
3987 #endif
3988 strncpy(Players[Player_num].callsign, nd_save_callsign, CALLSIGN_LEN);
3989 Cockpit_mode = Newdemo_old_cockpit;
3990 Game_mode = GM_GAME_OVER;
3991 Function_mode = FMODE_MENU;
3992 longjmp(LeaveGame,0); // Exit game loop
3993 }
3994
3995
3996 #ifndef NDEBUG
3997
3998 #define BUF_SIZE 16384
3999
4000 void newdemo_strip_frames(char *outname, int bytes_to_strip)
4001 {
4002 FILE *outfile;
4003 char *buf;
4004 int total_size, bytes_done, read_elems, bytes_back;
4005 int trailer_start, loc1, loc2, stop_loc, bytes_to_read;
4006 short last_frame_length;
4007
4008 bytes_done = 0;
4009 total_size = filelength(fileno(infile));
4010 outfile = fopen(outname, "wb");
4011 if (outfile == NULL) {
4012 newmenu_item m[1];
4013
4014 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't open output file";
4015 newmenu_do( NULL, NULL, 1, m, NULL );
4016 newdemo_stop_playback();
4017 return;
4018 }
4019 buf = d_malloc(BUF_SIZE);
4020 if (buf == NULL) {
4021 newmenu_item m[1];
4022
4023 m[ 0].type = NM_TYPE_TEXT; m[ 0].text = "Can't malloc output buffer";
4024 newmenu_do( NULL, NULL, 1, m, NULL );
4025 fclose(outfile);
4026 newdemo_stop_playback();
4027 return;
4028 }
4029 newdemo_goto_end();
4030 trailer_start = ftell(infile);
4031 fseek(infile, 11, SEEK_CUR);
4032 bytes_back = 0;
4033 while (bytes_back < bytes_to_strip) {
4034 loc1 = ftell(infile);
4035 //fseek(infile, -10, SEEK_CUR);
4036 //nd_read_short(&last_frame_length);
4037 //fseek(infile, 8 - last_frame_length, SEEK_CUR);
4038 newdemo_back_frames(1);
4039 loc2 = ftell(infile);
4040 bytes_back += (loc1 - loc2);
4041 }
4042 fseek(infile, -10, SEEK_CUR);
4043 nd_read_short(&last_frame_length);
4044 fseek(infile, -3, SEEK_CUR);
4045 stop_loc = ftell(infile);
4046 fseek(infile, 0, SEEK_SET);
4047 while (stop_loc > 0) {
4048 if (stop_loc < BUF_SIZE)
4049 bytes_to_read = stop_loc;
4050 else
4051 bytes_to_read = BUF_SIZE;
4052 read_elems = fread(buf, 1, bytes_to_read, infile);
4053 fwrite(buf, 1, read_elems, outfile);
4054 stop_loc -= read_elems;
4055 }
4056 stop_loc = ftell(outfile);
4057 fseek(infile, trailer_start, SEEK_SET);
4058 while ((read_elems = fread(buf, 1, BUF_SIZE, infile)) != 0)
4059 fwrite(buf, 1, read_elems, outfile);
4060 fseek(outfile, stop_loc, SEEK_SET);
4061 fseek(outfile, 1, SEEK_CUR);
4062 fwrite(&last_frame_length, 2, 1, outfile);
4063 fclose(outfile);
4064 newdemo_stop_playback();
4065
4066 }
4067
4068 #endif
4069
4070 object DemoRightExtra,DemoLeftExtra;
4071 ubyte DemoDoRight=0,DemoDoLeft=0;
4072
4073 void nd_render_extras (ubyte which,object *obj)
4074 {
4075 ubyte w=which>>4;
4076 ubyte type=which&15;
4077
4078 if (which==255)
4079 {
4080 Int3(); // how'd we get here?
4081 do_cockpit_window_view(w,NULL,0,WBU_WEAPON,NULL);
4082 return;
4083 }
4084
4085 if (w)
4086 {
4087 memcpy (&DemoRightExtra,obj,sizeof(object)); DemoDoRight=type;
4088 }
4089 else
4090 {
4091 memcpy (&DemoLeftExtra,obj,sizeof(object)); DemoDoLeft=type;
4092 }
4093
4094 }
4095
4096 void DoJasonInterpolate (fix recorded_time)
4097 {
4098 fix the_delay;
4099
4100 JasonPlaybackTotal+=FrameTime;
4101
4102 if (!First_time_playback)
4103 {
4104 // get the difference between the recorded time and the playback time
4105 the_delay=(recorded_time - FrameTime);
4106 //mprintf ((0,"The delay=%d\n", f2i(the_delay)));
4107 if (the_delay >= f0_0)
4108 {
4109 stop_time();
4110 timer_delay(the_delay);
4111 start_time();
4112 }
4113 else
4114 {
4115 while (JasonPlaybackTotal > nd_recorded_total)
4116 if (newdemo_read_frame_information() == -1)
4117 {
4118 newdemo_stop_playback();
4119 return;
4120 }
4121
4122 //the_delay = nd_recorded_total - JasonPlaybackTotal;
4123 //if (the_delay > f0_0)
4124 // timer_delay(the_delay);
4125 }
4126
4127 }
4128
4129 First_time_playback=0;
4130 }
4131
4132 #ifdef MACINTOSH
4133 #pragma global_optimizer reset
4134 #endif
4135
4136