home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / newdemo.c < prev    next >
Text File  |  1998-06-08  |  113KB  |  3,755 lines

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