home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / endlevel.c < prev    next >
Text File  |  1998-06-08  |  46KB  |  1,727 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/endlevel.c $
  15.  * $Revision: 2.2 $
  16.  * $Author: john $
  17.  * $Date: 1995/03/21 14:40:14 $
  18.  * 
  19.  * Code for rendering external scenes
  20.  * 
  21.  * $Log: endlevel.c $
  22.  * Revision 2.2  1995/03/21  14:40:14  john
  23.  * Ifdef'd out the NETWORK code.
  24.  * 
  25.  * Revision 2.1  1995/03/20  18:15:50  john
  26.  * Added code to not store the normals in the segment structure.
  27.  * 
  28.  * Revision 2.0  1995/02/27  11:30:42  john
  29.  * New version 2.0, which has no anonymous unions, builds with
  30.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  31.  * 
  32.  * Revision 1.80  1995/02/22  13:24:45  john
  33.  * Removed the vecmat anonymous unions.
  34.  * 
  35.  * Revision 1.79  1995/02/11  12:41:54  john
  36.  * Added new song method, with FM bank switching..
  37.  * 
  38.  * Revision 1.78  1995/02/08  11:37:41  mike
  39.  * Check for failures in call to obj_create.
  40.  * 
  41.  * Revision 1.77  1995/02/05  22:09:49  matt
  42.  * Switch out of rear view when starting endlevel sequence
  43.  * 
  44.  * Revision 1.76  1995/01/30  18:08:28  rob
  45.  * Add palette fade out before ending level on special missions.
  46.  * 
  47.  * Revision 1.75  1995/01/29  16:19:19  rob
  48.  * Fixed endlevel for custom missions.
  49.  * 
  50.  * Revision 1.74  1995/01/26  12:18:10  rob
  51.  * Changed calling convention of network_do_frame.
  52.  * 
  53.  * Revision 1.73  1995/01/21  16:50:03  matt
  54.  * Made endlevel work with new mission stuff
  55.  * 
  56.  * Revision 1.72  1994/12/20  18:22:51  john
  57.  * Added code to support non-looping songs, and put
  58.  * it in for endlevel and credits.
  59.  * 
  60.  * Revision 1.71  1994/12/15  12:23:58  matt
  61.  * Added check for failure to create camera object
  62.  * 
  63.  * Revision 1.70  1994/12/15  03:05:28  matt
  64.  * Added error checking for NULL return from object_create_explosion()
  65.  * 
  66.  * Revision 1.69  1994/12/12  21:41:38  matt
  67.  * Don't start endlevel if OF_SHOULD_BE_DEAD is set for player
  68.  * 
  69.  * Revision 1.68  1994/12/12  15:44:54  rob
  70.  * Rolled back a change to endlevel_start that caused more bugs than
  71.  * it fixed.
  72.  * 
  73.  * Revision 1.67  1994/12/12  12:08:33  rob
  74.  * IF a player is dead upon entering the tunnel, make them not dead.  Not perfect solution
  75.  * but avoids some last-minute weirdness we want to fix.  This should be revisited in new
  76.  * versions if possible!
  77.  * 
  78.  * Revision 1.66  1994/12/11  22:02:13  allender
  79.  * made endlevel data loading work with .txb encoded format (made with
  80.  * compbit -i level0?.end -o level0?.txb)
  81.  * 
  82.  * Revision 1.65  1994/12/11  20:32:47  matt
  83.  * Made camera transition happen 1/3 of the way through exit tunnel
  84.  * 
  85.  * Revision 1.64  1994/12/08  20:56:27  john
  86.  * More cfile stuff.
  87.  * 
  88.  * Revision 1.63  1994/12/07  17:00:52  rob
  89.  * Trying to fix homing tone warning when in exit tunnel.
  90.  * 
  91.  * Revision 1.62  1994/12/06  13:24:47  matt
  92.  * Made exit model come out of bitmaps.tbl
  93.  * 
  94.  * Revision 1.61  1994/12/06  12:06:22  matt
  95.  * Fixed/cleaned up satellite (planet/sun) code
  96.  * 
  97.  * Revision 1.60  1994/12/05  13:37:12  adam
  98.  * removed slew-mode
  99.  * 
  100.  * Revision 1.59  1994/12/05  12:49:37  matt
  101.  * Made satellite a rod (instead of a plane old non-rotating bitmap), and
  102.  * made the size settable in the .end file
  103.  * 
  104.  * Revision 1.58  1994/12/04  21:40:00  matt
  105.  * Added explosion sounds
  106.  * 
  107.  * Revision 1.57  1994/12/04  18:31:41  matt
  108.  * Wasn't coding planet position, causing it to disappear sometimes
  109.  * 
  110.  * Revision 1.56  1994/12/04  14:30:26  john
  111.  * Added hooks for music..
  112.  * 
  113.  * Revision 1.55  1994/12/04  13:53:52  matt
  114.  * Added code to make camera off-centered during lookback
  115.  * 
  116.  * Revision 1.54  1994/12/04  12:30:18  matt
  117.  * Fixed slew for short sequence
  118.  * 
  119.  * Revision 1.53  1994/12/03  19:28:10  matt
  120.  * Added alternate model for exit model after mine destruction
  121.  * 
  122.  * Revision 1.52  1994/12/03  00:17:23  matt
  123.  * Made endlevel sequence cut off early
  124.  * Made exit model and bit explosion always plot last (after all terrain)
  125.  * 
  126.  * Revision 1.51  1994/12/01  20:15:43  yuan
  127.  * Localization.
  128.  * 
  129.  * Revision 1.50  1994/11/30  23:27:35  adam
  130.  * mucked around carelessly
  131.  * 
  132.  * Revision 1.49  1994/11/28  21:50:37  mike
  133.  * optimizations.
  134.  * 
  135.  * Revision 1.48  1994/11/28  00:12:05  allender
  136.  * took out demo code that was in at one time to record endlevel sequence.
  137.  * We are _not_ recording endlevel sequence
  138.  * 
  139.  * Revision 1.47  1994/11/27  23:35:54  allender
  140.  * pause demo recording when starting endlevel sequence.  on demo playback,
  141.  * don't do endlevel at all.
  142.  * 
  143.  * Revision 1.46  1994/11/27  23:13:59  matt
  144.  * Made changes for new mprintf calling convention
  145.  * 
  146.  * Revision 1.45  1994/11/26  23:17:29  matt
  147.  * When camera leaves mine, bank it so it's level with the ground
  148.  * 
  149.  * Revision 1.44  1994/11/23  16:52:13  rob
  150.  * Ended netgame endlevel sequence a bit earlier.
  151.  * 
  152.  * Revision 1.43  1994/11/22  19:20:46  rob
  153.  * Modem support for secret levels.
  154.  * 
  155.  * Revision 1.42  1994/11/22  12:11:03  rob
  156.  * Fixed bug - file handle left open in load_endlevel_data.
  157.  * 
  158.  * Revision 1.41  1994/11/21  17:29:22  matt
  159.  * Cleaned up sequencing & game saving for secret levels
  160.  * 
  161.  * Revision 1.40  1994/11/19  15:14:54  mike
  162.  * remove unused code and data
  163.  * 
  164.  * Revision 1.39  1994/11/19  12:41:32  matt
  165.  * Added system to read endlevel data from file, and to make it work
  166.  * with any exit tunnel.
  167.  * 
  168.  * Revision 1.38  1994/11/17  15:02:24  mike
  169.  * support new segment validation functions.
  170.  * 
  171.  * Revision 1.37  1994/11/17  13:04:45  allender
  172.  * backout out newdemo changes
  173.  * 
  174.  * Revision 1.35  1994/11/16  14:52:33  rob
  175.  * Commented out SLEW_ON on Matt's direction.
  176.  * Changed something to fix demo recording.
  177.  * 
  178.  * Revision 1.34  1994/11/16  11:49:29  matt
  179.  * Added code to rotate terrain to match mine
  180.  * 
  181.  * Revision 1.33  1994/11/14  17:54:54  allender
  182.  * on exit sequence during demo recording, force player exited from mine
  183.  * packet to all other network players
  184.  * 
  185.  * Revision 1.32  1994/11/10  21:27:42  matt
  186.  * Took out printf's
  187.  * 
  188.  * Revision 1.31  1994/11/10  14:02:24  matt
  189.  * Hacked in support for player ships with different textures
  190.  * 
  191.  * Revision 1.30  1994/11/09  10:31:33  matt
  192.  * Don't create explosions if can't find seg to create them in
  193.  * 
  194.  * Revision 1.29  1994/11/05  17:22:37  john
  195.  * Fixed lots of sequencing problems with newdemo stuff.
  196.  * 
  197.  * Revision 1.28  1994/11/03  11:10:39  matt
  198.  * Fixed chase angles code
  199.  * Maybe other things, too.
  200.  * 
  201.  * Revision 1.27  1994/10/30  20:09:21  matt
  202.  * For endlevel: added big explosion at tunnel exit; made lights in tunnel 
  203.  * go out; made more explosions on walls.
  204.  * 
  205.  * Revision 1.26  1994/10/28  16:37:50  allender
  206.  * stop demo recording when endlevel sequence activated
  207.  * 
  208.  * Revision 1.25  1994/10/27  21:15:21  matt
  209.  * Added explosions in mine chasing player
  210.  * 
  211.  * Revision 1.24  1994/10/27  01:03:57  matt
  212.  * Fixed several small bugs in flythrough
  213.  * 
  214.  * Revision 1.23  1994/10/22  01:32:30  matt
  215.  * Don't start endlevel sequence if player dead
  216.  * 
  217.  * Revision 1.22  1994/10/22  00:08:06  matt
  218.  * Fixed up problems with bonus & game sequencing
  219.  * Player doesn't get credit for hostages unless he gets them out alive
  220.  * 
  221.  * 
  222.  * 
  223.  */
  224.  
  225. #pragma off (unreferenced)
  226. static char rcsid[] = "$Id: endlevel.c 2.2 1995/03/21 14:40:14 john Exp $";
  227. #pragma on (unreferenced)
  228.  
  229. //#define SLEW_ON 1
  230.  
  231. //#define _MARK_ON
  232.  
  233. #include <stdlib.h>
  234. //#include <wsample.h> //This file not included in public domain release -KRB
  235. #include <stdio.h>
  236. #include <ctype.h>
  237. #include <string.h>
  238.  
  239. #include "3d.h"
  240. #include "error.h"
  241. #include "gr.h"
  242. #include "palette.h"
  243. #include "iff.h"
  244. #include "mono.h"
  245. #include "texmap.h"
  246. #include "fvi.h"
  247. #include "mem.h"
  248. #include "sounds.h"
  249.  
  250. #include "inferno.h"
  251. #include "endlevel.h"
  252. #include "object.h"
  253. #include "game.h"
  254. #include "gauges.h"
  255. #include "wall.h"
  256. #include "terrain.h"
  257. #include "polyobj.h"
  258. #include "bm.h"
  259. #include "gameseq.h"
  260. #include "newdemo.h"
  261. #include "multi.h"
  262. #include "vclip.h"
  263. #include "fireball.h"
  264. #include "network.h"
  265. #include "text.h"
  266. #include "digi.h"
  267. #include "cfile.h"
  268. #include "compbit.h"
  269. #include "songs.h"
  270.  
  271. typedef struct flythrough_data {
  272.     object        *obj;
  273.     vms_angvec    angles;            //orientation in angles
  274.     vms_vector    step;                //how far in a second
  275.     vms_vector    angstep;            //rotation per second
  276.     fix            speed;            //how fast object is moving
  277.     vms_vector     headvec;            //where we want to be pointing
  278.     int            first_time;        //flag for if first time through
  279.     fix            offset_frac;    //how far off-center as portion of way
  280.     fix            offset_dist;    //how far currently off-center
  281. } flythrough_data;
  282.  
  283. //endlevel sequence states
  284.  
  285. #define EL_OFF                0        //not in endlevel
  286. #define EL_FLYTHROUGH    1        //auto-flythrough in tunnel
  287. #define EL_LOOKBACK        2        //looking back at player
  288. #define EL_OUTSIDE        3        //flying outside for a while
  289. #define EL_STOPPED        4        //stopped, watching explosion
  290. #define EL_PANNING        5        //panning around, watching player
  291. #define EL_CHASING        6        //chasing player to station
  292.  
  293. #define SHORT_SEQUENCE    1        //if defined, end sequnce when panning starts
  294. //#define STATION_ENABLED    1        //if defined, load & use space station model
  295.  
  296. int Endlevel_sequence = 0;
  297.  
  298. extern fix player_speed;
  299.  
  300. int transition_segnum,exit_segnum;
  301.  
  302. object *endlevel_camera;
  303.  
  304. #define FLY_SPEED i2f(50)
  305.  
  306. #define FLY_ACCEL i2f(5)
  307.  
  308. fix cur_fly_speed,desired_fly_speed;
  309.  
  310. extern int matt_find_connect_side(int seg0,int seg1);
  311.  
  312. grs_bitmap *satellite_bitmap,*station_bitmap,*terrain_bitmap;    //!!*exit_bitmap,
  313. vms_vector satellite_pos,satellite_upvec;
  314. //!!grs_bitmap **exit_bitmap_list[1];
  315. int station_modelnum,exit_modelnum,destroyed_exit_modelnum;
  316.  
  317. vms_vector station_pos = {0xf8c4<<10,0x3c1c<<12,0x372<<10};
  318.  
  319. #ifdef STATION_ENABLED
  320. grs_bitmap *station_bitmap;
  321. grs_bitmap **station_bitmap_list[1];
  322. int station_modelnum;
  323. #endif
  324.  
  325. vms_vector mine_exit_point;
  326. vms_vector mine_ground_exit_point;
  327. vms_vector mine_side_exit_point;
  328. vms_matrix mine_exit_orient;
  329.  
  330. int outside_mine;
  331.  
  332. start_endlevel_flythrough(int n,object *obj,fix speed);
  333.  
  334. grs_bitmap terrain_bm_instance;
  335. grs_bitmap satellite_bm_instance;
  336.  
  337. //find delta between two angles
  338. fixang delta_ang(fixang a,fixang b)
  339. {
  340.     fixang delta0,delta1;
  341.  
  342.     return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1;
  343.  
  344. }
  345.  
  346. //return though which side of seg0 is seg1
  347. int matt_find_connect_side(int seg0,int seg1)
  348. {
  349.     segment *Seg=&Segments[seg0];
  350.     int i;
  351.  
  352.     for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i;
  353.  
  354.     return -1;
  355. }
  356.  
  357. free_endlevel_data()
  358. {
  359.     if (terrain_bm_instance.bm_data)
  360.         free(terrain_bm_instance.bm_data);
  361.  
  362.     if (satellite_bm_instance.bm_data)
  363.         free(satellite_bm_instance.bm_data);
  364. }
  365.  
  366. init_endlevel()
  367. {
  368.     //##satellite_bitmap = bm_load("earth.bbm");
  369.     //##terrain_bitmap = bm_load("moon.bbm");
  370.     //##
  371.     //##load_terrain("matt5b.bbm");        //load bitmap as height array
  372.     //##//load_terrain("ttest2.bbm");        //load bitmap as height array
  373.     
  374.     #ifdef STATION_ENABLED
  375.     station_bitmap = bm_load("steel3.bbm");
  376.     station_bitmap_list[0] = &station_bitmap;
  377.  
  378.     station_modelnum = load_polygon_model("station.pof",1,station_bitmap_list,NULL);
  379.     #endif
  380.  
  381. //!!    exit_bitmap = bm_load("steel1.bbm");
  382. //!!    exit_bitmap_list[0] = &exit_bitmap;
  383.  
  384. //!!    exit_modelnum = load_polygon_model("exit01.pof",1,exit_bitmap_list,NULL);
  385. //!!    destroyed_exit_modelnum = load_polygon_model("exit01d.pof",1,exit_bitmap_list,NULL);
  386.  
  387.     generate_starfield();
  388.  
  389.     atexit(free_endlevel_data);
  390.  
  391.     terrain_bm_instance.bm_data = satellite_bm_instance.bm_data = NULL;
  392. }
  393.  
  394. static int cockpit_mode_save;
  395.  
  396. object external_explosion;
  397. int ext_expl_playing,mine_destroyed;
  398.  
  399. extern fix flash_scale;
  400.  
  401. vms_angvec exit_angles={-0xa00,0,0};
  402.  
  403. vms_matrix surface_orient;
  404.  
  405. int endlevel_data_loaded=0;
  406.  
  407. start_endlevel_sequence()
  408. {
  409.     int last_segnum,exit_side,tunnel_length;
  410.  
  411.     if (Newdemo_state == ND_STATE_RECORDING)        // stop demo recording
  412.         Newdemo_state = ND_STATE_PAUSED;
  413.  
  414.     if (Newdemo_state == ND_STATE_PLAYBACK)        // don't do this if in playback mode
  415.         return;
  416.  
  417.     if (Player_is_dead || ConsoleObject->flags&OF_SHOULD_BE_DEAD)
  418.         return;                //don't start if dead!
  419.  
  420.     Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
  421.  
  422.     reset_rear_view();        //turn off rear view if set
  423.  
  424.     if (!endlevel_data_loaded) {
  425.  
  426.         #ifdef NETWORK
  427.         if (Game_mode & GM_MULTI) {
  428.             multi_send_endlevel_start(0);
  429.             #ifdef NETWORK
  430.             network_do_frame(1, 1);
  431.             #endif
  432.         }
  433.         #endif
  434.  
  435.         gr_palette_fade_out(gr_palette, 32, 0);
  436.  
  437.         PlayerFinishedLevel(0);        //don't do special sequence
  438.         return;
  439.     }
  440.  
  441.     {
  442.         int segnum,old_segnum,entry_side,i;
  443.  
  444.         //count segments in exit tunnel
  445.  
  446.         old_segnum = ConsoleObject->segnum;
  447.         exit_side = find_exit_side(ConsoleObject);
  448.         segnum = Segments[old_segnum].children[exit_side];
  449.         tunnel_length = 0;
  450.         do {
  451.             entry_side = matt_find_connect_side(segnum,old_segnum);
  452.             exit_side = Side_opposite[entry_side];
  453.             old_segnum = segnum;
  454.             segnum = Segments[segnum].children[exit_side];
  455.             tunnel_length++;
  456.         } while (segnum >= 0);
  457.  
  458.         if (segnum != -2) {
  459.             PlayerFinishedLevel(0);        //don't do special sequence
  460.             return;
  461.         }
  462.  
  463.         last_segnum = old_segnum;
  464.  
  465.         //now pick transition segnum 1/3 of the way in
  466.  
  467.         old_segnum = ConsoleObject->segnum;
  468.         exit_side = find_exit_side(ConsoleObject);
  469.         segnum = Segments[old_segnum].children[exit_side];
  470.         i=tunnel_length/3;
  471.         while (i--) {
  472.             entry_side = matt_find_connect_side(segnum,old_segnum);
  473.             exit_side = Side_opposite[entry_side];
  474.             old_segnum = segnum;
  475.             segnum = Segments[segnum].children[exit_side];
  476.         }
  477.         transition_segnum = segnum;
  478.  
  479.     }
  480.  
  481.     Assert(last_segnum == exit_segnum);
  482.  
  483.     cockpit_mode_save = Cockpit_mode;
  484.  
  485.     #ifdef NETWORK
  486.     if (Game_mode & GM_MULTI) {
  487.         multi_send_endlevel_start(0);
  488.         network_do_frame(1, 1);
  489.     }
  490.     #endif
  491.  
  492.     songs_play_song( SONG_ENDLEVEL, 0 );
  493.  
  494.     Endlevel_sequence = EL_FLYTHROUGH;
  495.  
  496.     ConsoleObject->movement_type = MT_NONE;            //movement handled by flythrough
  497.     ConsoleObject->control_type = CT_NONE;
  498.  
  499.     Game_suspended |= SUSP_ROBOTS;          //robots don't move
  500.  
  501.     cur_fly_speed = desired_fly_speed = FLY_SPEED;
  502.  
  503.     start_endlevel_flythrough(0,ConsoleObject,cur_fly_speed);        //initialize
  504.  
  505.     HUD_init_message( TXT_EXIT_SEQUENCE );
  506.  
  507.     outside_mine = ext_expl_playing = 0;
  508.  
  509.     flash_scale = f1_0;
  510.  
  511.     //init_endlevel();
  512.  
  513.     mine_destroyed=0;
  514.  
  515. }
  516.  
  517. extern flythrough_data fly_objects[];
  518.  
  519. extern object *slew_obj;
  520.  
  521. vms_angvec player_angles,player_dest_angles;
  522. vms_angvec camera_desired_angles,camera_cur_angles;
  523.  
  524. #define CHASE_TURN_RATE (0x4000/4)        //max turn per second
  525.  
  526. //returns bitmask of which angles are at dest. bits 0,1,2 = p,b,h
  527. int chase_angles(vms_angvec *cur_angles,vms_angvec *desired_angles)
  528. {
  529.     vms_angvec delta_angs,alt_angles,alt_delta_angs;
  530.     fix total_delta,alt_total_delta;
  531.     fix frame_turn;
  532.     int mask=0;
  533.  
  534.     delta_angs.p = desired_angles->p - cur_angles->p;
  535.     delta_angs.h = desired_angles->h - cur_angles->h;
  536.     delta_angs.b = desired_angles->b - cur_angles->b;
  537. //delta_angs.b = 0;
  538.  
  539. //printf("chasing angles...desired = %x %x %x, cur = %x %x %x   ",desired_angles->p,desired_angles->b,desired_angles->h,cur_angles->p,cur_angles->b,cur_angles->h);
  540.  
  541.     total_delta = abs(delta_angs.p) + abs(delta_angs.b) + abs(delta_angs.h);
  542.  
  543.     alt_angles.p = f1_0/2 - cur_angles->p;
  544.     alt_angles.b = cur_angles->b + f1_0/2;
  545.     alt_angles.h = cur_angles->h + f1_0/2;
  546.  
  547.     alt_delta_angs.p = desired_angles->p - alt_angles.p;
  548.     alt_delta_angs.h = desired_angles->h - alt_angles.h;
  549.     alt_delta_angs.b = desired_angles->b - alt_angles.b;
  550. //alt_delta_angs.b = 0;
  551.  
  552.     alt_total_delta = abs(alt_delta_angs.p) + abs(alt_delta_angs.b) + abs(alt_delta_angs.h);
  553.  
  554. //printf("Total delta = %x, alt total_delta = %x\n",total_delta,alt_total_delta);
  555.  
  556.     if (alt_total_delta < total_delta) {
  557.         //mprintf((0,"FLIPPING ANGLES!\n"));
  558.         //printf("FLIPPING ANGLES!\n");
  559.         *cur_angles = alt_angles;
  560.         delta_angs = alt_delta_angs;
  561.     }
  562.  
  563.     frame_turn = fixmul(FrameTime,CHASE_TURN_RATE);
  564.  
  565.     if (abs(delta_angs.p) < frame_turn) {
  566.         cur_angles->p = desired_angles->p;
  567.         mask |= 1;
  568.     }
  569.     else
  570.         if (delta_angs.p > 0)
  571.             cur_angles->p += frame_turn;
  572.         else
  573.             cur_angles->p -= frame_turn;
  574.  
  575.     if (abs(delta_angs.b) < frame_turn) {
  576.         cur_angles->b = desired_angles->b;
  577.         mask |= 2;
  578.     }
  579.     else
  580.         if (delta_angs.b > 0)
  581.             cur_angles->b += frame_turn;
  582.         else
  583.             cur_angles->b -= frame_turn;
  584. //cur_angles->b = 0;
  585.  
  586.     if (abs(delta_angs.h) < frame_turn) {
  587.         cur_angles->h = desired_angles->h;
  588.         mask |= 4;
  589.     }
  590.     else
  591.         if (delta_angs.h > 0)
  592.             cur_angles->h += frame_turn;
  593.         else
  594.             cur_angles->h -= frame_turn;
  595.  
  596.     return mask;
  597. }
  598.  
  599. stop_endlevel_sequence()
  600. {
  601.     Interpolation_method = 0;
  602.  
  603.     gr_palette_fade_out(gr_palette, 32, 0);
  604.  
  605.     select_cockpit(cockpit_mode_save);
  606.  
  607.     Endlevel_sequence = EL_OFF;
  608.  
  609.     PlayerFinishedLevel(0);
  610.  
  611. }
  612.  
  613. #define VCLIP_BIG_PLAYER_EXPLOSION    58
  614.  
  615. //--unused-- vms_vector upvec = {0,f1_0,0};
  616.  
  617. //find the angle between the player's heading & the station
  618. get_angs_to_object(vms_angvec *av,vms_vector *targ_pos,vms_vector *cur_pos)
  619. {
  620.     vms_vector tv;
  621.  
  622.     vm_vec_sub(&tv,targ_pos,cur_pos);
  623.  
  624.     vm_extract_angles_vector(av,&tv);
  625. }
  626.  
  627. do_endlevel_frame()
  628. {
  629.     static fix timer;
  630.     vms_vector save_last_pos;
  631.     static fix explosion_wait1=0;
  632.     static fix explosion_wait2=0;
  633.     static fix bank_rate;
  634.     static fix ext_expl_halflife;
  635.  
  636.     save_last_pos = ConsoleObject->last_pos;    //don't let move code change this
  637.     object_move_all();
  638.     ConsoleObject->last_pos = save_last_pos;
  639.  
  640.     if (ext_expl_playing) {
  641.  
  642.         external_explosion.lifeleft -= FrameTime;
  643.         do_explosion_sequence(&external_explosion);
  644.  
  645.         if (external_explosion.lifeleft < ext_expl_halflife)
  646.             mine_destroyed = 1;
  647.  
  648.         if (external_explosion.flags & OF_SHOULD_BE_DEAD)
  649.             ext_expl_playing = 0;
  650.     }
  651.  
  652.     if (cur_fly_speed != desired_fly_speed) {
  653.         fix delta = desired_fly_speed - cur_fly_speed;
  654.         fix frame_accel = fixmul(FrameTime,FLY_ACCEL);
  655.  
  656.         if (abs(delta) < frame_accel)
  657.             cur_fly_speed = desired_fly_speed;
  658.         else
  659.             if (delta > 0)
  660.                 cur_fly_speed += frame_accel;
  661.             else
  662.                 cur_fly_speed -= frame_accel;
  663.     }
  664.  
  665.     //do big explosions
  666.     if (!outside_mine) {
  667.  
  668.         if (Endlevel_sequence==EL_OUTSIDE) {
  669.             vms_vector tvec;
  670.  
  671.             vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point);
  672.  
  673.             if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) {
  674.                 object *tobj;
  675.  
  676.                 outside_mine = 1;
  677.  
  678.                 tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION);
  679.  
  680.                 if (tobj) {
  681.                     external_explosion = *tobj;
  682.  
  683.                     tobj->flags |= OF_SHOULD_BE_DEAD;
  684.  
  685.                     flash_scale = 0;    //kill lights in mine
  686.  
  687.                     ext_expl_halflife = tobj->lifeleft;
  688.  
  689.                     ext_expl_playing = 1;
  690.                 }
  691.     
  692.                 digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 );
  693.             }
  694.         }
  695.  
  696.         //do explosions chasing player
  697.         if ((explosion_wait1-=FrameTime) < 0) {
  698.             vms_vector tpnt;
  699.             int segnum;
  700.             object *expl;
  701.             static int sound_count;
  702.  
  703.             vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5);
  704.             vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*15);
  705.             vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*15);
  706.  
  707.             segnum = find_point_seg(&tpnt,ConsoleObject->segnum);
  708.  
  709.             if (segnum != -1) {
  710.                 expl = object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION);
  711.                 if (rand()<10000 || ++sound_count==7) {        //pseudo-random
  712.                     digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 );
  713.                     sound_count=0;
  714.                 }
  715.             }
  716.  
  717.             explosion_wait1 = 0x2000 + rand()/4;
  718.  
  719.         }
  720.     }
  721.  
  722.     //do little explosions on walls
  723.     if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE)
  724.         if ((explosion_wait2-=FrameTime) < 0) {
  725.             vms_vector tpnt;
  726.             fvi_query fq;
  727.             fvi_info hit_data;
  728.  
  729.             //create little explosion on wall
  730.  
  731.             vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*100);
  732.             vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*100);
  733.             vm_vec_add2(&tpnt,&ConsoleObject->pos);
  734.  
  735.             if (Endlevel_sequence == EL_FLYTHROUGH)
  736.                 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*200);
  737.             else
  738.                 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*60);
  739.  
  740.             //find hit point on wall
  741.  
  742.             fq.p0 = &ConsoleObject->pos;
  743.             fq.p1 = &tpnt;
  744.             fq.startseg = ConsoleObject->segnum;
  745.             fq.rad = 0;
  746.             fq.thisobjnum = 0;
  747.             fq.ignore_obj_list = NULL;
  748.             fq.flags = 0;
  749.  
  750.             find_vector_intersection(&fq,&hit_data);
  751.  
  752.             if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1)
  753.                 object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+rand()*6,VCLIP_SMALL_EXPLOSION);
  754.  
  755.             explosion_wait2 = (0xa00 + rand()/8)/2;
  756.         }
  757.  
  758.     switch (Endlevel_sequence) {
  759.  
  760.         case EL_OFF: return;
  761.  
  762.         case EL_FLYTHROUGH: {
  763.  
  764.             do_endlevel_flythrough(0);
  765.  
  766.             if (ConsoleObject->segnum == transition_segnum) {
  767.                 int objnum;
  768.  
  769.                 Endlevel_sequence = EL_LOOKBACK;
  770.  
  771.                 objnum = obj_create(OBJ_CAMERA, 0, 
  772.                     ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0,
  773.                     CT_NONE,MT_NONE,RT_NONE);
  774.  
  775.                 if (objnum == -1) {                //can't get object, so abort
  776.                     mprintf((1, "Can't get object for endlevel sequence.  Aborting endlevel sequence.\n"));
  777.                     stop_endlevel_sequence();
  778.                     return;
  779.                 }
  780.  
  781.                 Viewer = endlevel_camera = &Objects[objnum];
  782.  
  783.                 select_cockpit(CM_LETTERBOX);
  784.  
  785.                 fly_objects[1] = fly_objects[0];
  786.                 fly_objects[1].obj = endlevel_camera;
  787.                 fly_objects[1].speed = (5*cur_fly_speed)/4;
  788.                 fly_objects[1].offset_frac = 0x4000;
  789.  
  790.                 vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7));
  791.  
  792.                 timer=0x20000;
  793.             }
  794.  
  795.             break;
  796.         }
  797.  
  798.  
  799.         case EL_LOOKBACK: {
  800.  
  801.             do_endlevel_flythrough(0);
  802.             do_endlevel_flythrough(1);
  803.  
  804.             if (timer>0) {
  805.  
  806.                 timer -= FrameTime;
  807.  
  808.                 if (timer < 0)        //reduce speed
  809.                     fly_objects[1].speed = fly_objects[0].speed;
  810.             }
  811.  
  812.             if (endlevel_camera->segnum == exit_segnum) {
  813.                 vms_angvec cam_angles,exit_seg_angles;
  814.  
  815.                 Endlevel_sequence = EL_OUTSIDE;
  816.  
  817.                 timer = i2f(2);
  818.  
  819.                 vm_vec_negate(&endlevel_camera->orient.fvec);
  820.                 vm_vec_negate(&endlevel_camera->orient.rvec);
  821.  
  822.                 vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
  823.                 vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient);
  824.                 bank_rate = (-exit_seg_angles.b - cam_angles.b)/2;
  825.  
  826.                 ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE;
  827.  
  828.                 //_MARK_("Starting outside");//Commented out by KRB
  829.  
  830. #ifdef SLEW_ON
  831.  slew_obj = endlevel_camera;
  832. #endif
  833.             }
  834.                 
  835.             break;
  836.         }
  837.  
  838.         case EL_OUTSIDE: {
  839.             #ifndef SLEW_ON
  840.             vms_angvec cam_angles;
  841.             #endif
  842.  
  843.             vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
  844. #ifndef SLEW_ON
  845.             vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed));
  846.             vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10));
  847.  
  848.             vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
  849.             cam_angles.b += fixmul(bank_rate,FrameTime);
  850.             vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles);
  851. #endif
  852.  
  853.             timer -= FrameTime;
  854.  
  855.             if (timer < 0) {
  856.  
  857.                 Endlevel_sequence = EL_STOPPED;
  858.  
  859.                 vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient);
  860.  
  861.                 timer = i2f(3);
  862.  
  863.             }
  864.  
  865.             break;
  866.         }
  867.  
  868.         case EL_STOPPED: {
  869.  
  870.             get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
  871.             chase_angles(&player_angles,&player_dest_angles);
  872.             vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
  873.  
  874.             vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
  875.  
  876.             timer -= FrameTime;
  877.  
  878.             if (timer < 0) {
  879.  
  880.                 #ifdef SLEW_ON
  881.                 slew_obj = endlevel_camera;
  882.                 _do_slew_movement(endlevel_camera,1,1);
  883.                 timer += FrameTime;        //make time stop
  884.                 break;
  885.                 #else
  886.  
  887.                 #ifdef SHORT_SEQUENCE
  888.  
  889.                 stop_endlevel_sequence();
  890.  
  891.                 #else
  892.                 Endlevel_sequence = EL_PANNING;
  893.  
  894.                 vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient);
  895.  
  896.  
  897.                 timer = i2f(3);
  898.  
  899.                 if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer
  900.                     stop_endlevel_sequence();
  901.                     return;
  902.                 }
  903.  
  904.                 //mprintf((0,"Switching to pan...\n"));
  905.                 #endif        //SHORT_SEQUENCE
  906.                 #endif        //SLEW_ON
  907.  
  908.             }
  909.             break;
  910.         }
  911.  
  912.         #ifndef SHORT_SEQUENCE
  913.         case EL_PANNING: {
  914.             #ifndef SLEW_ON
  915.             int mask;
  916.             #endif
  917.  
  918.             get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
  919.             chase_angles(&player_angles,&player_dest_angles);
  920.             vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
  921.             vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
  922.  
  923.             #ifdef SLEW_ON
  924.             _do_slew_movement(endlevel_camera,1,1);
  925.             #else
  926.  
  927.             get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
  928.             mask = chase_angles(&camera_cur_angles,&camera_desired_angles);
  929.             vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);
  930.  
  931.             if ((mask&5) == 5) {
  932.  
  933.                 vms_vector tvec;
  934.  
  935.                 Endlevel_sequence = EL_CHASING;
  936.  
  937.                 //_MARK_("Done outside");//Commented out -KRB
  938.  
  939.                 vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos);
  940.                 vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL);
  941.  
  942.                 desired_fly_speed *= 2;
  943.  
  944.                 //mprintf((0,"Switching to chase...\n"));
  945.  
  946.             }
  947.             #endif
  948.  
  949.             break;
  950.         }
  951.  
  952.         case EL_CHASING: {
  953.             fix d,speed_scale;
  954.  
  955.             #ifdef SLEW_ON
  956.             _do_slew_movement(endlevel_camera,1,1);
  957.             #endif
  958.  
  959.             get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
  960.             chase_angles(&camera_cur_angles,&camera_desired_angles);
  961.  
  962.             #ifndef SLEW_ON
  963.             vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);
  964.             #endif
  965.  
  966.             d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos);
  967.  
  968.             speed_scale = fixdiv(d,i2f(0x20));
  969.             if (d<f1_0) d=f1_0;
  970.  
  971.             get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
  972.             chase_angles(&player_angles,&player_dest_angles);
  973.             vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
  974.  
  975.             vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
  976.             #ifndef SLEW_ON
  977.             vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed)));
  978.  
  979.             if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10))
  980.                 stop_endlevel_sequence();
  981.             #endif
  982.  
  983.             break;
  984.  
  985.         }
  986.         #endif        //ifdef SHORT_SEQUENCE
  987.     }
  988. }
  989.  
  990.  
  991. #define MIN_D 0x100
  992.  
  993. //find which side to fly out of
  994. find_exit_side(object *obj)
  995. {
  996.     int i;
  997.     vms_vector prefvec,segcenter,sidevec;
  998.     fix best_val=-f2_0;
  999.     int best_side;
  1000.     segment *pseg = &Segments[obj->segnum];
  1001.  
  1002.     //find exit side
  1003.  
  1004.     vm_vec_normalized_dir_quick(&prefvec,&obj->pos,&obj->last_pos);
  1005.  
  1006.     compute_segment_center(&segcenter,pseg);
  1007.  
  1008.     best_side=-1;
  1009.     for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) {
  1010.         fix d;
  1011.  
  1012.         if (pseg->children[i]!=-1) {
  1013.  
  1014.             compute_center_point_on_side(&sidevec,pseg,i);
  1015.             vm_vec_normalized_dir_quick(&sidevec,&sidevec,&segcenter);
  1016.             d = vm_vec_dotprod(&sidevec,&prefvec);
  1017.  
  1018.             if (labs(d) < MIN_D) d=0;
  1019.  
  1020.             if (d > best_val) {best_val=d; best_side=i;}
  1021.  
  1022.         }
  1023.     }
  1024.  
  1025.     Assert(best_side!=-1);
  1026.  
  1027.     return best_side;
  1028. }
  1029.  
  1030. extern fix Render_zoom;                            //the player's zoom factor
  1031.  
  1032. extern vms_vector Viewer_eye;    //valid during render
  1033.  
  1034. void render_mine(int start_seg_num,fix eye_offset);
  1035.  
  1036. draw_exit_model()
  1037. {
  1038.     vms_vector model_pos;
  1039.     int f=15,u=0;    //21;
  1040.  
  1041.     vm_vec_scale_add(&model_pos,&mine_exit_point,&mine_exit_orient.fvec,i2f(f));
  1042.     vm_vec_scale_add2(&model_pos,&mine_exit_orient.uvec,i2f(u));
  1043.  
  1044.     draw_polygon_model(&model_pos,&mine_exit_orient,NULL,(mine_destroyed)?destroyed_exit_modelnum:exit_modelnum,0,f1_0,NULL,NULL);
  1045.  
  1046. }
  1047.  
  1048. int exit_point_bmx,exit_point_bmy;
  1049.  
  1050. fix satellite_size = i2f(400);
  1051.  
  1052. #define SATELLITE_DIST        i2f(1024)
  1053. #define SATELLITE_WIDTH        satellite_size
  1054. #define SATELLITE_HEIGHT    ((satellite_size*9)/4)        //((satellite_size*5)/2)
  1055.  
  1056. render_external_scene(fix eye_offset)
  1057. {
  1058.  
  1059.     Viewer_eye = Viewer->pos;
  1060.  
  1061.     if (eye_offset)
  1062.         vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
  1063.  
  1064.     g3_set_view_matrix(&Viewer->pos,&Viewer->orient,Render_zoom);
  1065.  
  1066.     //g3_draw_horizon(BM_XRGB(0,0,0),BM_XRGB(16,16,16));        //,-1);
  1067.     gr_clear_canvas(BM_XRGB(0,0,0));
  1068.  
  1069.     g3_start_instance_matrix(&vmd_zero_vector,&surface_orient);
  1070.     draw_stars();
  1071.     g3_done_instance();
  1072.  
  1073.     {    //draw satellite
  1074.  
  1075.         vms_vector delta;
  1076.         g3s_point p,top_pnt;
  1077.  
  1078.         g3_rotate_point(&p,&satellite_pos);
  1079.         g3_rotate_delta_vec(&delta,&satellite_upvec);
  1080.  
  1081.         g3_add_delta_vec(&top_pnt,&p,&delta);
  1082.  
  1083.         if (! (p.p3_codes & CC_BEHIND)) {
  1084.             int save_im = Interpolation_method;
  1085.             //p.p3_flags &= ~PF_PROJECTED;
  1086.             //g3_project_point(&p);
  1087.             if (! (p.p3_flags & PF_OVERFLOW)) {
  1088.                 Interpolation_method = 0;
  1089.                 //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap);
  1090.                 g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,f1_0);
  1091.                 Interpolation_method = save_im;
  1092.             }
  1093.         }
  1094.     }
  1095.  
  1096.     #ifdef STATION_ENABLED
  1097.     draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,f1_0,NULL,NULL);
  1098.     #endif
  1099.  
  1100.     render_terrain(&mine_ground_exit_point,exit_point_bmx,exit_point_bmy);
  1101.  
  1102.     draw_exit_model();
  1103.     if (ext_expl_playing)
  1104.         draw_fireball(&external_explosion);
  1105.  
  1106.     Lighting_on=0;
  1107.     render_object(ConsoleObject);
  1108.     Lighting_on=1;
  1109. }
  1110.  
  1111. #define MAX_STARS 500
  1112.  
  1113. vms_vector stars[MAX_STARS];
  1114.  
  1115. generate_starfield()
  1116. {
  1117.     int i;
  1118.  
  1119.     for (i=0;i<MAX_STARS;i++) {
  1120.  
  1121.         stars[i].x = (rand() - RAND_MAX/2) << 14;
  1122.         stars[i].z = (rand() - RAND_MAX/2) << 14;
  1123.         stars[i].y = (rand()/2) << 14;
  1124.  
  1125.     }
  1126. }
  1127.  
  1128. draw_stars()
  1129. {
  1130.     int i;
  1131.     int intensity=31;
  1132.     g3s_point p;
  1133.  
  1134.     for (i=0;i<MAX_STARS;i++) {
  1135.  
  1136.         if ((i&63) == 0) {
  1137.             gr_setcolor(BM_XRGB(intensity,intensity,intensity));
  1138.             intensity-=3;
  1139.         }            
  1140.  
  1141.         //g3_rotate_point(&p,&stars[i]);
  1142.         g3_rotate_delta_vec(&p.p3_vec,&stars[i]);
  1143.         g3_code_point(&p);
  1144.  
  1145.         if (p.p3_codes == 0) {
  1146.  
  1147.             p.p3_flags &= ~PF_PROJECTED;
  1148.  
  1149.             g3_project_point(&p);
  1150.  
  1151.             gr_pixel(f2i(p.p3_sx),f2i(p.p3_sy));
  1152.         }
  1153.     }
  1154.  
  1155. //@@    {
  1156. //@@        vms_vector delta;
  1157. //@@        g3s_point top_pnt;
  1158. //@@
  1159. //@@        g3_rotate_point(&p,&satellite_pos);
  1160. //@@        g3_rotate_delta_vec(&delta,&satellite_upvec);
  1161. //@@
  1162. //@@        g3_add_delta_vec(&top_pnt,&p,&delta);
  1163. //@@
  1164. //@@        if (! (p.p3_codes & CC_BEHIND)) {
  1165. //@@            int save_im = Interpolation_method;
  1166. //@@            Interpolation_method = 0;
  1167. //@@            //p.p3_flags &= ~PF_PROJECTED;
  1168. //@@            g3_project_point(&p);
  1169. //@@            if (! (p.p3_flags & PF_OVERFLOW))
  1170. //@@                //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap);
  1171. //@@                g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,f1_0);
  1172. //@@            Interpolation_method = save_im;
  1173. //@@        }
  1174. //@@    }
  1175.  
  1176. }
  1177.  
  1178. endlevel_render_mine(fix eye_offset)
  1179. {
  1180.     int start_seg_num;
  1181.  
  1182.     Viewer_eye = Viewer->pos;
  1183.  
  1184.     if (Viewer->type == OBJ_PLAYER )
  1185.         vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
  1186.  
  1187.     if (eye_offset)
  1188.         vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
  1189.  
  1190.     #ifdef EDITOR
  1191.     if (Function_mode==FMODE_EDITOR)
  1192.         Viewer_eye = Viewer->pos;
  1193.     #endif
  1194.  
  1195.     if (Endlevel_sequence >= EL_OUTSIDE) {
  1196.  
  1197.         start_seg_num = exit_segnum;
  1198.     }
  1199.     else {
  1200.         start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
  1201.  
  1202.         if (start_seg_num==-1)
  1203.             start_seg_num = Viewer->segnum;
  1204.     }
  1205.  
  1206.     if (Endlevel_sequence == EL_LOOKBACK) {
  1207.         vms_matrix headm,viewm;
  1208.         vms_angvec angles = {0,0,0x7fff};
  1209.  
  1210.         vm_angles_2_matrix(&headm,&angles);
  1211.         vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
  1212.         g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
  1213.     }
  1214.     else
  1215.         g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
  1216.  
  1217.     render_mine(start_seg_num,eye_offset);
  1218. }
  1219.  
  1220. void render_endlevel_frame(fix eye_offset)
  1221. {
  1222.  
  1223.     g3_start_frame();
  1224.  
  1225.     if (Endlevel_sequence < EL_OUTSIDE)
  1226.         endlevel_render_mine(eye_offset);
  1227.     else
  1228.         render_external_scene(eye_offset);
  1229.  
  1230.     g3_end_frame();
  1231.  
  1232. }
  1233.  
  1234.  
  1235.  
  1236. ///////////////////////// copy of flythrough code for endlevel
  1237.  
  1238.  
  1239. #define MAX_FLY_OBJECTS 2
  1240.  
  1241. flythrough_data fly_objects[MAX_FLY_OBJECTS];
  1242.  
  1243. flythrough_data *flydata;
  1244.  
  1245. int matt_find_connect_side(int seg0,int seg1);
  1246.  
  1247. void compute_segment_center(vms_vector *vp,segment *sp);
  1248.  
  1249. fixang delta_ang(fixang a,fixang b);
  1250. fixang interp_angle(fixang dest,fixang src,fixang step);
  1251.  
  1252. #define DEFAULT_SPEED i2f(16)
  1253.  
  1254. #define MIN_D 0x100
  1255.  
  1256. //if speed is zero, use default speed
  1257. start_endlevel_flythrough(int n,object *obj,fix speed)
  1258. {
  1259.     flydata = &fly_objects[n];
  1260.  
  1261.     flydata->obj = obj;
  1262.  
  1263.     flydata->first_time = 1;
  1264.  
  1265.     flydata->speed = speed?speed:DEFAULT_SPEED;
  1266.  
  1267.     flydata->offset_frac = 0;
  1268. }
  1269.  
  1270. static vms_angvec *angvec_add2_scale(vms_angvec *dest,vms_vector *src,fix s)
  1271. {
  1272.     dest->p += fixmul(src->x,s);
  1273.     dest->b  += fixmul(src->z,s);
  1274.     dest->h  += fixmul(src->y,s);
  1275.  
  1276.     return dest;
  1277. }
  1278.  
  1279. #define MAX_ANGSTEP    0x4000        //max turn per second
  1280.  
  1281. #define MAX_SLIDE_PER_SEGMENT 0x10000
  1282.  
  1283. do_endlevel_flythrough(int n)
  1284. {
  1285.     object *obj;
  1286.     segment *pseg;
  1287.     int old_player_seg;
  1288.  
  1289.     flydata = &fly_objects[n];
  1290.     obj = flydata->obj;
  1291.     
  1292.     old_player_seg = obj->segnum;
  1293.  
  1294.     //move the player for this frame
  1295.  
  1296.     if (!flydata->first_time) {
  1297.  
  1298.         vm_vec_scale_add2(&obj->pos,&flydata->step,FrameTime);
  1299.         angvec_add2_scale(&flydata->angles,&flydata->angstep,FrameTime);
  1300.  
  1301.         vm_angles_2_matrix(&obj->orient,&flydata->angles);
  1302.     }
  1303.  
  1304.     //check new player seg
  1305.  
  1306.     update_object_seg(obj);
  1307.     pseg = &Segments[obj->segnum];
  1308.  
  1309.     if (flydata->first_time || obj->segnum != old_player_seg) {        //moved into new seg
  1310.         vms_vector curcenter,nextcenter;
  1311.         fix step_size,seg_time;
  1312.         short entry_side,exit_side;    //what sides we entry and leave through
  1313.         vms_vector dest_point;        //where we are heading (center of exit_side)
  1314.         vms_angvec dest_angles;        //where we want to be pointing
  1315.         vms_matrix dest_orient;
  1316.         int up_side;
  1317.  
  1318.         //find new exit side
  1319.  
  1320.         if (!flydata->first_time) {
  1321.  
  1322.             entry_side = matt_find_connect_side(obj->segnum,old_player_seg);
  1323.             exit_side = Side_opposite[entry_side];
  1324.         }
  1325.  
  1326.         if (flydata->first_time || entry_side==-1 || pseg->children[exit_side]==-1)
  1327.             exit_side = find_exit_side(obj);
  1328.  
  1329.         {                                        //find closest side to align to
  1330.             fix d,largest_d=-f1_0;
  1331.             int i;
  1332.  
  1333.             for (i=0;i<6;i++) {
  1334.                 #ifdef COMPACT_SEGS
  1335.                 vms_vector v1;
  1336.                 get_side_normal(pseg, i, 0, &v1 );
  1337.                 d = vm_vec_dot(&v1,&flydata->obj->orient.uvec);
  1338.                 #else
  1339.                 d = vm_vec_dot(&pseg->sides[i].normals[0],&flydata->obj->orient.uvec);
  1340.                 #endif
  1341.                 if (d > largest_d) {largest_d = d; up_side=i;}
  1342.             }
  1343.  
  1344.         }
  1345.  
  1346.         //update target point & angles
  1347.  
  1348.         compute_center_point_on_side(&dest_point,pseg,exit_side);
  1349.  
  1350.         //update target point and movement points
  1351.  
  1352.         //offset object sideways
  1353.         if (flydata->offset_frac) {
  1354.             int s0=-1,s1,i;
  1355.             vms_vector s0p,s1p;
  1356.             fix dist;
  1357.  
  1358.             for (i=0;i<6;i++)
  1359.                 if (i!=entry_side && i!=exit_side && i!=up_side && i!=Side_opposite[up_side])
  1360.                     if (s0==-1)
  1361.                         s0 = i;
  1362.                     else
  1363.                         s1 = i;
  1364.  
  1365.             compute_center_point_on_side(&s0p,pseg,s0);
  1366.             compute_center_point_on_side(&s1p,pseg,s1);
  1367.             dist = fixmul(vm_vec_dist(&s0p,&s1p),flydata->offset_frac);
  1368.  
  1369.             if (dist-flydata->offset_dist > MAX_SLIDE_PER_SEGMENT)
  1370.                 dist = flydata->offset_dist + MAX_SLIDE_PER_SEGMENT;
  1371.  
  1372.             flydata->offset_dist = dist;
  1373.  
  1374.             vm_vec_scale_add2(&dest_point,&obj->orient.rvec,dist);
  1375.  
  1376.         }
  1377.  
  1378.         vm_vec_sub(&flydata->step,&dest_point,&obj->pos);
  1379.         step_size = vm_vec_normalize_quick(&flydata->step);
  1380.         vm_vec_scale(&flydata->step,flydata->speed);
  1381.  
  1382.         compute_segment_center(&curcenter,pseg);
  1383.         compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]);
  1384.         vm_vec_sub(&flydata->headvec,&nextcenter,&curcenter);
  1385.  
  1386.         #ifdef COMPACT_SEGS    
  1387.         {
  1388.             vms_vector _v1;
  1389.             get_side_normal(pseg, up_side, 0, &_v1 );
  1390.             vm_vector_2_matrix(&dest_orient,&flydata->headvec,&_v1,NULL);
  1391.         }
  1392.         #else
  1393.         vm_vector_2_matrix(&dest_orient,&flydata->headvec,&pseg->sides[up_side].normals[0],NULL);
  1394.         #endif
  1395.         vm_extract_angles_matrix(&dest_angles,&dest_orient);
  1396.  
  1397.         if (flydata->first_time)
  1398.             vm_extract_angles_matrix(&flydata->angles,&obj->orient);
  1399.  
  1400.         seg_time = fixdiv(step_size,flydata->speed);    //how long through seg
  1401.  
  1402.         if (seg_time) {
  1403.             flydata->angstep.x = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.p,dest_angles.p),seg_time)));
  1404.             flydata->angstep.z = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.b,dest_angles.b),seg_time)));
  1405.             flydata->angstep.y = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.h,dest_angles.h),seg_time)));
  1406.  
  1407.         }
  1408.         else {
  1409.             flydata->angles = dest_angles;
  1410.             flydata->angstep.x = flydata->angstep.y = flydata->angstep.z = 0;
  1411.         }
  1412.     }
  1413.  
  1414.     flydata->first_time=0;
  1415. }
  1416.  
  1417. #define JOY_NULL 15
  1418. #define ROT_SPEED 8        //rate of rotation while key held down
  1419. #define VEL_SPEED (15)    //rate of acceleration while key held down
  1420.  
  1421. extern short old_joy_x,old_joy_y;    //position last time around
  1422.  
  1423. #include "key.h"
  1424. #include "joy.h"
  1425.  
  1426. #ifdef SLEW_ON        //this is a special routine for slewing around external scene
  1427. int _do_slew_movement(object *obj, int check_keys, int check_joy )
  1428. {
  1429.     int moved = 0;
  1430.     vms_vector svel, movement;                //scaled velocity (per this frame)
  1431.     vms_matrix rotmat,new_pm;
  1432.     int joy_x,joy_y,btns;
  1433.     int joyx_moved,joyy_moved;
  1434.     vms_angvec rotang;
  1435.  
  1436.     if (keyd_pressed[KEY_PAD5])
  1437.         vm_vec_zero(&obj->phys_info.velocity);
  1438.  
  1439.     if (check_keys) {
  1440.         obj->phys_info.velocity.x += VEL_SPEED * (key_down_time(KEY_PAD9) - key_down_time(KEY_PAD7));
  1441.         obj->phys_info.velocity.y += VEL_SPEED * (key_down_time(KEY_PADMINUS) - key_down_time(KEY_PADPLUS));
  1442.         obj->phys_info.velocity.z += VEL_SPEED * (key_down_time(KEY_PAD8) - key_down_time(KEY_PAD2));
  1443.  
  1444.         rotang.pitch =  (key_down_time(KEY_LBRACKET) - key_down_time(KEY_RBRACKET))/ROT_SPEED;
  1445.         rotang.bank  = (key_down_time(KEY_PAD1) - key_down_time(KEY_PAD3))/ROT_SPEED;
  1446.         rotang.head  = (key_down_time(KEY_PAD6) - key_down_time(KEY_PAD4))/ROT_SPEED;
  1447.     }
  1448.     else
  1449.         rotang.pitch = rotang.bank  = rotang.head  = 0;
  1450.  
  1451.     //check for joystick movement
  1452.  
  1453.     if (check_joy && joy_present)    {
  1454.         joy_get_pos(&joy_x,&joy_y);
  1455.         btns=joy_get_btns();
  1456.     
  1457.         joyx_moved = (abs(joy_x - old_joy_x)>JOY_NULL);
  1458.         joyy_moved = (abs(joy_y - old_joy_y)>JOY_NULL);
  1459.     
  1460.         if (abs(joy_x) < JOY_NULL) joy_x = 0;
  1461.         if (abs(joy_y) < JOY_NULL) joy_y = 0;
  1462.     
  1463.         if (btns)
  1464.             if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 512,FrameTime); else;
  1465.         else
  1466.             if (joyy_moved) obj->phys_info.velocity.z = -joy_y * 8192;
  1467.     
  1468.         if (!rotang.head) rotang.head = fixmul(joy_x * 512,FrameTime);
  1469.     
  1470.         if (joyx_moved) old_joy_x = joy_x;
  1471.         if (joyy_moved) old_joy_y = joy_y;
  1472.     }
  1473.  
  1474.     moved = rotang.pitch | rotang.bank | rotang.head;
  1475.  
  1476.     vm_angles_2_matrix(&rotmat,&rotang);
  1477.     vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
  1478.     obj->orient = new_pm;
  1479.     vm_transpose_matrix(&new_pm);        //make those columns rows
  1480.  
  1481.     moved |= obj->phys_info.velocity.x | obj->phys_info.velocity.y | obj->phys_info.velocity.z;
  1482.  
  1483.     svel = obj->phys_info.velocity;
  1484.     vm_vec_scale(&svel,FrameTime);        //movement in this frame
  1485.     vm_vec_rotate(&movement,&svel,&new_pm);
  1486.  
  1487.     vm_vec_add2(&obj->pos,&movement);
  1488.  
  1489.     moved |= (movement.x || movement.y || movement.z);
  1490.  
  1491.     return moved;
  1492. }
  1493. #endif
  1494.  
  1495. #define LINE_LEN    80
  1496. #define NUM_VARS    8
  1497.  
  1498. #define STATION_DIST    i2f(1024)
  1499.  
  1500. int convert_ext( char *dest, char *ext )
  1501. {
  1502.     char *t;
  1503.  
  1504.     t = strchr(dest,'.');
  1505.  
  1506.     if (t && (t-dest <= 8)) {
  1507.         t[1] = ext[0];            
  1508.         t[2] = ext[1];            
  1509.         t[3] = ext[2];    
  1510.         return 1;
  1511.     }
  1512.     else
  1513.         return 0;
  1514. }
  1515.  
  1516. //called for each level to load & setup the exit sequence
  1517. load_endlevel_data(int level_num)
  1518. {
  1519.     char filename[13];
  1520.     char line[LINE_LEN],*p;
  1521.     CFILE *ifile;
  1522.     int var,segnum,sidenum;
  1523.     int exit_side, i;
  1524.     int have_binary = 0;
  1525.  
  1526.     endlevel_data_loaded = 0;        //not loaded yet
  1527.  
  1528. try_again:
  1529.     ;
  1530.  
  1531.     if (level_num<0)        //secret level
  1532.         strcpy(filename,Secret_level_names[-level_num-1]);
  1533.     else                    //normal level
  1534.         strcpy(filename,Level_names[level_num-1]);
  1535.  
  1536.     if (!convert_ext(filename,"END"))
  1537.         return;
  1538.  
  1539.     ifile = cfopen(filename,"rb");
  1540.  
  1541.     if (!ifile) {
  1542.  
  1543.         convert_ext(filename,"TXB");
  1544.  
  1545.         ifile = cfopen(filename,"rb");
  1546.  
  1547.         if (!ifile)
  1548.             if (level_num==1) {
  1549.                 return;        //abort
  1550.                 //Error("Cannot load file text of binary version of <%s>",filename);
  1551.             }
  1552.             else {
  1553.                 level_num = 1;
  1554.                 goto try_again;
  1555.             }
  1556.  
  1557.         have_binary = 1;
  1558.     }
  1559.  
  1560.     //ok...this parser is pretty simple.  It ignores comments, but
  1561.     //everything else must be in the right place
  1562.  
  1563.     var = 0;
  1564.  
  1565.     while (cfgets(line,LINE_LEN,ifile)) {
  1566.  
  1567.         if (have_binary) {
  1568.             for (i = 0; i < strlen(line) - 1; i++) {
  1569.                 encode_rotate_left(&(line[i]));
  1570.                 line[i] = line[i] ^ BITMAP_TBL_XOR;
  1571.                 encode_rotate_left(&(line[i]));
  1572.             }
  1573.             p = line;
  1574.         }
  1575.  
  1576.         if ((p=strchr(line,';'))!=NULL)
  1577.             *p = 0;        //cut off comment
  1578.  
  1579.         for (p=line+strlen(line)-1;p>line && isspace(*p);*p--=0);
  1580.         for (p=line;isspace(*p);p++);
  1581.  
  1582.         if (!*p)        //empty line
  1583.             continue;
  1584.  
  1585.         switch (var) {
  1586.  
  1587.             case 0: {                        //ground terrain
  1588.                 int iff_error;
  1589.                 ubyte pal[768];
  1590.  
  1591.                 if (terrain_bm_instance.bm_data)
  1592.                     free(terrain_bm_instance.bm_data);
  1593.  
  1594.                 iff_error = iff_read_bitmap(p,&terrain_bm_instance,BM_LINEAR,pal);
  1595.                 if (iff_error != IFF_NO_ERROR) {
  1596.                     mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error)));
  1597.                     Error("File %s - IFF error: %s",p,iff_errormsg(iff_error));
  1598.                 }
  1599.  
  1600.                 terrain_bitmap = &terrain_bm_instance;
  1601.                 gr_remap_bitmap_good( terrain_bitmap, pal, iff_transparent_color, -1);
  1602.  
  1603.                 break;
  1604.             }
  1605.  
  1606.             case 1:                            //height map
  1607.  
  1608.                 load_terrain(p);
  1609.                 break;
  1610.  
  1611.  
  1612.             case 2:
  1613.  
  1614.                 sscanf(p,"%d,%d",&exit_point_bmx,&exit_point_bmy);
  1615.                 break;
  1616.  
  1617.             case 3:                            //exit heading
  1618.  
  1619.                 exit_angles.h = i2f(atoi(p))/360;
  1620.                 break;
  1621.  
  1622.             case 4: {                        //planet bitmap
  1623.                 int iff_error;
  1624.                 ubyte pal[768];
  1625.  
  1626.                 if (satellite_bm_instance.bm_data)
  1627.                     free(satellite_bm_instance.bm_data);
  1628.  
  1629.                 iff_error = iff_read_bitmap(p,&satellite_bm_instance,BM_LINEAR,pal);
  1630.                 if (iff_error != IFF_NO_ERROR) {
  1631.                     mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error)));
  1632.                     Error("File %s - IFF error: %s",p,iff_errormsg(iff_error));
  1633.                 }
  1634.  
  1635.                 satellite_bitmap = &satellite_bm_instance;
  1636.                 gr_remap_bitmap_good( satellite_bitmap, pal, iff_transparent_color, -1);
  1637.  
  1638.                 break;
  1639.             }
  1640.  
  1641.             case 5:                            //earth pos
  1642.             case 7: {                        //station pos
  1643.                 vms_matrix tm;
  1644.                 vms_angvec ta;
  1645.                 int pitch,head;
  1646.  
  1647.                 sscanf(p,"%d,%d",&head,&pitch);
  1648.  
  1649.                 ta.h = i2f(head)/360;
  1650.                 ta.p = -i2f(pitch)/360;
  1651.                 ta.b = 0;
  1652.  
  1653.                 vm_angles_2_matrix(&tm,&ta);
  1654.  
  1655.                 if (var==5)
  1656.                     satellite_pos = tm.fvec;
  1657.                     //vm_vec_copy_scale(&satellite_pos,&tm.fvec,SATELLITE_DIST);
  1658.                 else
  1659.                     station_pos = tm.fvec;
  1660.  
  1661.                 break;
  1662.             }
  1663.  
  1664.             case 6:                        //planet size
  1665.                 satellite_size = i2f(atoi(p));
  1666.                 break;
  1667.         }
  1668.  
  1669.         var++;
  1670.  
  1671.     }
  1672.  
  1673.     Assert(var == NUM_VARS);
  1674.  
  1675.  
  1676.     // OK, now the data is loaded.  Initialize everything
  1677.  
  1678.     //find the exit sequence by searching all segments for a side with
  1679.     //children == -2
  1680.  
  1681.     for (segnum=0,exit_segnum=-1;exit_segnum==-1 && segnum<=Highest_segment_index;segnum++)
  1682.         for (sidenum=0;sidenum<6;sidenum++)
  1683.             if (Segments[segnum].children[sidenum] == -2) {
  1684.                 exit_segnum = segnum;
  1685.                 exit_side = sidenum;
  1686.                 break;
  1687.             }
  1688.  
  1689.     Assert(exit_segnum!=-1);
  1690.  
  1691.     compute_segment_center(&mine_exit_point,&Segments[exit_segnum]);
  1692.     extract_orient_from_segment(&mine_exit_orient,&Segments[exit_segnum]);
  1693.     compute_center_point_on_side(&mine_side_exit_point,&Segments[exit_segnum],exit_side);
  1694.  
  1695.     vm_vec_scale_add(&mine_ground_exit_point,&mine_exit_point,&mine_exit_orient.uvec,-i2f(20));
  1696.  
  1697.     //compute orientation of surface
  1698.     {
  1699.         vms_vector tv;
  1700.         vms_matrix exit_orient,tm;
  1701.  
  1702.         vm_angles_2_matrix(&exit_orient,&exit_angles);
  1703.         vm_transpose_matrix(&exit_orient);
  1704.         vm_matrix_x_matrix(&surface_orient,&mine_exit_orient,&exit_orient);
  1705.  
  1706.         vm_copy_transpose_matrix(&tm,&surface_orient);
  1707.         vm_vec_rotate(&tv,&station_pos,&tm);
  1708.         vm_vec_scale_add(&station_pos,&mine_exit_point,&tv,STATION_DIST);
  1709.  
  1710. vm_vec_rotate(&tv,&satellite_pos,&tm);
  1711. vm_vec_scale_add(&satellite_pos,&mine_exit_point,&tv,SATELLITE_DIST);
  1712.  
  1713. vm_vector_2_matrix(&tm,&tv,&surface_orient.uvec,NULL);
  1714. vm_vec_copy_scale(&satellite_upvec,&tm.uvec,SATELLITE_HEIGHT);
  1715.  
  1716.  
  1717.     }
  1718.  
  1719.     cfclose(ifile);
  1720.  
  1721.     endlevel_data_loaded = 1;
  1722.  
  1723. }
  1724.  
  1725.  
  1726. 
  1727.