2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Starfield/Supernova.cpp $
15 * Include file for nebula stuff
18 * Revision 1.4 2002/06/17 06:33:11 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.3 2002/06/09 04:41:27 relnev
22 * added copyright header
24 * Revision 1.2 2002/05/07 03:16:52 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:10 root
31 * 5 9/09/99 11:40p Dave
32 * Handle an SDL_assert() in beam code. Added supernova sounds. Play the right
33 * 2 end movies properly, based upon what the player did in the mission.
35 * 4 9/03/99 1:32a Dave
36 * CD checking by act. Added support to play 2 cutscenes in a row
37 * seamlessly. Fixed super low level cfile bug related to files in the
38 * root directory of a CD. Added cheat code to set campaign mission # in
41 * 3 7/31/99 4:15p Dave
42 * Fixed supernova particle velocities. Handle OBJ_NONE in target
43 * monitoring view. Properly use objectives notify gauge colors.
45 * 2 7/21/99 8:10p Dave
46 * First run of supernova effect.
52 #include "freespace.h"
56 #include "starfield.h"
57 #include "supernova.h"
62 #include "popupdead.h"
64 #include "missioncampaign.h"
65 #include "gamesequence.h"
70 // --------------------------------------------------------------------------------------------------------------------------
71 // SUPERNOVA DEFINES/VARS
75 #define SUPERNOVA_SOUND_1_TIME 15.0f
76 #define SUPERNOVA_SOUND_2_TIME 5.0f
77 int Supernova_sound_1_played = 0;
78 int Supernova_sound_2_played = 0;
80 // countdown for supernova
81 float Supernova_time_total = -1.0f;
82 float Supernova_time = -1.0f;
83 int Supernova_finished = 0;
84 int Supernova_popup = 0;
85 float Supernova_fade_to_white = 0.0f;
86 int Supernova_particle_stamp = -1;
88 // supernova camera pos
89 vector Supernova_camera_pos;
90 matrix Supernova_camera_orient;
92 int Supernova_status = SUPERNOVA_NONE;
94 // --------------------------------------------------------------------------------------------------------------------------
95 // SUPERNOVA FUNCTIONS
99 void supernova_level_init()
101 Supernova_time_total = -1.0f;
102 Supernova_time = -1.0f;
103 Supernova_finished = 0;
104 Supernova_fade_to_white = 0.0f;
106 Supernova_particle_stamp = -1;
108 Supernova_sound_1_played = 0;
109 Supernova_sound_2_played = 0;
111 Supernova_status = SUPERNOVA_NONE;
115 void supernova_start(int seconds)
118 if((float)seconds < SUPERNOVA_CUT_TIME){
122 // no supernova in multiplayer
123 if(Game_mode & GM_MULTIPLAYER){
127 // only good if we have one sun
132 Supernova_time_total = (float)seconds;
133 Supernova_time = (float)seconds;
134 Supernova_finished = 0;
135 Supernova_fade_to_white = 0.0f;
137 Supernova_particle_stamp = -1;
139 Supernova_status = SUPERNOVA_STARTED;
142 int sn_particles = 100;
146 sn_particles = Dc_arg_int;
148 void supernova_do_particles()
152 vector norm, sun_temp;
155 if((Player_obj == NULL) || (Player_ship == NULL)){
160 if((Supernova_particle_stamp == -1) || timestamp_elapsed(Supernova_particle_stamp)){
161 Supernova_particle_stamp = timestamp(sn_particles);
164 stars_get_sun_pos(0, &sun_temp);
165 vm_vec_add2(&sun_temp, &Player_obj->pos);
166 vm_vec_sub(&norm, &Player_obj->pos, &sun_temp);
167 vm_vec_normalize(&norm);
169 particle_emitter whee;
170 whee.max_life = 1.0f;
171 whee.min_life = 0.6f;
172 whee.max_vel = 50.0f;
173 whee.min_vel = 25.0f;
174 whee.normal_variance = 0.75f;
178 whee.max_rad = 1.25f;
181 for(idx=0; idx<10; idx++){
182 submodel_get_two_random_points(Player_ship->modelnum, 0, &ta, &tb);
184 // rotate into world space
185 vm_vec_unrotate(&a, &ta, &Player_obj->orient);
186 vm_vec_add2(&a, &Player_obj->pos);
189 vm_vec_scale(&whee.vel, 30.0f);
190 vm_vec_add2(&whee.vel, &Player_obj->phys_info.vel);
192 particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
194 vm_vec_unrotate(&b, &tb, &Player_obj->orient);
195 vm_vec_add2(&b, &Player_obj->pos);
197 particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
202 // call once per frame
203 float sn_shudder = 0.45f;
206 dc_get_arg(ARG_FLOAT);
207 sn_shudder = Dc_arg_float;
210 void supernova_process()
214 // if the supernova is running
215 sn_stage = supernova_active();
217 Supernova_time -= flFrametime;
220 if((Supernova_time <= SUPERNOVA_SOUND_1_TIME) && !Supernova_sound_1_played){
221 Supernova_sound_1_played = 1;
222 snd_play(&Snds[SND_SUPERNOVA_1], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
224 if((Supernova_time <= SUPERNOVA_SOUND_2_TIME) && !Supernova_sound_2_played){
225 Supernova_sound_2_played = 1;
226 snd_play(&Snds[SND_SUPERNOVA_2], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
229 // if we've crossed from stage 1 to stage 2 kill all particles and stick a bunch on the player ship
230 if((sn_stage == 1) && (supernova_active() == 2)){
231 // first kill all active particles so we have a bunch of free ones
235 // if we're in stage 2, emit particles
236 if((sn_stage >= 2) && (sn_stage != 5)){
237 supernova_do_particles();
240 // if we've got negative. the supernova is done
241 if(Supernova_time < 0.0f){
242 Supernova_finished = 1;
243 Supernova_fade_to_white += flFrametime;
245 // start the dead popup
246 if(Supernova_fade_to_white >= SUPERNOVA_FADE_TO_WHITE_TIME){
247 if(!Supernova_popup){
248 // main freespace 2 campaign? if so - end it now
249 if((Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace2") && Campaign_ended_in_mission){
250 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
256 Supernova_finished = 2;
262 // is there a supernova active
263 int supernova_active()
265 // if the supernova has "finished". fade to white and dead popup
266 if(Supernova_finished == 1){
267 Supernova_status = SUPERNOVA_HIT;
270 if(Supernova_finished == 2){
271 Supernova_status = SUPERNOVA_HIT;
276 if((Supernova_time_total <= 0.0f) || (Supernova_time <= 0.0f)){
281 if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){
282 Supernova_status = SUPERNOVA_HIT;
287 if(Supernova_time < SUPERNOVA_CUT_TIME){
288 Supernova_status = SUPERNOVA_HIT;
296 // time left before the supernova hits
297 float supernova_time_left()
299 return Supernova_time;
302 // pct complete the supernova (0.0 to 1.0)
303 float supernova_pct_complete()
306 if(!supernova_active()){
310 return (Supernova_time_total - Supernova_time) / Supernova_time_total;
313 // if the camera should cut to the "you-are-toast" cam
314 int supernova_camera_cut()
316 // if we're not in a supernova
317 if(!supernova_active()){
321 // if we're past the critical time
322 if(Supernova_time <= SUPERNOVA_CUT_TIME){
330 // apply a shake to the orient matrix
331 void supernova_apply_shake(matrix *eye_orient, float intensity)
339 // Make eye shake due to engine wash
342 tangles.p += 0.07f * intensity * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX;
343 tangles.h += 0.07f * intensity * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX;
346 vm_angles_2_matrix(&tm, &tangles);
347 SDL_assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
348 SDL_assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
349 SDL_assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
350 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
354 // get view params from supernova
355 float sn_distance = 300.0f; // shockwave moving at 1000/ms ?
356 float sn_cam_distance = 25.0f;
359 dc_get_arg(ARG_FLOAT);
360 sn_distance = Dc_arg_float;
364 dc_get_arg(ARG_FLOAT);
365 sn_cam_distance = Dc_arg_float;
367 void supernova_set_view(vector *eye_pos, matrix *eye_orient)
370 vector sun_temp, sun;
373 float cut_pct = 1.0f - (Supernova_time / SUPERNOVA_CUT_TIME);
375 // set the controls for the heart of the sun
376 stars_get_sun_pos(0, &sun_temp);
377 vm_vec_add2(&sun_temp, &Player_obj->pos);
378 vm_vec_sub(&sun, &sun_temp, &Player_obj->pos);
379 vm_vec_normalize(&sun);
381 // always set the camera pos
383 vm_vector_2_matrix(&whee, &move, NULL, NULL);
384 vm_vec_scale_add(&Supernova_camera_pos, &Player_obj->pos, &whee.v.rvec, sn_cam_distance);
385 vm_vec_scale_add2(&Supernova_camera_pos, &whee.v.uvec, 30.0f);
386 *eye_pos = Supernova_camera_pos;
388 // if we're no longer moving the camera
389 if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){
390 // *eye_pos = Supernova_camera_pos;
391 *eye_orient = Supernova_camera_orient;
394 supernova_apply_shake(eye_orient, cut_pct * sn_shudder);
400 // get a vector somewhere between the supernova shockwave and the player ship
401 at = Player_obj->pos;
402 vm_vec_scale_add2(&at, &sun, sn_distance);
403 vm_vec_sub(&move, &Player_obj->pos, &at);
404 vm_vec_normalize(&move);
406 // linearly move towards the player pos
407 float pct = ((SUPERNOVA_CUT_TIME - Supernova_time) / SUPERNOVA_CAMERA_MOVE_TIME);
408 vm_vec_scale_add2(&at, &move, sn_distance * pct);
410 *eye_pos = Supernova_camera_pos;
411 vm_vec_sub(&view, &at, eye_pos);
412 vm_vec_normalize(&view);
413 vm_vector_2_matrix(&Supernova_camera_orient, &view, NULL, NULL);
414 *eye_orient = Supernova_camera_orient;
418 supernova_apply_shake(eye_orient, cut_pct * sn_shudder);