]> icculus.org git repositories - taylor/freespace2.git/blob - src/starfield/supernova.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / starfield / supernova.cpp
1 /*
2  * $Logfile: /Freespace2/code/Starfield/Supernova.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Include file for nebula stuff
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:52  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:10  root
14  * Initial import.
15  *
16  * 
17  * 5     9/09/99 11:40p Dave
18  * Handle an Assert() in beam code. Added supernova sounds. Play the right
19  * 2 end movies properly, based upon what the player did in the mission.
20  * 
21  * 4     9/03/99 1:32a Dave
22  * CD checking by act. Added support to play 2 cutscenes in a row
23  * seamlessly. Fixed super low level cfile bug related to files in the
24  * root directory of a CD. Added cheat code to set campaign mission # in
25  * main hall.
26  * 
27  * 3     7/31/99 4:15p Dave
28  * Fixed supernova particle velocities. Handle OBJ_NONE in target
29  * monitoring view. Properly use objectives notify gauge colors.
30  * 
31  * 2     7/21/99 8:10p Dave
32  * First run of supernova effect.
33  *  
34  *
35  * $NoKeywords: $
36  */
37
38 #include "freespace.h"
39 #include "vecmat.h"
40 #include "object.h"
41 #include "lighting.h"
42 #include "starfield.h"
43 #include "supernova.h"
44 #include "particle.h"
45 #include "ship.h"
46 #include "timer.h"
47 #include "model.h"
48 #include "popupdead.h"
49 #include "key.h"
50 #include "missioncampaign.h"
51 #include "gamesequence.h"
52 #include "gamesnd.h"
53 #include "sound.h"
54
55
56 // --------------------------------------------------------------------------------------------------------------------------
57 // SUPERNOVA DEFINES/VARS
58 //
59
60 // supernova time 1
61 #define SUPERNOVA_SOUND_1_TIME                                  15.0f
62 #define SUPERNOVA_SOUND_2_TIME                                  5.0f
63 int Supernova_sound_1_played = 0;
64 int Supernova_sound_2_played = 0;
65
66 // countdown for supernova
67 float Supernova_time_total = -1.0f;
68 float Supernova_time = -1.0f;
69 int Supernova_finished = 0;
70 int Supernova_popup = 0;
71 float Supernova_fade_to_white = 0.0f;
72 int Supernova_particle_stamp = -1;
73
74 // supernova camera pos
75 vector Supernova_camera_pos;
76 matrix Supernova_camera_orient;
77
78 int Supernova_status = SUPERNOVA_NONE;
79
80 // --------------------------------------------------------------------------------------------------------------------------
81 // SUPERNOVA FUNCTIONS
82 //
83
84 // level init
85 void supernova_level_init()
86 {
87         Supernova_time_total = -1.0f;
88         Supernova_time = -1.0f; 
89         Supernova_finished = 0;
90         Supernova_fade_to_white = 0.0f;
91         Supernova_popup = 0;
92         Supernova_particle_stamp = -1;
93
94         Supernova_sound_1_played = 0;
95         Supernova_sound_2_played = 0;
96
97         Supernova_status = SUPERNOVA_NONE;
98 }
99
100 // start a supernova
101 void supernova_start(int seconds)
102 {
103         // bogus time
104         if((float)seconds < SUPERNOVA_CUT_TIME){
105                 return;
106         }
107
108         // no supernova in multiplayer
109         if(Game_mode & GM_MULTIPLAYER){
110                 return;
111         }
112
113         // only good if we have one sun
114         if(Num_suns != 1){
115                 return;
116         }
117         
118         Supernova_time_total = (float)seconds;
119         Supernova_time = (float)seconds;
120         Supernova_finished = 0;
121         Supernova_fade_to_white = 0.0f;
122         Supernova_popup = 0;
123         Supernova_particle_stamp = -1;
124
125         Supernova_status = SUPERNOVA_STARTED;   
126 }
127
128 int sn_particles = 100;
129 DCF(sn_part, "")
130 {
131         dc_get_arg(ARG_INT);
132         sn_particles = Dc_arg_int;
133 }
134 void supernova_do_particles()
135 {       
136         int idx;
137         vector a, b, ta, tb;
138         vector norm, sun_temp;
139
140         // no player ship
141         if((Player_obj == NULL) || (Player_ship == NULL)){
142                 return;
143         }
144
145         // timestamp
146         if((Supernova_particle_stamp == -1) || timestamp_elapsed(Supernova_particle_stamp)){
147                 Supernova_particle_stamp = timestamp(sn_particles);
148
149                 // get particle norm            
150                 stars_get_sun_pos(0, &sun_temp);
151                 vm_vec_add2(&sun_temp, &Player_obj->pos);
152                 vm_vec_sub(&norm, &Player_obj->pos, &sun_temp);
153                 vm_vec_normalize(&norm);
154
155                 particle_emitter whee;
156                 whee.max_life = 1.0f;
157                 whee.min_life = 0.6f;
158                 whee.max_vel = 50.0f;
159                 whee.min_vel = 25.0f;
160                 whee.normal_variance = 0.75f;
161                 whee.num_high = 5;
162                 whee.num_low = 2;
163                 whee.min_rad = 0.5f;
164                 whee.max_rad = 1.25f;           
165
166                 // emit
167                 for(idx=0; idx<10; idx++){                      
168                         submodel_get_two_random_points(Player_ship->modelnum, 0, &ta, &tb);
169
170                         // rotate into world space
171                         vm_vec_unrotate(&a, &ta, &Player_obj->orient);                  
172                         vm_vec_add2(&a, &Player_obj->pos);                      
173                         whee.pos = a;
174                         whee.vel = norm;
175                         vm_vec_scale(&whee.vel, 30.0f);                                         
176                         vm_vec_add2(&whee.vel, &Player_obj->phys_info.vel);                     
177                         whee.normal = norm;                     
178                         particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
179
180                         vm_vec_unrotate(&b, &tb, &Player_obj->orient);
181                         vm_vec_add2(&b, &Player_obj->pos);
182                         whee.pos = b;                   
183                         particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
184                 }
185         }
186 }
187
188 // call once per frame
189 float sn_shudder = 0.45f;
190 DCF(sn_shud, "")
191 {
192         dc_get_arg(ARG_FLOAT);
193         sn_shudder = Dc_arg_float;
194 }
195
196 void supernova_process()
197 {       
198         int sn_stage;   
199
200         // if the supernova is running
201         sn_stage = supernova_active();
202         if(sn_stage){
203                 Supernova_time -= flFrametime;
204
205                 // sound stuff
206                 if((Supernova_time <= SUPERNOVA_SOUND_1_TIME) && !Supernova_sound_1_played){
207                         Supernova_sound_1_played = 1;
208                         snd_play(&Snds[SND_SUPERNOVA_1], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
209                 }
210                 if((Supernova_time <= SUPERNOVA_SOUND_2_TIME) && !Supernova_sound_2_played){
211                         Supernova_sound_2_played = 1;
212                         snd_play(&Snds[SND_SUPERNOVA_2], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
213                 }
214
215                 // if we've crossed from stage 1 to stage 2 kill all particles and stick a bunch on the player ship
216                 if((sn_stage == 1) && (supernova_active() == 2)){
217                         // first kill all active particles so we have a bunch of free ones
218                         particle_kill_all();                            
219                 }               
220
221                 // if we're in stage 2, emit particles
222                 if((sn_stage >= 2) && (sn_stage != 5)){
223                         supernova_do_particles();
224                 }
225
226                 // if we've got negative. the supernova is done
227                 if(Supernova_time < 0.0f){                                                      
228                         Supernova_finished = 1;
229                         Supernova_fade_to_white += flFrametime;
230
231                         // start the dead popup
232                         if(Supernova_fade_to_white >= SUPERNOVA_FADE_TO_WHITE_TIME){
233                                 if(!Supernova_popup){
234                                         // main freespace 2 campaign? if so - end it now
235                                         if((Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2") && Campaign_ended_in_mission){
236                                                 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
237                                         } else {
238                                                 popupdead_start();
239                                         }
240                                         Supernova_popup = 1;
241                                 }
242                                 Supernova_finished = 2;
243                         }
244                 }
245         }                       
246 }
247
248 // is there a supernova active
249 int supernova_active()
250 {
251         // if the supernova has "finished". fade to white and dead popup
252         if(Supernova_finished == 1){
253                 Supernova_status = SUPERNOVA_HIT;
254                 return 4;
255         }
256         if(Supernova_finished == 2){
257                 Supernova_status = SUPERNOVA_HIT;
258                 return 5;
259         }
260
261         // no supernova
262         if((Supernova_time_total <= 0.0f) || (Supernova_time <= 0.0f)){
263                 return 0;
264         }       
265
266         // final stage, 
267         if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){         
268                 Supernova_status = SUPERNOVA_HIT;
269                 return 3;
270         }       
271
272         // 2nd stage
273         if(Supernova_time < SUPERNOVA_CUT_TIME){
274                 Supernova_status = SUPERNOVA_HIT;
275                 return 2;
276         }
277
278         // first stage
279         return 1;
280 }
281
282 // time left before the supernova hits
283 float supernova_time_left()
284 {
285         return Supernova_time;
286 }
287
288 // pct complete the supernova (0.0 to 1.0)
289 float supernova_pct_complete()
290 {
291         // bogus
292         if(!supernova_active()){
293                 return -1.0f;
294         }
295
296         return (Supernova_time_total - Supernova_time) / Supernova_time_total;
297 }
298
299 // if the camera should cut to the "you-are-toast" cam
300 int supernova_camera_cut()
301 {
302         // if we're not in a supernova
303         if(!supernova_active()){
304                 return 0;
305         }
306
307         // if we're past the critical time
308         if(Supernova_time <= SUPERNOVA_CUT_TIME){
309                 return 1;
310         }
311
312         // no cut yet
313         return 0;
314 }
315
316 // apply a shake to the orient matrix
317 void supernova_apply_shake(matrix *eye_orient, float intensity)
318 {       
319         angles  tangles;
320
321         tangles.p = 0.0f;
322         tangles.h = 0.0f;
323         tangles.b = 0.0f;       
324
325         // Make eye shake due to engine wash            
326         int r1 = myrand();
327         int r2 = myrand();
328         tangles.p += 0.07f * intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
329         tangles.h += 0.07f * intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;                      
330
331         matrix  tm, tm2;
332         vm_angles_2_matrix(&tm, &tangles);
333         Assert(vm_vec_mag(&tm.fvec) > 0.0f);
334         Assert(vm_vec_mag(&tm.rvec) > 0.0f);
335         Assert(vm_vec_mag(&tm.uvec) > 0.0f);
336         vm_matrix_x_matrix(&tm2, eye_orient, &tm);
337         *eye_orient = tm2;      
338 }
339
340 // get view params from supernova
341 float sn_distance = 300.0f;                             // shockwave moving at 1000/ms ?
342 float sn_cam_distance = 25.0f;
343 DCF(sn_dist, "")
344 {
345         dc_get_arg(ARG_FLOAT);
346         sn_distance = Dc_arg_float;
347 }
348 DCF(sn_cam_dist, "")
349 {
350         dc_get_arg(ARG_FLOAT);
351         sn_cam_distance = Dc_arg_float;
352 }
353 void supernova_set_view(vector *eye_pos, matrix *eye_orient)
354 {
355         vector at;
356         vector sun_temp, sun;
357         vector move;
358         vector view;
359         float cut_pct = 1.0f - (Supernova_time / SUPERNOVA_CUT_TIME);           
360         
361         // set the controls for the heart of the sun    
362         stars_get_sun_pos(0, &sun_temp);
363         vm_vec_add2(&sun_temp, &Player_obj->pos);
364         vm_vec_sub(&sun, &sun_temp, &Player_obj->pos);
365         vm_vec_normalize(&sun);
366
367         // always set the camera pos
368         matrix whee;
369         vm_vector_2_matrix(&whee, &move, NULL, NULL);
370         vm_vec_scale_add(&Supernova_camera_pos, &Player_obj->pos, &whee.rvec, sn_cam_distance);
371         vm_vec_scale_add2(&Supernova_camera_pos, &whee.uvec, 30.0f);
372         *eye_pos = Supernova_camera_pos;
373
374         // if we're no longer moving the camera
375         if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){
376                 // *eye_pos = Supernova_camera_pos;
377                 *eye_orient = Supernova_camera_orient;          
378
379                 // shake the eye                
380                 supernova_apply_shake(eye_orient, cut_pct * sn_shudder);
381
382                 return;
383         } 
384         // otherwise move it
385         else {
386                 // get a vector somewhere between the supernova shockwave and the player ship   
387                 at = Player_obj->pos;
388                 vm_vec_scale_add2(&at, &sun, sn_distance);
389                 vm_vec_sub(&move, &Player_obj->pos, &at);
390                 vm_vec_normalize(&move);
391                                 
392                 // linearly move towards the player pos
393                 float pct = ((SUPERNOVA_CUT_TIME - Supernova_time) / SUPERNOVA_CAMERA_MOVE_TIME);
394                 vm_vec_scale_add2(&at, &move, sn_distance * pct);       
395
396                 *eye_pos = Supernova_camera_pos;
397                 vm_vec_sub(&view, &at, eye_pos);
398                 vm_vec_normalize(&view);
399                 vm_vector_2_matrix(&Supernova_camera_orient, &view, NULL, NULL);
400                 *eye_orient = Supernova_camera_orient;
401         }       
402
403         // shake the eye
404         supernova_apply_shake(eye_orient, cut_pct * sn_shudder);
405 }