mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 12:41:35 -10:00
423 lines
10 KiB
C++
423 lines
10 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/Starfield/Supernova.cpp $
|
|
* $Revision: 2.4 $
|
|
* $Date: 2004-07-26 20:47:53 $
|
|
* $Author: Kazan $
|
|
*
|
|
* Include file for nebula stuff
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 2.3 2004/07/12 16:33:07 Kazan
|
|
* MCD - define _MCD_CHECK to use memory tracking
|
|
*
|
|
* Revision 2.2 2004/03/05 09:02:07 Goober5000
|
|
* Uber pass at reducing #includes
|
|
* --Goober5000
|
|
*
|
|
* Revision 2.1 2002/08/01 01:41:10 penguin
|
|
* The big include file move
|
|
*
|
|
* Revision 2.0 2002/06/03 04:02:29 penguin
|
|
* Warpcore CVS sync
|
|
*
|
|
* Revision 1.2 2002/05/04 04:52:22 mharris
|
|
* 1st draft at porting
|
|
*
|
|
* Revision 1.1 2002/05/02 18:03:13 mharris
|
|
* Initial checkin - converted filenames and includes to lower case
|
|
*
|
|
*
|
|
* 5 9/09/99 11:40p Dave
|
|
* Handle an Assert() in beam code. Added supernova sounds. Play the right
|
|
* 2 end movies properly, based upon what the player did in the mission.
|
|
*
|
|
* 4 9/03/99 1:32a Dave
|
|
* CD checking by act. Added support to play 2 cutscenes in a row
|
|
* seamlessly. Fixed super low level cfile bug related to files in the
|
|
* root directory of a CD. Added cheat code to set campaign mission # in
|
|
* main hall.
|
|
*
|
|
* 3 7/31/99 4:15p Dave
|
|
* Fixed supernova particle velocities. Handle OBJ_NONE in target
|
|
* monitoring view. Properly use objectives notify gauge colors.
|
|
*
|
|
* 2 7/21/99 8:10p Dave
|
|
* First run of supernova effect.
|
|
*
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "starfield/supernova.h"
|
|
#include "freespace2/freespace.h"
|
|
#include "math/vecmat.h"
|
|
#include "starfield/starfield.h"
|
|
#include "particle/particle.h"
|
|
#include "ship/ship.h"
|
|
#include "io/timer.h"
|
|
#include "popup/popupdead.h"
|
|
#include "mission/missioncampaign.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "gamesnd/gamesnd.h"
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------------
|
|
// SUPERNOVA DEFINES/VARS
|
|
//
|
|
|
|
// supernova time 1
|
|
#define SUPERNOVA_SOUND_1_TIME 15.0f
|
|
#define SUPERNOVA_SOUND_2_TIME 5.0f
|
|
int Supernova_sound_1_played = 0;
|
|
int Supernova_sound_2_played = 0;
|
|
|
|
// countdown for supernova
|
|
float Supernova_time_total = -1.0f;
|
|
float Supernova_time = -1.0f;
|
|
int Supernova_finished = 0;
|
|
int Supernova_popup = 0;
|
|
float Supernova_fade_to_white = 0.0f;
|
|
int Supernova_particle_stamp = -1;
|
|
|
|
// supernova camera pos
|
|
vector Supernova_camera_pos;
|
|
matrix Supernova_camera_orient;
|
|
|
|
int Supernova_status = SUPERNOVA_NONE;
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------------
|
|
// SUPERNOVA FUNCTIONS
|
|
//
|
|
|
|
// level init
|
|
void supernova_level_init()
|
|
{
|
|
Supernova_time_total = -1.0f;
|
|
Supernova_time = -1.0f;
|
|
Supernova_finished = 0;
|
|
Supernova_fade_to_white = 0.0f;
|
|
Supernova_popup = 0;
|
|
Supernova_particle_stamp = -1;
|
|
|
|
Supernova_sound_1_played = 0;
|
|
Supernova_sound_2_played = 0;
|
|
|
|
Supernova_status = SUPERNOVA_NONE;
|
|
}
|
|
|
|
// start a supernova
|
|
void supernova_start(int seconds)
|
|
{
|
|
// bogus time
|
|
if((float)seconds < SUPERNOVA_CUT_TIME){
|
|
return;
|
|
}
|
|
|
|
// no supernova in multiplayer
|
|
if(Game_mode & GM_MULTIPLAYER){
|
|
return;
|
|
}
|
|
|
|
// only good if we have one sun
|
|
if(Num_suns != 1){
|
|
return;
|
|
}
|
|
|
|
Supernova_time_total = (float)seconds;
|
|
Supernova_time = (float)seconds;
|
|
Supernova_finished = 0;
|
|
Supernova_fade_to_white = 0.0f;
|
|
Supernova_popup = 0;
|
|
Supernova_particle_stamp = -1;
|
|
|
|
Supernova_status = SUPERNOVA_STARTED;
|
|
}
|
|
|
|
int sn_particles = 100;
|
|
DCF(sn_part, "")
|
|
{
|
|
dc_get_arg(ARG_INT);
|
|
sn_particles = Dc_arg_int;
|
|
}
|
|
void supernova_do_particles()
|
|
{
|
|
int idx;
|
|
vector a, b, ta, tb;
|
|
vector norm, sun_temp;
|
|
|
|
// no player ship
|
|
if((Player_obj == NULL) || (Player_ship == NULL)){
|
|
return;
|
|
}
|
|
|
|
// timestamp
|
|
if((Supernova_particle_stamp == -1) || timestamp_elapsed(Supernova_particle_stamp)){
|
|
Supernova_particle_stamp = timestamp(sn_particles);
|
|
|
|
// get particle norm
|
|
stars_get_sun_pos(0, &sun_temp);
|
|
vm_vec_add2(&sun_temp, &Player_obj->pos);
|
|
vm_vec_sub(&norm, &Player_obj->pos, &sun_temp);
|
|
vm_vec_normalize(&norm);
|
|
|
|
particle_emitter whee;
|
|
whee.max_life = 1.0f;
|
|
whee.min_life = 0.6f;
|
|
whee.max_vel = 50.0f;
|
|
whee.min_vel = 25.0f;
|
|
whee.normal_variance = 0.75f;
|
|
whee.num_high = 5;
|
|
whee.num_low = 2;
|
|
whee.min_rad = 0.5f;
|
|
whee.max_rad = 1.25f;
|
|
|
|
// emit
|
|
for(idx=0; idx<10; idx++){
|
|
submodel_get_two_random_points(Player_ship->modelnum, 0, &ta, &tb);
|
|
|
|
// rotate into world space
|
|
vm_vec_unrotate(&a, &ta, &Player_obj->orient);
|
|
vm_vec_add2(&a, &Player_obj->pos);
|
|
whee.pos = a;
|
|
whee.vel = norm;
|
|
vm_vec_scale(&whee.vel, 30.0f);
|
|
vm_vec_add2(&whee.vel, &Player_obj->phys_info.vel);
|
|
whee.normal = norm;
|
|
particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
|
|
|
|
vm_vec_unrotate(&b, &tb, &Player_obj->orient);
|
|
vm_vec_add2(&b, &Player_obj->pos);
|
|
whee.pos = b;
|
|
particle_emit(&whee, PARTICLE_FIRE, (uint)-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// call once per frame
|
|
float sn_shudder = 0.45f;
|
|
DCF(sn_shud, "")
|
|
{
|
|
dc_get_arg(ARG_FLOAT);
|
|
sn_shudder = Dc_arg_float;
|
|
}
|
|
|
|
void supernova_process()
|
|
{
|
|
int sn_stage;
|
|
|
|
// if the supernova is running
|
|
sn_stage = supernova_active();
|
|
if(sn_stage){
|
|
Supernova_time -= flFrametime;
|
|
|
|
// sound stuff
|
|
if((Supernova_time <= SUPERNOVA_SOUND_1_TIME) && !Supernova_sound_1_played){
|
|
Supernova_sound_1_played = 1;
|
|
snd_play(&Snds[SND_SUPERNOVA_1], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
|
|
}
|
|
if((Supernova_time <= SUPERNOVA_SOUND_2_TIME) && !Supernova_sound_2_played){
|
|
Supernova_sound_2_played = 1;
|
|
snd_play(&Snds[SND_SUPERNOVA_2], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY);
|
|
}
|
|
|
|
// if we've crossed from stage 1 to stage 2 kill all particles and stick a bunch on the player ship
|
|
if((sn_stage == 1) && (supernova_active() == 2)){
|
|
// first kill all active particles so we have a bunch of free ones
|
|
particle_kill_all();
|
|
}
|
|
|
|
// if we're in stage 2, emit particles
|
|
if((sn_stage >= 2) && (sn_stage != 5)){
|
|
supernova_do_particles();
|
|
}
|
|
|
|
// if we've got negative. the supernova is done
|
|
if(Supernova_time < 0.0f){
|
|
Supernova_finished = 1;
|
|
Supernova_fade_to_white += flFrametime;
|
|
|
|
// start the dead popup
|
|
if(Supernova_fade_to_white >= SUPERNOVA_FADE_TO_WHITE_TIME){
|
|
if(!Supernova_popup){
|
|
// main freespace 2 campaign? if so - end it now
|
|
if((Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2") && Campaign_ended_in_mission){
|
|
gameseq_post_event(GS_EVENT_END_CAMPAIGN);
|
|
} else {
|
|
popupdead_start();
|
|
}
|
|
Supernova_popup = 1;
|
|
}
|
|
Supernova_finished = 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// is there a supernova active
|
|
int supernova_active()
|
|
{
|
|
// if the supernova has "finished". fade to white and dead popup
|
|
if(Supernova_finished == 1){
|
|
Supernova_status = SUPERNOVA_HIT;
|
|
return 4;
|
|
}
|
|
if(Supernova_finished == 2){
|
|
Supernova_status = SUPERNOVA_HIT;
|
|
return 5;
|
|
}
|
|
|
|
// no supernova
|
|
if((Supernova_time_total <= 0.0f) || (Supernova_time <= 0.0f)){
|
|
return 0;
|
|
}
|
|
|
|
// final stage,
|
|
if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){
|
|
Supernova_status = SUPERNOVA_HIT;
|
|
return 3;
|
|
}
|
|
|
|
// 2nd stage
|
|
if(Supernova_time < SUPERNOVA_CUT_TIME){
|
|
Supernova_status = SUPERNOVA_HIT;
|
|
return 2;
|
|
}
|
|
|
|
// first stage
|
|
return 1;
|
|
}
|
|
|
|
// time left before the supernova hits
|
|
float supernova_time_left()
|
|
{
|
|
return Supernova_time;
|
|
}
|
|
|
|
// pct complete the supernova (0.0 to 1.0)
|
|
float supernova_pct_complete()
|
|
{
|
|
// bogus
|
|
if(!supernova_active()){
|
|
return -1.0f;
|
|
}
|
|
|
|
return (Supernova_time_total - Supernova_time) / Supernova_time_total;
|
|
}
|
|
|
|
// if the camera should cut to the "you-are-toast" cam
|
|
int supernova_camera_cut()
|
|
{
|
|
// if we're not in a supernova
|
|
if(!supernova_active()){
|
|
return 0;
|
|
}
|
|
|
|
// if we're past the critical time
|
|
if(Supernova_time <= SUPERNOVA_CUT_TIME){
|
|
return 1;
|
|
}
|
|
|
|
// no cut yet
|
|
return 0;
|
|
}
|
|
|
|
// apply a shake to the orient matrix
|
|
void supernova_apply_shake(matrix *eye_orient, float intensity)
|
|
{
|
|
angles tangles;
|
|
|
|
tangles.p = 0.0f;
|
|
tangles.h = 0.0f;
|
|
tangles.b = 0.0f;
|
|
|
|
// Make eye shake due to engine wash
|
|
int r1 = myrand();
|
|
int r2 = myrand();
|
|
tangles.p += 0.07f * intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
|
|
tangles.h += 0.07f * intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
|
|
|
|
matrix tm, tm2;
|
|
vm_angles_2_matrix(&tm, &tangles);
|
|
Assert(vm_vec_mag(&tm.vec.fvec) > 0.0f);
|
|
Assert(vm_vec_mag(&tm.vec.rvec) > 0.0f);
|
|
Assert(vm_vec_mag(&tm.vec.uvec) > 0.0f);
|
|
vm_matrix_x_matrix(&tm2, eye_orient, &tm);
|
|
*eye_orient = tm2;
|
|
}
|
|
|
|
// get view params from supernova
|
|
float sn_distance = 300.0f; // shockwave moving at 1000/ms ?
|
|
float sn_cam_distance = 25.0f;
|
|
DCF(sn_dist, "")
|
|
{
|
|
dc_get_arg(ARG_FLOAT);
|
|
sn_distance = Dc_arg_float;
|
|
}
|
|
DCF(sn_cam_dist, "")
|
|
{
|
|
dc_get_arg(ARG_FLOAT);
|
|
sn_cam_distance = Dc_arg_float;
|
|
}
|
|
void supernova_set_view(vector *eye_pos, matrix *eye_orient)
|
|
{
|
|
vector at;
|
|
vector sun_temp, sun;
|
|
vector move;
|
|
vector view;
|
|
float cut_pct = 1.0f - (Supernova_time / SUPERNOVA_CUT_TIME);
|
|
|
|
// set the controls for the heart of the sun
|
|
stars_get_sun_pos(0, &sun_temp);
|
|
vm_vec_add2(&sun_temp, &Player_obj->pos);
|
|
vm_vec_sub(&sun, &sun_temp, &Player_obj->pos);
|
|
vm_vec_normalize(&sun);
|
|
|
|
// always set the camera pos
|
|
matrix whee;
|
|
vm_vector_2_matrix(&whee, &move, NULL, NULL);
|
|
vm_vec_scale_add(&Supernova_camera_pos, &Player_obj->pos, &whee.vec.rvec, sn_cam_distance);
|
|
vm_vec_scale_add2(&Supernova_camera_pos, &whee.vec.uvec, 30.0f);
|
|
*eye_pos = Supernova_camera_pos;
|
|
|
|
// if we're no longer moving the camera
|
|
if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)){
|
|
// *eye_pos = Supernova_camera_pos;
|
|
*eye_orient = Supernova_camera_orient;
|
|
|
|
// shake the eye
|
|
supernova_apply_shake(eye_orient, cut_pct * sn_shudder);
|
|
|
|
return;
|
|
}
|
|
// otherwise move it
|
|
else {
|
|
// get a vector somewhere between the supernova shockwave and the player ship
|
|
at = Player_obj->pos;
|
|
vm_vec_scale_add2(&at, &sun, sn_distance);
|
|
vm_vec_sub(&move, &Player_obj->pos, &at);
|
|
vm_vec_normalize(&move);
|
|
|
|
// linearly move towards the player pos
|
|
float pct = ((SUPERNOVA_CUT_TIME - Supernova_time) / SUPERNOVA_CAMERA_MOVE_TIME);
|
|
vm_vec_scale_add2(&at, &move, sn_distance * pct);
|
|
|
|
*eye_pos = Supernova_camera_pos;
|
|
vm_vec_sub(&view, &at, eye_pos);
|
|
vm_vec_normalize(&view);
|
|
vm_vector_2_matrix(&Supernova_camera_orient, &view, NULL, NULL);
|
|
*eye_orient = Supernova_camera_orient;
|
|
}
|
|
|
|
// shake the eye
|
|
supernova_apply_shake(eye_orient, cut_pct * sn_shudder);
|
|
}
|