mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 17:48:46 -10:00
312 lines
6.9 KiB
C++
312 lines
6.9 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.
|
|
*
|
|
*/
|
|
|
|
#include "globalincs/systemvars.h"
|
|
#include "parse/parselo.h"
|
|
#include "weapon/muzzleflash.h"
|
|
#include "particle/particle.h"
|
|
#include "graphics/2d.h"
|
|
#include "math/vecmat.h"
|
|
#include "object/object.h"
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
// MUZZLE FLASH DEFINES/VARS
|
|
//
|
|
|
|
// muzzle flash info - read from a table
|
|
typedef struct mflash_blob_info {
|
|
char name[MAX_FILENAME_LEN];
|
|
int anim_id;
|
|
float offset;
|
|
float radius;
|
|
|
|
mflash_blob_info( const mflash_blob_info& mbi )
|
|
{
|
|
strcpy_s( name, mbi.name );
|
|
anim_id = mbi.anim_id;
|
|
offset = mbi.offset;
|
|
radius = mbi.radius;
|
|
}
|
|
|
|
mflash_blob_info() :
|
|
anim_id( -1 ),
|
|
offset( 0.0 ),
|
|
radius( 0.0 )
|
|
{
|
|
name[ 0 ] = '\0';
|
|
}
|
|
|
|
void operator=( const mflash_blob_info& r )
|
|
{
|
|
strcpy_s( name, r.name );
|
|
anim_id = r.anim_id;
|
|
offset = r.offset;
|
|
radius = r.radius;
|
|
}
|
|
} mflash_blob_info;
|
|
|
|
typedef struct mflash_info {
|
|
char name[MAX_FILENAME_LEN];
|
|
int used_this_level;
|
|
SCP_vector<mflash_blob_info> blobs;
|
|
|
|
mflash_info()
|
|
: used_this_level( 0 )
|
|
{
|
|
name[ 0 ] = '\0';
|
|
}
|
|
|
|
mflash_info( const mflash_info& mi )
|
|
{
|
|
strcpy_s( name, mi.name );
|
|
used_this_level = mi.used_this_level;
|
|
blobs = mi.blobs;
|
|
}
|
|
|
|
void operator=( const mflash_info& r )
|
|
{
|
|
strcpy_s( name, r.name );
|
|
used_this_level = r.used_this_level;
|
|
blobs = r.blobs;
|
|
}
|
|
} mflash_info;
|
|
|
|
SCP_vector<mflash_info> Mflash_info;
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
// MUZZLE FLASH FUNCTIONS
|
|
//
|
|
|
|
void parse_mflash_tbl(char *filename)
|
|
{
|
|
int rval;
|
|
uint i;
|
|
|
|
if ((rval = setjmp(parse_abort)) != 0) {
|
|
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
|
|
return;
|
|
}
|
|
|
|
read_file_text(filename, CF_TYPE_TABLES);
|
|
reset_parse();
|
|
|
|
// header
|
|
required_string("#Muzzle flash types");
|
|
|
|
while ( optional_string("$Mflash:") ) {
|
|
mflash_info mflash;
|
|
bool override_mflash = false;
|
|
|
|
required_string("+name:");
|
|
stuff_string(mflash.name, F_NAME, MAX_FILENAME_LEN);
|
|
|
|
if (optional_string("+override"))
|
|
override_mflash = true;
|
|
|
|
// read in all blobs
|
|
while ( optional_string("+blob_name:") ) {
|
|
mflash_blob_info mblob;
|
|
|
|
stuff_string(mblob.name, F_NAME, MAX_FILENAME_LEN);
|
|
|
|
required_string("+blob_offset:");
|
|
stuff_float(&mblob.offset);
|
|
|
|
required_string("+blob_radius:");
|
|
stuff_float(&mblob.radius);
|
|
|
|
mflash.blobs.push_back(mblob);
|
|
}
|
|
|
|
for (i = 0; i < Mflash_info.size(); i++) {
|
|
if ( !stricmp(mflash.name, Mflash_info[i].name) ) {
|
|
if (override_mflash) {
|
|
Mflash_info[i] = mflash;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// no matching name exists so add as new
|
|
if (i == Mflash_info.size()) {
|
|
Mflash_info.push_back(mflash);
|
|
}
|
|
// a mflash of the same name exists, don't add it again
|
|
else {
|
|
if (!override_mflash) {
|
|
Warning(LOCATION, "Muzzle flash \"%s\" already exists! Using existing entry instead.", mflash.name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// close
|
|
required_string("#end");
|
|
}
|
|
|
|
// initialize muzzle flash stuff for the whole game
|
|
void mflash_game_init()
|
|
{
|
|
// parse main table first
|
|
parse_mflash_tbl("mflash.tbl");
|
|
|
|
// look for any modular tables
|
|
parse_modular_table(NOX("*-mfl.tbm"), parse_mflash_tbl);
|
|
}
|
|
|
|
void mflash_mark_as_used(int index)
|
|
{
|
|
if (index < 0)
|
|
return;
|
|
|
|
Assert( index < (int)Mflash_info.size() );
|
|
|
|
Mflash_info[index].used_this_level++;
|
|
}
|
|
|
|
void mflash_page_in(bool load_all)
|
|
{
|
|
uint i, idx;
|
|
int num_frames, fps;
|
|
|
|
// load up all anims
|
|
for ( i = 0; i < Mflash_info.size(); i++) {
|
|
// skip if it's not used
|
|
if ( !load_all && !Mflash_info[i].used_this_level )
|
|
continue;
|
|
|
|
// blobs
|
|
int original_num_blobs = Mflash_info[i].blobs.size();
|
|
int original_idx = 1;
|
|
for ( idx = 0; idx < Mflash_info[i].blobs.size(); ) {
|
|
Mflash_info[i].blobs[idx].anim_id = bm_load_either(Mflash_info[i].blobs[idx].name, &num_frames, &fps, NULL, 1);
|
|
if ( Mflash_info[i].blobs[idx].anim_id >= 0 ) {
|
|
bm_page_in_xparent_texture( Mflash_info[i].blobs[idx].anim_id );
|
|
++idx;
|
|
}
|
|
else {
|
|
Warning(LOCATION, "Muzleflash \"%s\", blob [%d/%d]\nMuzzleflash blob \"%s\" not found! Deleting.",
|
|
Mflash_info[i].name, original_idx, original_num_blobs, Mflash_info[i].blobs[idx].name);
|
|
Mflash_info[i].blobs.erase( Mflash_info[i].blobs.begin() + idx );
|
|
}
|
|
++original_idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
// initialize muzzle flash stuff for the level
|
|
void mflash_level_init()
|
|
{
|
|
uint i, idx;
|
|
|
|
// reset all anim usage for this level
|
|
for ( i = 0; i < Mflash_info.size(); i++) {
|
|
for ( idx = 0; idx < Mflash_info[i].blobs.size(); idx++) {
|
|
Mflash_info[i].used_this_level = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// shutdown stuff for the level
|
|
void mflash_level_close()
|
|
{
|
|
uint i, idx;
|
|
|
|
// release all anims
|
|
for ( i = 0; i < Mflash_info.size(); i++) {
|
|
// blobs
|
|
for ( idx = 0; idx < Mflash_info[i].blobs.size(); idx++) {
|
|
if ( Mflash_info[i].blobs[idx].anim_id < 0 )
|
|
continue;
|
|
|
|
bm_release( Mflash_info[i].blobs[idx].anim_id );
|
|
Mflash_info[i].blobs[idx].anim_id = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create a muzzle flash on the guy
|
|
void mflash_create(vec3d *gun_pos, vec3d *gun_dir, physics_info *pip, int mflash_type, object *local)
|
|
{
|
|
// mflash *mflashp;
|
|
mflash_info *mi;
|
|
mflash_blob_info *mbi;
|
|
particle_info p;
|
|
uint idx;
|
|
|
|
// standalone server should never create trails
|
|
if(Game_mode & GM_STANDALONE_SERVER){
|
|
return;
|
|
}
|
|
|
|
// illegal value
|
|
if ( (mflash_type < 0) || (mflash_type >= (int)Mflash_info.size()) )
|
|
return;
|
|
|
|
// create the actual animations
|
|
mi = &Mflash_info[mflash_type];
|
|
|
|
if (local != NULL) {
|
|
for (idx = 0; idx < mi->blobs.size(); idx++) {
|
|
mbi = &mi->blobs[idx];
|
|
|
|
// bogus anim
|
|
if (mbi->anim_id < 0)
|
|
continue;
|
|
|
|
// fire it up
|
|
memset(&p, 0, sizeof(particle_info));
|
|
vm_vec_scale_add(&p.pos, gun_pos, gun_dir, mbi->offset);
|
|
vm_vec_zero(&p.vel);
|
|
//vm_vec_scale_add(&p.vel, &pip->rotvel, &pip->vel, 1.0f);
|
|
p.rad = mbi->radius;
|
|
p.type = PARTICLE_BITMAP;
|
|
p.optional_data = mbi->anim_id;
|
|
p.attached_objnum = OBJ_INDEX(local);
|
|
p.attached_sig = local->signature;
|
|
particle_create(&p);
|
|
}
|
|
} else {
|
|
for (idx = 0; idx < mi->blobs.size(); idx++) {
|
|
mbi = &mi->blobs[idx];
|
|
|
|
// bogus anim
|
|
if (mbi->anim_id < 0)
|
|
continue;
|
|
|
|
// fire it up
|
|
memset(&p, 0, sizeof(particle_info));
|
|
vm_vec_scale_add(&p.pos, gun_pos, gun_dir, mbi->offset);
|
|
vm_vec_scale_add(&p.vel, &pip->rotvel, &pip->vel, 1.0f);
|
|
p.rad = mbi->radius;
|
|
p.type = PARTICLE_BITMAP;
|
|
p.optional_data = mbi->anim_id;
|
|
p.attached_objnum = -1;
|
|
p.attached_sig = 0;
|
|
particle_create(&p);
|
|
}
|
|
}
|
|
}
|
|
|
|
// lookup type by name
|
|
int mflash_lookup(char *name)
|
|
{
|
|
uint idx;
|
|
|
|
// look it up
|
|
for (idx = 0; idx < Mflash_info.size(); idx++) {
|
|
if ( !stricmp(name, Mflash_info[idx].name) )
|
|
return idx;
|
|
}
|
|
|
|
// couldn't find it
|
|
return -1;
|
|
}
|