1 /* $Id: endlevel.c,v 1.17 2003-10-10 09:36:35 btb Exp $ */
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
17 * Code for rendering external scenes
20 * Revision 1.5 1995/10/31 10:24:09 allender
23 * Revision 1.4 1995/09/14 16:33:54 allender
24 * fixed function return values for those that didn't
25 * have them...thanks matt!
27 * Revision 1.3 1995/07/28 15:36:26 allender
28 * reverse inverse sqrt change
30 * Revision 1.2 1995/07/28 15:17:40 allender
31 * inverse magnitude fixup
33 * Revision 1.1 1995/05/16 15:24:32 allender
36 * Revision 2.2 1995/03/21 14:40:14 john
37 * Ifdef'd out the NETWORK code.
39 * Revision 2.1 1995/03/20 18:15:50 john
40 * Added code to not store the normals in the segment structure.
42 * Revision 2.0 1995/02/27 11:30:42 john
43 * New version 2.0, which has no anonymous unions, builds with
44 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
46 * Revision 1.80 1995/02/22 13:24:45 john
47 * Removed the vecmat anonymous unions.
49 * Revision 1.79 1995/02/11 12:41:54 john
50 * Added new song method, with FM bank switching..
52 * Revision 1.78 1995/02/08 11:37:41 mike
53 * Check for failures in call to obj_create.
55 * Revision 1.77 1995/02/05 22:09:49 matt
56 * Switch out of rear view when starting endlevel sequence
58 * Revision 1.76 1995/01/30 18:08:28 rob
59 * Add palette fade out before ending level on special missions.
61 * Revision 1.75 1995/01/29 16:19:19 rob
62 * Fixed endlevel for custom missions.
64 * Revision 1.74 1995/01/26 12:18:10 rob
65 * Changed calling convention of network_do_frame.
67 * Revision 1.73 1995/01/21 16:50:03 matt
68 * Made endlevel work with new mission stuff
70 * Revision 1.72 1994/12/20 18:22:51 john
71 * Added code to support non-looping songs, and put
72 * it in for endlevel and credits.
74 * Revision 1.71 1994/12/15 12:23:58 matt
75 * Added check for failure to create camera object
77 * Revision 1.70 1994/12/15 03:05:28 matt
78 * Added error checking for NULL return from object_create_explosion()
80 * Revision 1.69 1994/12/12 21:41:38 matt
81 * Don't start endlevel if OF_SHOULD_BE_DEAD is set for player
83 * Revision 1.68 1994/12/12 15:44:54 rob
84 * Rolled back a change to endlevel_start that caused more bugs than
87 * Revision 1.67 1994/12/12 12:08:33 rob
88 * IF a player is dead upon entering the tunnel, make them not dead. Not perfect solution
89 * but avoids some last-minute weirdness we want to fix. This should be revisited in new
90 * versions if possible!
92 * Revision 1.66 1994/12/11 22:02:13 allender
93 * made endlevel data loading work with .txb encoded format (made with
94 * compbit -i level0?.end -o level0?.txb)
96 * Revision 1.65 1994/12/11 20:32:47 matt
97 * Made camera transition happen 1/3 of the way through exit tunnel
99 * Revision 1.64 1994/12/08 20:56:27 john
102 * Revision 1.63 1994/12/07 17:00:52 rob
103 * Trying to fix homing tone warning when in exit tunnel.
105 * Revision 1.62 1994/12/06 13:24:47 matt
106 * Made exit model come out of bitmaps.tbl
108 * Revision 1.61 1994/12/06 12:06:22 matt
109 * Fixed/cleaned up satellite (planet/sun) code
111 * Revision 1.60 1994/12/05 13:37:12 adam
114 * Revision 1.59 1994/12/05 12:49:37 matt
115 * Made satellite a rod (instead of a plane old non-rotating bitmap), and
116 * made the size settable in the .end file
118 * Revision 1.58 1994/12/04 21:40:00 matt
119 * Added explosion sounds
121 * Revision 1.57 1994/12/04 18:31:41 matt
122 * Wasn't coding planet position, causing it to disappear sometimes
124 * Revision 1.56 1994/12/04 14:30:26 john
125 * Added hooks for music..
127 * Revision 1.55 1994/12/04 13:53:52 matt
128 * Added code to make camera off-centered during lookback
130 * Revision 1.54 1994/12/04 12:30:18 matt
131 * Fixed slew for short sequence
133 * Revision 1.53 1994/12/03 19:28:10 matt
134 * Added alternate model for exit model after mine destruction
136 * Revision 1.52 1994/12/03 00:17:23 matt
137 * Made endlevel sequence cut off early
138 * Made exit model and bit explosion always plot last (after all terrain)
140 * Revision 1.51 1994/12/01 20:15:43 yuan
143 * Revision 1.50 1994/11/30 23:27:35 adam
144 * mucked around carelessly
146 * Revision 1.49 1994/11/28 21:50:37 mike
149 * Revision 1.48 1994/11/28 00:12:05 allender
150 * took out demo code that was in at one time to record endlevel sequence.
151 * We are _not_ recording endlevel sequence
153 * Revision 1.47 1994/11/27 23:35:54 allender
154 * pause demo recording when starting endlevel sequence. on demo playback,
155 * don't do endlevel at all.
157 * Revision 1.46 1994/11/27 23:13:59 matt
158 * Made changes for new mprintf calling convention
160 * Revision 1.45 1994/11/26 23:17:29 matt
161 * When camera leaves mine, bank it so it's level with the ground
163 * Revision 1.44 1994/11/23 16:52:13 rob
164 * Ended netgame endlevel sequence a bit earlier.
166 * Revision 1.43 1994/11/22 19:20:46 rob
167 * Modem support for secret levels.
169 * Revision 1.42 1994/11/22 12:11:03 rob
170 * Fixed bug - file handle left open in load_endlevel_data.
172 * Revision 1.41 1994/11/21 17:29:22 matt
173 * Cleaned up sequencing & game saving for secret levels
175 * Revision 1.40 1994/11/19 15:14:54 mike
176 * remove unused code and data
178 * Revision 1.39 1994/11/19 12:41:32 matt
179 * Added system to read endlevel data from file, and to make it work
180 * with any exit tunnel.
182 * Revision 1.38 1994/11/17 15:02:24 mike
183 * support new segment validation functions.
185 * Revision 1.37 1994/11/17 13:04:45 allender
186 * backout out newdemo changes
188 * Revision 1.35 1994/11/16 14:52:33 rob
189 * Commented out SLEW_ON on Matt's direction.
190 * Changed something to fix demo recording.
192 * Revision 1.34 1994/11/16 11:49:29 matt
193 * Added code to rotate terrain to match mine
195 * Revision 1.33 1994/11/14 17:54:54 allender
196 * on exit sequence during demo recording, force player exited from mine
197 * packet to all other network players
199 * Revision 1.32 1994/11/10 21:27:42 matt
202 * Revision 1.31 1994/11/10 14:02:24 matt
203 * Hacked in support for player ships with different textures
205 * Revision 1.30 1994/11/09 10:31:33 matt
206 * Don't create explosions if can't find seg to create them in
208 * Revision 1.29 1994/11/05 17:22:37 john
209 * Fixed lots of sequencing problems with newdemo stuff.
211 * Revision 1.28 1994/11/03 11:10:39 matt
212 * Fixed chase angles code
213 * Maybe other things, too.
215 * Revision 1.27 1994/10/30 20:09:21 matt
216 * For endlevel: added big explosion at tunnel exit; made lights in tunnel
217 * go out; made more explosions on walls.
219 * Revision 1.26 1994/10/28 16:37:50 allender
220 * stop demo recording when endlevel sequence activated
222 * Revision 1.25 1994/10/27 21:15:21 matt
223 * Added explosions in mine chasing player
225 * Revision 1.24 1994/10/27 01:03:57 matt
226 * Fixed several small bugs in flythrough
228 * Revision 1.23 1994/10/22 01:32:30 matt
229 * Don't start endlevel sequence if player dead
231 * Revision 1.22 1994/10/22 00:08:06 matt
232 * Fixed up problems with bonus & game sequencing
233 * Player doesn't get credit for hostages unless he gets them out alive
244 static char rcsid[] = "$Id: endlevel.c,v 1.17 2003-10-10 09:36:35 btb Exp $";
256 #include <ctype.h> // for isspace
272 #include "endlevel.h"
285 #include "fireball.h"
297 typedef struct flythrough_data {
299 vms_angvec angles; //orientation in angles
300 vms_vector step; //how far in a second
301 vms_vector angstep; //rotation per second
302 fix speed; //how fast object is moving
303 vms_vector headvec; //where we want to be pointing
304 int first_time; //flag for if first time through
305 fix offset_frac; //how far off-center as portion of way
306 fix offset_dist; //how far currently off-center
309 //endlevel sequence states
311 #define EL_OFF 0 //not in endlevel
312 #define EL_FLYTHROUGH 1 //auto-flythrough in tunnel
313 #define EL_LOOKBACK 2 //looking back at player
314 #define EL_OUTSIDE 3 //flying outside for a while
315 #define EL_STOPPED 4 //stopped, watching explosion
316 #define EL_PANNING 5 //panning around, watching player
317 #define EL_CHASING 6 //chasing player to station
319 #define SHORT_SEQUENCE 1 //if defined, end sequnce when panning starts
320 //#define STATION_ENABLED 1 //if defined, load & use space station model
322 int Endlevel_sequence = 0;
324 extern fix player_speed;
326 int transition_segnum,exit_segnum;
328 object *endlevel_camera;
330 #define FLY_SPEED i2f(50)
332 void do_endlevel_flythrough(int n);
334 int find_exit_side(object *obj);
335 void generate_starfield();
336 void start_endlevel_flythrough(int n,object *obj,fix speed);
337 void start_rendered_endlevel_sequence();
340 char movie_table[] = { 'a','a','a','a','d','d','d','d' };
342 char movie_table[] = { 'a','b','c',
354 #define N_MOVIES (sizeof(movie_table) / sizeof(*movie_table))
358 char movie_table_secret[] = {'a','d'};
360 char movie_table_secret[] = {'a','d','g','j','m','p'};
362 #define N_MOVIES_SECRET (sizeof(movie_table_secret) / sizeof(*movie_table_secret))
364 #define N_MOVIES_SECRET 0
368 #define FLY_ACCEL i2f(5)
370 fix cur_fly_speed,desired_fly_speed;
372 extern int matt_find_connect_side(int seg0,int seg1);
374 grs_bitmap *satellite_bitmap,*station_bitmap,*terrain_bitmap; //!!*exit_bitmap,
375 vms_vector satellite_pos,satellite_upvec;
376 //!!grs_bitmap **exit_bitmap_list[1];
377 int station_modelnum,exit_modelnum,destroyed_exit_modelnum;
379 vms_vector station_pos = {0xf8c4<<10,0x3c1c<<12,0x372<<10};
381 #ifdef STATION_ENABLED
382 grs_bitmap *station_bitmap;
383 grs_bitmap **station_bitmap_list[1];
384 int station_modelnum;
387 vms_vector mine_exit_point;
388 vms_vector mine_ground_exit_point;
389 vms_vector mine_side_exit_point;
390 vms_matrix mine_exit_orient;
394 grs_bitmap terrain_bm_instance;
395 grs_bitmap satellite_bm_instance;
397 //find delta between two angles
398 fixang delta_ang(fixang a,fixang b)
400 fixang delta0,delta1;
402 return (abs(delta0 = a - b) < abs(delta1 = b - a)) ? delta0 : delta1;
406 //return though which side of seg0 is seg1
407 int matt_find_connect_side(int seg0,int seg1)
409 segment *Seg=&Segments[seg0];
412 for (i=MAX_SIDES_PER_SEGMENT;i--;) if (Seg->children[i]==seg1) return i;
417 extern int Kmatrix_nomovie_message;
419 #if defined(D2_OEM) || defined(COMPILATION)
420 #define MOVIE_REQUIRED 0
422 #define MOVIE_REQUIRED 1
425 //returns movie played status. see movie.h
426 int start_endlevel_movie()
428 char movie_name[] = "esa.mve";
432 //Assert(Current_mission_num == Builtin_mission_num); //only play movie for built-in mission
434 //Assert(N_MOVIES >= Last_level);
435 //Assert(N_MOVIES_SECRET >= -Last_secret_level);
438 if (Current_level_num == Last_level)
439 return 1; //don't play movie
442 if (Current_level_num > 0)
443 movie_name[2] = movie_table[Current_level_num-1];
446 return 0; //no escapes for secret level
448 Error("Invalid level number <%d>",Current_level_num);
452 memcpy(save_pal,gr_palette,768);
455 r=PlayMovie(movie_name,(Game_mode & GM_MULTI)?0:MOVIE_REQUIRED);
457 return 0; // movie not played for shareware
460 if (Newdemo_state == ND_STATE_PLAYBACK) {
461 set_screen_mode(SCREEN_GAME);
462 memcpy(gr_palette,save_pal,768);
466 if (r==MOVIE_NOT_PLAYED && (Game_mode & GM_MULTI))
467 Kmatrix_nomovie_message=1;
469 Kmatrix_nomovie_message=0;
479 if (terrain_bm_instance.bm_data)
480 d_free(terrain_bm_instance.bm_data);
482 if (satellite_bm_instance.bm_data)
483 d_free(satellite_bm_instance.bm_data);
488 //##satellite_bitmap = bm_load("earth.bbm");
489 //##terrain_bitmap = bm_load("moon.bbm");
491 //##load_terrain("matt5b.bbm"); //load bitmap as height array
492 //##//load_terrain("ttest2.bbm"); //load bitmap as height array
494 #ifdef STATION_ENABLED
495 station_bitmap = bm_load("steel3.bbm");
496 station_bitmap_list[0] = &station_bitmap;
498 station_modelnum = load_polygon_model("station.pof",1,station_bitmap_list,NULL);
501 //!! exit_bitmap = bm_load("steel1.bbm");
502 //!! exit_bitmap_list[0] = &exit_bitmap;
504 //!! exit_modelnum = load_polygon_model("exit01.pof",1,exit_bitmap_list,NULL);
505 //!! destroyed_exit_modelnum = load_polygon_model("exit01d.pof",1,exit_bitmap_list,NULL);
507 generate_starfield();
509 atexit(free_endlevel_data);
511 terrain_bm_instance.bm_data = satellite_bm_instance.bm_data = NULL;
514 object external_explosion;
515 int ext_expl_playing,mine_destroyed;
517 extern fix flash_scale;
519 vms_angvec exit_angles={-0xa00,0,0};
521 vms_matrix surface_orient;
523 int endlevel_data_loaded=0;
524 extern char last_palette_loaded[];
526 void start_endlevel_sequence()
529 int movie_played = MOVIE_NOT_PLAYED;
532 if ((Mission_list[Current_mission_num].descent_version == 1
533 || Current_mission_num == Builtin_mission_num)
534 && Piggy_hamfile_version >= 3)
535 inited = load_exit_models();
539 if (Newdemo_state == ND_STATE_RECORDING) // stop demo recording
540 Newdemo_state = ND_STATE_PAUSED;
542 if (Newdemo_state == ND_STATE_PLAYBACK) { // don't do this if in playback mode
543 if (Current_mission_num == Builtin_mission_num) //only play movie for built-in mission
544 start_endlevel_movie();
545 strcpy(last_palette_loaded,""); //force palette load next time
549 if (Player_is_dead || ConsoleObject->flags&OF_SHOULD_BE_DEAD)
550 return; //don't start if dead!
552 // Dematerialize Buddy!
553 for (i=0; i<=Highest_object_index; i++)
554 if (Objects[i].type == OBJ_ROBOT)
555 if (Robot_info[Objects[i].id].companion) {
556 object_create_explosion(Objects[i].segnum, &Objects[i].pos, F1_0*7/2, VCLIP_POWERUP_DISAPPEARANCE );
557 Objects[i].flags |= OF_SHOULD_BE_DEAD;
560 Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
562 reset_rear_view(); //turn off rear view if set
565 if (Game_mode & GM_MULTI) {
566 multi_send_endlevel_start(0);
567 network_do_frame(1, 1);
571 if (Current_mission_num == Builtin_mission_num) {
572 // only play movie for built-in mission
573 if (!(Game_mode & GM_MULTI))
574 movie_played = start_endlevel_movie();
577 if (inited && endlevel_data_loaded && (movie_played == MOVIE_NOT_PLAYED)) {
578 //don't have movie. Do rendered sequence, if available
580 start_rendered_endlevel_sequence();
585 //don't have movie or rendered sequence, fade out
586 gr_palette_fade_out(gr_palette, 32, 0);
588 PlayerFinishedLevel(0); //done with level
591 static int cockpit_mode_save;
593 void start_rendered_endlevel_sequence()
595 int last_segnum,exit_side,tunnel_length;
598 int segnum,old_segnum,entry_side,i;
600 //count segments in exit tunnel
602 old_segnum = ConsoleObject->segnum;
603 exit_side = find_exit_side(ConsoleObject);
604 segnum = Segments[old_segnum].children[exit_side];
607 entry_side = matt_find_connect_side(segnum,old_segnum);
608 exit_side = Side_opposite[entry_side];
610 segnum = Segments[segnum].children[exit_side];
612 } while (segnum >= 0);
615 PlayerFinishedLevel(0); //don't do special sequence
619 last_segnum = old_segnum;
621 //now pick transition segnum 1/3 of the way in
623 old_segnum = ConsoleObject->segnum;
624 exit_side = find_exit_side(ConsoleObject);
625 segnum = Segments[old_segnum].children[exit_side];
629 entry_side = matt_find_connect_side(segnum,old_segnum);
630 exit_side = Side_opposite[entry_side];
632 segnum = Segments[segnum].children[exit_side];
634 transition_segnum = segnum;
638 cockpit_mode_save = Cockpit_mode;
641 if (Game_mode & GM_MULTI) {
642 multi_send_endlevel_start(0);
643 network_do_frame(1, 1);
648 Assert(last_segnum == exit_segnum);
649 // songs_play_song( SONG_ENDLEVEL, 0 ); // JTS: Until we get an exit song, just don't worry
652 Endlevel_sequence = EL_FLYTHROUGH;
654 ConsoleObject->movement_type = MT_NONE; //movement handled by flythrough
655 ConsoleObject->control_type = CT_NONE;
657 Game_suspended |= SUSP_ROBOTS; //robots don't move
659 cur_fly_speed = desired_fly_speed = FLY_SPEED;
661 start_endlevel_flythrough(0,ConsoleObject,cur_fly_speed); //initialize
663 HUD_init_message( TXT_EXIT_SEQUENCE );
665 outside_mine = ext_expl_playing = 0;
675 extern flythrough_data fly_objects[];
677 extern object *slew_obj;
679 vms_angvec player_angles,player_dest_angles;
680 vms_angvec camera_desired_angles,camera_cur_angles;
682 #define CHASE_TURN_RATE (0x4000/4) //max turn per second
684 //returns bitmask of which angles are at dest. bits 0,1,2 = p,b,h
685 int chase_angles(vms_angvec *cur_angles,vms_angvec *desired_angles)
687 vms_angvec delta_angs,alt_angles,alt_delta_angs;
688 fix total_delta,alt_total_delta;
692 delta_angs.p = desired_angles->p - cur_angles->p;
693 delta_angs.h = desired_angles->h - cur_angles->h;
694 delta_angs.b = desired_angles->b - cur_angles->b;
697 //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);
699 total_delta = abs(delta_angs.p) + abs(delta_angs.b) + abs(delta_angs.h);
701 alt_angles.p = f1_0/2 - cur_angles->p;
702 alt_angles.b = cur_angles->b + f1_0/2;
703 alt_angles.h = cur_angles->h + f1_0/2;
705 alt_delta_angs.p = desired_angles->p - alt_angles.p;
706 alt_delta_angs.h = desired_angles->h - alt_angles.h;
707 alt_delta_angs.b = desired_angles->b - alt_angles.b;
708 //alt_delta_angs.b = 0;
710 alt_total_delta = abs(alt_delta_angs.p) + abs(alt_delta_angs.b) + abs(alt_delta_angs.h);
712 //printf("Total delta = %x, alt total_delta = %x\n",total_delta,alt_total_delta);
714 if (alt_total_delta < total_delta) {
715 //mprintf((0,"FLIPPING ANGLES!\n"));
716 //printf("FLIPPING ANGLES!\n");
717 *cur_angles = alt_angles;
718 delta_angs = alt_delta_angs;
721 frame_turn = fixmul(FrameTime,CHASE_TURN_RATE);
723 if (abs(delta_angs.p) < frame_turn) {
724 cur_angles->p = desired_angles->p;
728 if (delta_angs.p > 0)
729 cur_angles->p += frame_turn;
731 cur_angles->p -= frame_turn;
733 if (abs(delta_angs.b) < frame_turn) {
734 cur_angles->b = desired_angles->b;
738 if (delta_angs.b > 0)
739 cur_angles->b += frame_turn;
741 cur_angles->b -= frame_turn;
744 if (abs(delta_angs.h) < frame_turn) {
745 cur_angles->h = desired_angles->h;
749 if (delta_angs.h > 0)
750 cur_angles->h += frame_turn;
752 cur_angles->h -= frame_turn;
757 void stop_endlevel_sequence()
759 Interpolation_method = 0;
761 gr_palette_fade_out(gr_palette, 32, 0);
763 select_cockpit(cockpit_mode_save);
765 Endlevel_sequence = EL_OFF;
767 PlayerFinishedLevel(0);
771 #define VCLIP_BIG_PLAYER_EXPLOSION 58
773 //--unused-- vms_vector upvec = {0,f1_0,0};
775 //find the angle between the player's heading & the station
776 void get_angs_to_object(vms_angvec *av,vms_vector *targ_pos,vms_vector *cur_pos)
780 vm_vec_sub(&tv,targ_pos,cur_pos);
782 vm_extract_angles_vector(av,&tv);
785 void do_endlevel_frame()
788 static fix bank_rate;
789 vms_vector save_last_pos;
790 static fix explosion_wait1=0;
791 static fix explosion_wait2=0;
792 static fix ext_expl_halflife;
794 save_last_pos = ConsoleObject->last_pos; //don't let move code change this
796 ConsoleObject->last_pos = save_last_pos;
798 if (ext_expl_playing) {
800 external_explosion.lifeleft -= FrameTime;
801 do_explosion_sequence(&external_explosion);
803 if (external_explosion.lifeleft < ext_expl_halflife)
806 if (external_explosion.flags & OF_SHOULD_BE_DEAD)
807 ext_expl_playing = 0;
810 if (cur_fly_speed != desired_fly_speed) {
811 fix delta = desired_fly_speed - cur_fly_speed;
812 fix frame_accel = fixmul(FrameTime,FLY_ACCEL);
814 if (abs(delta) < frame_accel)
815 cur_fly_speed = desired_fly_speed;
818 cur_fly_speed += frame_accel;
820 cur_fly_speed -= frame_accel;
826 if (Endlevel_sequence==EL_OUTSIDE) {
829 vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point);
831 if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) {
836 tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION);
839 external_explosion = *tobj;
841 tobj->flags |= OF_SHOULD_BE_DEAD;
843 flash_scale = 0; //kill lights in mine
845 ext_expl_halflife = tobj->lifeleft;
847 ext_expl_playing = 1;
850 digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 );
854 //do explosions chasing player
855 if ((explosion_wait1-=FrameTime) < 0) {
859 static int sound_count;
861 vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5);
862 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-RAND_MAX/2)*15);
863 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-RAND_MAX/2)*15);
865 segnum = find_point_seg(&tpnt,ConsoleObject->segnum);
868 expl = object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION);
869 if (d_rand()<10000 || ++sound_count==7) { //pseudo-random
870 digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 );
875 explosion_wait1 = 0x2000 + d_rand()/4;
880 //do little explosions on walls
881 if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE)
882 if ((explosion_wait2-=FrameTime) < 0) {
887 //create little explosion on wall
889 vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(d_rand()-RAND_MAX/2)*100);
890 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(d_rand()-RAND_MAX/2)*100);
891 vm_vec_add2(&tpnt,&ConsoleObject->pos);
893 if (Endlevel_sequence == EL_FLYTHROUGH)
894 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*200);
896 vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,d_rand()*60);
898 //find hit point on wall
900 fq.p0 = &ConsoleObject->pos;
902 fq.startseg = ConsoleObject->segnum;
905 fq.ignore_obj_list = NULL;
908 find_vector_intersection(&fq,&hit_data);
910 if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1)
911 object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+d_rand()*6,VCLIP_SMALL_EXPLOSION);
913 explosion_wait2 = (0xa00 + d_rand()/8)/2;
916 switch (Endlevel_sequence) {
920 case EL_FLYTHROUGH: {
922 do_endlevel_flythrough(0);
924 if (ConsoleObject->segnum == transition_segnum) {
926 if ((Current_mission_num == Builtin_mission_num) &&
927 (start_endlevel_movie() != MOVIE_NOT_PLAYED))
928 stop_endlevel_sequence();
932 //songs_play_song( SONG_ENDLEVEL, 0 );
934 Endlevel_sequence = EL_LOOKBACK;
936 objnum = obj_create(OBJ_CAMERA, 0,
937 ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0,
938 CT_NONE,MT_NONE,RT_NONE);
940 if (objnum == -1) { //can't get object, so abort
941 mprintf((1, "Can't get object for endlevel sequence. Aborting endlevel sequence.\n"));
942 stop_endlevel_sequence();
946 Viewer = endlevel_camera = &Objects[objnum];
948 select_cockpit(CM_LETTERBOX);
950 fly_objects[1] = fly_objects[0];
951 fly_objects[1].obj = endlevel_camera;
952 fly_objects[1].speed = (5*cur_fly_speed)/4;
953 fly_objects[1].offset_frac = 0x4000;
955 vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7));
968 do_endlevel_flythrough(0);
969 do_endlevel_flythrough(1);
975 if (timer < 0) //reduce speed
976 fly_objects[1].speed = fly_objects[0].speed;
979 if (endlevel_camera->segnum == exit_segnum) {
980 vms_angvec cam_angles,exit_seg_angles;
982 Endlevel_sequence = EL_OUTSIDE;
986 vm_vec_negate(&endlevel_camera->orient.fvec);
987 vm_vec_negate(&endlevel_camera->orient.rvec);
989 vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
990 vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient);
991 bank_rate = (-exit_seg_angles.b - cam_angles.b)/2;
993 ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE;
996 slew_obj = endlevel_camera;
1005 vms_angvec cam_angles;
1008 vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
1010 vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed));
1011 vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10));
1013 vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
1014 cam_angles.b += fixmul(bank_rate,FrameTime);
1015 vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles);
1022 Endlevel_sequence = EL_STOPPED;
1024 vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient);
1035 get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
1036 chase_angles(&player_angles,&player_dest_angles);
1037 vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
1039 vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
1046 slew_obj = endlevel_camera;
1047 _do_slew_movement(endlevel_camera,1,1);
1048 timer += FrameTime; //make time stop
1052 #ifdef SHORT_SEQUENCE
1054 stop_endlevel_sequence();
1057 Endlevel_sequence = EL_PANNING;
1059 vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient);
1064 if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer
1065 stop_endlevel_sequence();
1069 //mprintf((0,"Switching to pan...\n"));
1070 #endif //SHORT_SEQUENCE
1077 #ifndef SHORT_SEQUENCE
1083 get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
1084 chase_angles(&player_angles,&player_dest_angles);
1085 vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
1086 vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
1089 _do_slew_movement(endlevel_camera,1,1);
1092 get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
1093 mask = chase_angles(&camera_cur_angles,&camera_desired_angles);
1094 vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);
1096 if ((mask&5) == 5) {
1100 Endlevel_sequence = EL_CHASING;
1102 vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos);
1103 vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL);
1105 desired_fly_speed *= 2;
1107 //mprintf((0,"Switching to chase...\n"));
1119 _do_slew_movement(endlevel_camera,1,1);
1122 get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
1123 chase_angles(&camera_cur_angles,&camera_desired_angles);
1126 vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);
1129 d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos);
1131 speed_scale = fixdiv(d,i2f(0x20));
1134 get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
1135 chase_angles(&player_angles,&player_dest_angles);
1136 vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
1138 vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
1140 vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed)));
1142 if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10))
1143 stop_endlevel_sequence();
1149 #endif //ifdef SHORT_SEQUENCE
1157 //find which side to fly out of
1158 int find_exit_side(object *obj)
1161 vms_vector prefvec,segcenter,sidevec;
1164 segment *pseg = &Segments[obj->segnum];
1168 vm_vec_normalized_dir_quick(&prefvec,&obj->pos,&obj->last_pos);
1170 compute_segment_center(&segcenter,pseg);
1173 for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) {
1176 if (pseg->children[i]!=-1) {
1178 compute_center_point_on_side(&sidevec,pseg,i);
1179 vm_vec_normalized_dir_quick(&sidevec,&sidevec,&segcenter);
1180 d = vm_vec_dotprod(&sidevec,&prefvec);
1182 if (labs(d) < MIN_D) d=0;
1184 if (d > best_val) {best_val=d; best_side=i;}
1189 Assert(best_side!=-1);
1194 extern fix Render_zoom; //the player's zoom factor
1196 extern vms_vector Viewer_eye; //valid during render
1198 void draw_exit_model()
1200 vms_vector model_pos;
1203 vm_vec_scale_add(&model_pos,&mine_exit_point,&mine_exit_orient.fvec,i2f(f));
1204 vm_vec_scale_add2(&model_pos,&mine_exit_orient.uvec,i2f(u));
1206 draw_polygon_model(&model_pos,&mine_exit_orient,NULL,(mine_destroyed)?destroyed_exit_modelnum:exit_modelnum,0,f1_0,NULL,NULL);
1210 int exit_point_bmx,exit_point_bmy;
1212 fix satellite_size = i2f(400);
1214 #define SATELLITE_DIST i2f(1024)
1215 #define SATELLITE_WIDTH satellite_size
1216 #define SATELLITE_HEIGHT ((satellite_size*9)/4) //((satellite_size*5)/2)
1218 void render_external_scene(fix eye_offset)
1221 Viewer_eye = Viewer->pos;
1224 vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
1226 g3_set_view_matrix(&Viewer->pos,&Viewer->orient,Render_zoom);
1228 //g3_draw_horizon(BM_XRGB(0,0,0),BM_XRGB(16,16,16)); //,-1);
1229 gr_clear_canvas(BM_XRGB(0,0,0));
1231 g3_start_instance_matrix(&vmd_zero_vector,&surface_orient);
1238 g3s_point p,top_pnt;
1240 g3_rotate_point(&p,&satellite_pos);
1241 g3_rotate_delta_vec(&delta,&satellite_upvec);
1243 g3_add_delta_vec(&top_pnt,&p,&delta);
1245 if (! (p.p3_codes & CC_BEHIND)) {
1246 int save_im = Interpolation_method;
1247 //p.p3_flags &= ~PF_PROJECTED;
1248 //g3_project_point(&p);
1249 if (! (p.p3_flags & PF_OVERFLOW)) {
1250 Interpolation_method = 0;
1251 //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap);
1252 g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,f1_0);
1253 Interpolation_method = save_im;
1258 #ifdef STATION_ENABLED
1259 draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,f1_0,NULL,NULL);
1262 render_terrain(&mine_ground_exit_point,exit_point_bmx,exit_point_bmy);
1265 if (ext_expl_playing)
1266 draw_fireball(&external_explosion);
1269 render_object(ConsoleObject);
1273 #define MAX_STARS 500
1275 vms_vector stars[MAX_STARS];
1277 void generate_starfield()
1281 for (i=0;i<MAX_STARS;i++) {
1283 stars[i].x = (d_rand() - RAND_MAX/2) << 14;
1284 stars[i].z = (d_rand() - RAND_MAX/2) << 14;
1285 stars[i].y = (d_rand()/2) << 14;
1296 for (i=0;i<MAX_STARS;i++) {
1299 gr_setcolor(BM_XRGB(intensity,intensity,intensity));
1303 //g3_rotate_point(&p,&stars[i]);
1304 g3_rotate_delta_vec(&p.p3_vec,&stars[i]);
1307 if (p.p3_codes == 0) {
1309 p.p3_flags &= ~PF_PROJECTED;
1311 g3_project_point(&p);
1313 gr_pixel(f2i(p.p3_sx),f2i(p.p3_sy));
1318 //@@ vms_vector delta;
1319 //@@ g3s_point top_pnt;
1321 //@@ g3_rotate_point(&p,&satellite_pos);
1322 //@@ g3_rotate_delta_vec(&delta,&satellite_upvec);
1324 //@@ g3_add_delta_vec(&top_pnt,&p,&delta);
1326 //@@ if (! (p.p3_codes & CC_BEHIND)) {
1327 //@@ int save_im = Interpolation_method;
1328 //@@ Interpolation_method = 0;
1329 //@@ //p.p3_flags &= ~PF_PROJECTED;
1330 //@@ g3_project_point(&p);
1331 //@@ if (! (p.p3_flags & PF_OVERFLOW))
1332 //@@ //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap);
1333 //@@ g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,f1_0);
1334 //@@ Interpolation_method = save_im;
1340 void endlevel_render_mine(fix eye_offset)
1344 Viewer_eye = Viewer->pos;
1346 if (Viewer->type == OBJ_PLAYER )
1347 vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.fvec,(Viewer->size*3)/4);
1350 vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset);
1353 if (Function_mode==FMODE_EDITOR)
1354 Viewer_eye = Viewer->pos;
1357 if (Endlevel_sequence >= EL_OUTSIDE) {
1359 start_seg_num = exit_segnum;
1362 start_seg_num = find_point_seg(&Viewer_eye,Viewer->segnum);
1364 if (start_seg_num==-1)
1365 start_seg_num = Viewer->segnum;
1368 if (Endlevel_sequence == EL_LOOKBACK) {
1369 vms_matrix headm,viewm;
1370 vms_angvec angles = {0,0,0x7fff};
1372 vm_angles_2_matrix(&headm,&angles);
1373 vm_matrix_x_matrix(&viewm,&Viewer->orient,&headm);
1374 g3_set_view_matrix(&Viewer_eye,&viewm,Render_zoom);
1377 g3_set_view_matrix(&Viewer_eye,&Viewer->orient,Render_zoom);
1379 render_mine(start_seg_num,eye_offset, 0);
1382 void render_endlevel_frame(fix eye_offset)
1387 if (Endlevel_sequence < EL_OUTSIDE)
1388 endlevel_render_mine(eye_offset);
1390 render_external_scene(eye_offset);
1397 ///////////////////////// copy of flythrough code for endlevel
1400 #define MAX_FLY_OBJECTS 2
1402 flythrough_data fly_objects[MAX_FLY_OBJECTS];
1404 flythrough_data *flydata;
1406 int matt_find_connect_side(int seg0,int seg1);
1408 void compute_segment_center(vms_vector *vp,segment *sp);
1410 fixang delta_ang(fixang a,fixang b);
1411 fixang interp_angle(fixang dest,fixang src,fixang step);
1413 #define DEFAULT_SPEED i2f(16)
1417 //if speed is zero, use default speed
1418 void start_endlevel_flythrough(int n,object *obj,fix speed)
1420 flydata = &fly_objects[n];
1424 flydata->first_time = 1;
1426 flydata->speed = speed?speed:DEFAULT_SPEED;
1428 flydata->offset_frac = 0;
1431 static vms_angvec *angvec_add2_scale(vms_angvec *dest,vms_vector *src,fix s)
1433 dest->p += fixmul(src->x,s);
1434 dest->b += fixmul(src->z,s);
1435 dest->h += fixmul(src->y,s);
1440 #define MAX_ANGSTEP 0x4000 //max turn per second
1442 #define MAX_SLIDE_PER_SEGMENT 0x10000
1444 void do_endlevel_flythrough(int n)
1450 flydata = &fly_objects[n];
1453 old_player_seg = obj->segnum;
1455 //move the player for this frame
1457 if (!flydata->first_time) {
1459 vm_vec_scale_add2(&obj->pos,&flydata->step,FrameTime);
1460 angvec_add2_scale(&flydata->angles,&flydata->angstep,FrameTime);
1462 vm_angles_2_matrix(&obj->orient,&flydata->angles);
1465 //check new player seg
1467 update_object_seg(obj);
1468 pseg = &Segments[obj->segnum];
1470 if (flydata->first_time || obj->segnum != old_player_seg) { //moved into new seg
1471 vms_vector curcenter,nextcenter;
1472 fix step_size,seg_time;
1473 short entry_side,exit_side = -1;//what sides we entry and leave through
1474 vms_vector dest_point; //where we are heading (center of exit_side)
1475 vms_angvec dest_angles; //where we want to be pointing
1476 vms_matrix dest_orient;
1481 //find new exit side
1483 if (!flydata->first_time) {
1485 entry_side = matt_find_connect_side(obj->segnum,old_player_seg);
1486 exit_side = Side_opposite[entry_side];
1489 if (flydata->first_time || entry_side==-1 || pseg->children[exit_side]==-1)
1490 exit_side = find_exit_side(obj);
1492 { //find closest side to align to
1493 fix d,largest_d=-f1_0;
1499 get_side_normal(pseg, i, 0, &v1 );
1500 d = vm_vec_dot(&v1,&flydata->obj->orient.uvec);
1502 d = vm_vec_dot(&pseg->sides[i].normals[0],&flydata->obj->orient.uvec);
1504 if (d > largest_d) {largest_d = d; up_side=i;}
1509 //update target point & angles
1511 compute_center_point_on_side(&dest_point,pseg,exit_side);
1513 //update target point and movement points
1515 //offset object sideways
1516 if (flydata->offset_frac) {
1522 if (i!=entry_side && i!=exit_side && i!=up_side && i!=Side_opposite[up_side])
1530 compute_center_point_on_side(&s0p,pseg,s0);
1531 compute_center_point_on_side(&s1p,pseg,s1);
1532 dist = fixmul(vm_vec_dist(&s0p,&s1p),flydata->offset_frac);
1534 if (dist-flydata->offset_dist > MAX_SLIDE_PER_SEGMENT)
1535 dist = flydata->offset_dist + MAX_SLIDE_PER_SEGMENT;
1537 flydata->offset_dist = dist;
1539 vm_vec_scale_add2(&dest_point,&obj->orient.rvec,dist);
1543 vm_vec_sub(&flydata->step,&dest_point,&obj->pos);
1544 step_size = vm_vec_normalize_quick(&flydata->step);
1545 vm_vec_scale(&flydata->step,flydata->speed);
1547 compute_segment_center(&curcenter,pseg);
1548 compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]);
1549 vm_vec_sub(&flydata->headvec,&nextcenter,&curcenter);
1554 get_side_normal(pseg, up_side, 0, &_v1 );
1555 vm_vector_2_matrix(&dest_orient,&flydata->headvec,&_v1,NULL);
1558 vm_vector_2_matrix(&dest_orient,&flydata->headvec,&pseg->sides[up_side].normals[0],NULL);
1560 vm_extract_angles_matrix(&dest_angles,&dest_orient);
1562 if (flydata->first_time)
1563 vm_extract_angles_matrix(&flydata->angles,&obj->orient);
1565 seg_time = fixdiv(step_size,flydata->speed); //how long through seg
1568 flydata->angstep.x = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.p,dest_angles.p),seg_time)));
1569 flydata->angstep.z = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.b,dest_angles.b),seg_time)));
1570 flydata->angstep.y = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.h,dest_angles.h),seg_time)));
1574 flydata->angles = dest_angles;
1575 flydata->angstep.x = flydata->angstep.y = flydata->angstep.z = 0;
1579 flydata->first_time=0;
1583 #define ROT_SPEED 8 //rate of rotation while key held down
1584 #define VEL_SPEED (15) //rate of acceleration while key held down
1586 extern short old_joy_x,old_joy_y; //position last time around
1591 #ifdef SLEW_ON //this is a special routine for slewing around external scene
1592 int _do_slew_movement(object *obj, int check_keys, int check_joy )
1595 vms_vector svel, movement; //scaled velocity (per this frame)
1596 vms_matrix rotmat,new_pm;
1597 int joy_x,joy_y,btns;
1598 int joyx_moved,joyy_moved;
1601 if (keyd_pressed[KEY_PAD5])
1602 vm_vec_zero(&obj->phys_info.velocity);
1605 obj->phys_info.velocity.x += VEL_SPEED * (key_down_time(KEY_PAD9) - key_down_time(KEY_PAD7));
1606 obj->phys_info.velocity.y += VEL_SPEED * (key_down_time(KEY_PADMINUS) - key_down_time(KEY_PADPLUS));
1607 obj->phys_info.velocity.z += VEL_SPEED * (key_down_time(KEY_PAD8) - key_down_time(KEY_PAD2));
1609 rotang.pitch = (key_down_time(KEY_LBRACKET) - key_down_time(KEY_RBRACKET))/ROT_SPEED;
1610 rotang.bank = (key_down_time(KEY_PAD1) - key_down_time(KEY_PAD3))/ROT_SPEED;
1611 rotang.head = (key_down_time(KEY_PAD6) - key_down_time(KEY_PAD4))/ROT_SPEED;
1614 rotang.pitch = rotang.bank = rotang.head = 0;
1616 //check for joystick movement
1618 if (check_joy && joy_present) {
1619 joy_get_pos(&joy_x,&joy_y);
1620 btns=joy_get_btns();
1622 joyx_moved = (abs(joy_x - old_joy_x)>JOY_NULL);
1623 joyy_moved = (abs(joy_y - old_joy_y)>JOY_NULL);
1625 if (abs(joy_x) < JOY_NULL) joy_x = 0;
1626 if (abs(joy_y) < JOY_NULL) joy_y = 0;
1629 if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 512,FrameTime); else;
1631 if (joyy_moved) obj->phys_info.velocity.z = -joy_y * 8192;
1633 if (!rotang.head) rotang.head = fixmul(joy_x * 512,FrameTime);
1635 if (joyx_moved) old_joy_x = joy_x;
1636 if (joyy_moved) old_joy_y = joy_y;
1639 moved = rotang.pitch | rotang.bank | rotang.head;
1641 vm_angles_2_matrix(&rotmat,&rotang);
1642 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
1643 obj->orient = new_pm;
1644 vm_transpose_matrix(&new_pm); //make those columns rows
1646 moved |= obj->phys_info.velocity.x | obj->phys_info.velocity.y | obj->phys_info.velocity.z;
1648 svel = obj->phys_info.velocity;
1649 vm_vec_scale(&svel,FrameTime); //movement in this frame
1650 vm_vec_rotate(&movement,&svel,&new_pm);
1652 vm_vec_add2(&obj->pos,&movement);
1654 moved |= (movement.x || movement.y || movement.z);
1663 #define STATION_DIST i2f(1024)
1665 int convert_ext( char *dest, char *ext )
1669 t = strchr(dest,'.');
1671 if (t && (t-dest <= 8)) {
1681 //called for each level to load & setup the exit sequence
1682 void load_endlevel_data(int level_num)
1685 char line[LINE_LEN],*p;
1687 int var,segnum,sidenum;
1689 int have_binary = 0;
1691 endlevel_data_loaded = 0; //not loaded yet
1696 if (level_num<0) //secret level
1697 strcpy(filename,Secret_level_names[-level_num-1]);
1699 strcpy(filename,Level_names[level_num-1]);
1701 if (!convert_ext(filename,"END"))
1702 Error("Error converting filename <%s> for endlevel data\n",filename);
1704 ifile = cfopen(filename,"rb");
1708 convert_ext(filename,"txb");
1710 ifile = cfopen(filename,"rb");
1714 con_printf(CON_DEBUG, "Cannot load file text of binary version of <%s>\n",filename);
1715 endlevel_data_loaded = 0; // won't be able to play endlevel sequence
1727 //ok...this parser is pretty simple. It ignores comments, but
1728 //everything else must be in the right place
1732 while (cfgets(line,LINE_LEN,ifile)) {
1735 for (i = 0; i < strlen(line) - 1; i++) {
1736 encode_rotate_left(&(line[i]));
1737 line[i] = line[i] ^ BITMAP_TBL_XOR;
1738 encode_rotate_left(&(line[i]));
1743 if ((p=strchr(line,';'))!=NULL)
1744 *p = 0; //cut off comment
1746 for (p=line+strlen(line)-1;p>line && isspace(*p);*p--=0);
1747 for (p=line;isspace(*p);p++);
1749 if (!*p) //empty line
1754 case 0: { //ground terrain
1758 if (terrain_bm_instance.bm_data)
1759 d_free(terrain_bm_instance.bm_data);
1761 Assert(terrain_bm_instance.bm_data == NULL);
1763 iff_error = iff_read_bitmap(p,&terrain_bm_instance,BM_LINEAR,pal);
1764 if (iff_error != IFF_NO_ERROR) {
1765 Warning("Can't load exit terrain from file %s: IFF error: %s",
1766 p, iff_errormsg(iff_error));
1767 endlevel_data_loaded = 0; // won't be able to play endlevel sequence
1771 terrain_bitmap = &terrain_bm_instance;
1773 gr_remap_bitmap_good( terrain_bitmap, pal, iff_transparent_color, -1);
1778 case 1: //height map
1786 sscanf(p,"%d,%d",&exit_point_bmx,&exit_point_bmy);
1789 case 3: //exit heading
1791 exit_angles.h = i2f(atoi(p))/360;
1794 case 4: { //planet bitmap
1798 if (satellite_bm_instance.bm_data)
1799 d_free(satellite_bm_instance.bm_data);
1801 iff_error = iff_read_bitmap(p,&satellite_bm_instance,BM_LINEAR,pal);
1802 if (iff_error != IFF_NO_ERROR) {
1803 Warning("Can't load exit satellite from file %s: IFF error: %s",
1804 p, iff_errormsg(iff_error));
1805 endlevel_data_loaded = 0; // won't be able to play endlevel sequence
1809 satellite_bitmap = &satellite_bm_instance;
1810 gr_remap_bitmap_good( satellite_bitmap, pal, iff_transparent_color, -1);
1816 case 7: { //station pos
1821 sscanf(p,"%d,%d",&head,&pitch);
1823 ta.h = i2f(head)/360;
1824 ta.p = -i2f(pitch)/360;
1827 vm_angles_2_matrix(&tm,&ta);
1830 satellite_pos = tm.fvec;
1831 //vm_vec_copy_scale(&satellite_pos,&tm.fvec,SATELLITE_DIST);
1833 station_pos = tm.fvec;
1838 case 6: //planet size
1839 satellite_size = i2f(atoi(p));
1847 Assert(var == NUM_VARS);
1850 // OK, now the data is loaded. Initialize everything
1852 //find the exit sequence by searching all segments for a side with
1855 for (segnum=0,exit_segnum=-1;exit_segnum==-1 && segnum<=Highest_segment_index;segnum++)
1856 for (sidenum=0;sidenum<6;sidenum++)
1857 if (Segments[segnum].children[sidenum] == -2) {
1858 exit_segnum = segnum;
1859 exit_side = sidenum;
1863 Assert(exit_segnum!=-1);
1865 compute_segment_center(&mine_exit_point,&Segments[exit_segnum]);
1866 extract_orient_from_segment(&mine_exit_orient,&Segments[exit_segnum]);
1867 compute_center_point_on_side(&mine_side_exit_point,&Segments[exit_segnum],exit_side);
1869 vm_vec_scale_add(&mine_ground_exit_point,&mine_exit_point,&mine_exit_orient.uvec,-i2f(20));
1871 //compute orientation of surface
1874 vms_matrix exit_orient,tm;
1876 vm_angles_2_matrix(&exit_orient,&exit_angles);
1877 vm_transpose_matrix(&exit_orient);
1878 vm_matrix_x_matrix(&surface_orient,&mine_exit_orient,&exit_orient);
1880 vm_copy_transpose_matrix(&tm,&surface_orient);
1881 vm_vec_rotate(&tv,&station_pos,&tm);
1882 vm_vec_scale_add(&station_pos,&mine_exit_point,&tv,STATION_DIST);
1884 vm_vec_rotate(&tv,&satellite_pos,&tm);
1885 vm_vec_scale_add(&satellite_pos,&mine_exit_point,&tv,SATELLITE_DIST);
1887 vm_vector_2_matrix(&tm,&tv,&surface_orient.uvec,NULL);
1888 vm_vec_copy_scale(&satellite_upvec,&tm.uvec,SATELLITE_HEIGHT);
1895 endlevel_data_loaded = 1;