while I'm putting up code snipets I'll put up the modifyed ship_fire_primary function for the fighter beams seeing as that is what this topic is about,
note it makes a clear diferental between fighter beams and targeting lasers, and it bypasses the targeting laser functions
// fires a primary weapon for the given object. It also handles multiplayer cases.
// in multiplayer, the starting network signature, and number of banks fired are sent
// to all the clients in the game. All the info is passed to send_primary at the end of
// the function. The check_energy parameter (defaults to 1) tells us whether or not
// we should check the energy. It will be 0 when a multiplayer client is firing an AI
// primary.
int ship_fire_primary(object * obj, int stream_weapons, int force)
{
vector gun_point, pnt, firing_pos;
int n = obj->instance;
ship *shipp;
ship_weapon *swp;
ship_info *sip;
ai_info *aip;
int weapon, i, j, weapon_objnum;
int bank_to_fire, num_fired = 0;
int banks_fired, have_timeout; // used for multiplayer to help determine whether or not to send packet
have_timeout = 0; // used to help tell us whether or not we need to send a packet
banks_fired = 0; // used in multiplayer -- bitfield of banks that were fired
int sound_played; // used to track what sound is played. If the player is firing two banks
// of the same laser, we only want to play one sound
Assert( obj != NULL );
if(obj == NULL){
return 0;
}
// in the case where the server is an observer, he can fire (which) would be bad - unless we do this.
if( obj->type == OBJ_OBSERVER){
return 0;
}
Assert( obj->type == OBJ_SHIP );
Assert( n >= 0 );
Assert( Ships[n].objnum == OBJ_INDEX(obj));
if((obj->type != OBJ_SHIP) || (n < 0) || (n >= MAX_SHIPS) || (Ships[n].objnum != OBJ_INDEX(obj))){
return 0;
}
shipp = &Ships[n];
swp = &shipp->weapons;
//if (shipp->targeting_laser_objnum != -1)
//shipp->targeting_laser_objnum = -1; // erase old laser obj num if it has any -Bobboau
// bogus
if((shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
return 0;
}
if((shipp->ai_index < 0) || (shipp->ai_index >= MAX_AI_INFO)){
return 0;
}
sip = &Ship_info[shipp->ship_info_index];
aip = &Ai_info[shipp->ai_index];
if ( swp->num_primary_banks <= 0 ) {
return 0;
}
if ( swp->current_primary_bank < 0 ){
return 0;
}
sound_played = -1;
// Fire the correct primary bank. If primaries are linked (SF_PRIMARY_LINKED set), then fire
// both primary banks.
int num_primary_banks;
if ( shipp->flags & SF_PRIMARY_LINKED ) {
num_primary_banks = swp->num_primary_banks;
} else {
num_primary_banks = min(1, swp->num_primary_banks);
}
Assert(num_primary_banks > 0);
if (num_primary_banks < 1){
return 0;
}
// if we're firing stream weapons, but the trigger is not down, do nothing
if(stream_weapons && !(shipp->flags & SF_TRIGGER_DOWN)){
return 0;
}
for ( i = 0; i < num_primary_banks; i++ ) {
bank_to_fire = (swp->current_primary_bank+i)%2; // Max supported banks is 2
weapon = swp->primary_bank_weapons[bank_to_fire];
Assert( weapon >= 0 && weapon < MAX_WEAPONS );
if ( (weapon < 0) || (weapon >= MAX_WEAPON_TYPES) ) {
Int3(); // why would a ship try to fire a weapon that doesn't exist?
continue;
}
weapon_info* winfo_p = &Weapon_info[weapon];
// if this is a targeting laser, start it up ///- only targeting laser if it is tag-c, otherwise it's a fighter beam -Bobboau
if((winfo_p->wi_flags & WIF_BEAM) && (winfo_p->tag_level == 3) && (shipp->flags & SF_TRIGGER_DOWN) && (winfo_p->b_info.beam_type == BEAM_TYPE_C) ){
ship_start_targeting_laser(shipp);
}
// if we're firing stream weapons and this is a non stream weapon, skip it
if(stream_weapons && !(winfo_p->wi_flags & WIF_STREAM)){
continue;
}
// if we're firing non stream weapons and this is a stream weapon, skip it
if(!stream_weapons && (winfo_p->wi_flags & WIF_STREAM)){
continue;
}
// only non-multiplayer clients (single, multi-host) need to do timestamp checking
if ( !timestamp_elapsed(swp->next_primary_fire_stamp[bank_to_fire]) ) {
if (timestamp_until(swp->next_primary_fire_stamp[bank_to_fire]) > 5000){
swp->next_primary_fire_stamp[bank_to_fire] = timestamp(1000);
}
have_timeout = 1;
continue;
}
//nprintf(("AI", "Time = %7.3f, firing %s\n", f2fl(Missiontime), Weapon_info[weapon].name));
// do timestamp stuff for next firing time
float next_fire_delay = (float) winfo_p->fire_wait * 1000.0f;
if (!(obj->flags & OF_PLAYER_SHIP) ) {
if (shipp->team == Ships[Player_obj->instance].team){
next_fire_delay *= Ship_fire_delay_scale_friendly[Game_skill_level];
} else {
next_fire_delay *= Ship_fire_delay_scale_hostile[Game_skill_level];
}
}
next_fire_delay *= 1.0f + (num_primary_banks - 1) * 0.5f; // 50% time penalty if banks linked
// MK, 2/4/98: Since you probably were allowed to fire earlier, but couldn't fire until your frame interval
// rolled around, subtract out up to half the previous frametime.
// Note, unless we track whether the fire button has been held down, and not tapped, it's hard to
// know how much time to subtract off. It could be this fire is "late" because the user didn't want to fire.
if ((next_fire_delay > 0.0f)) {
if (obj->flags & OF_PLAYER_SHIP) {
int t = timestamp_until(swp->next_primary_fire_stamp[bank_to_fire]);
if (t < 0) {
float tx;
tx = (float) t/-1000.0f;
if (tx > flFrametime/2.0f){
tx = 1000.0f * flFrametime * 0.7f;
}
next_fire_delay -= tx;
}
if ((int) next_fire_delay < 1){
next_fire_delay = 1.0f;
}
}
swp->next_primary_fire_stamp[bank_to_fire] = timestamp((int)(next_fire_delay));
if ((winfo_p->wi_flags & WIF_BEAM) && (winfo_p->b_info.beam_type == BEAM_TYPE_C))// fighter beams fire constantly, they only stop if they run out of power -Bobboau
swp->next_primary_fire_stamp[bank_to_fire] = timestamp();
}
// Here is where we check if weapons subsystem is capable of firing the weapon.
// Note that we can have partial bank firing, if the weapons subsystem is partially
// functional, which should be cool.
if ( ship_weapon_maybe_fail(shipp) && !force) {
if ( obj == Player_obj ) {
if ( ship_maybe_play_primary_fail_sound() ) {
}
}
continue;
}
polymodel *po = model_get( Ship_info[shipp->ship_info_index].modelnum );
if ( po->n_guns > 0 ) {
int num_slots = po->gun_banks[bank_to_fire].num_slots;
if(winfo_p->wi_flags & WIF_BEAM){ // the big change I made for fighter beams, if there beams fill out the Fire_Info for a targeting laser then fire it, for each point in the weapon bank -Bobboau
// fail unless we're forcing (energy based primaries)
if ( (shipp->weapon_energy < num_slots*winfo_p->energy_consumed*flFrametime) && !force) {
swp->next_primary_fire_stamp[bank_to_fire] = timestamp(swp->next_primary_fire_stamp[bank_to_fire]);
if ( obj == Player_obj ) {
if ( ship_maybe_play_primary_fail_sound() ) {
}
}
continue;
}
// deplete the weapon reserve energy by the amount of energy used to fire the weapon and the number of points and do it by the time it's been fireing becase this is a beam -Bobboau
shipp->weapon_energy -= num_slots*winfo_p->energy_consumed*flFrametime;
beam_fire_info fbfire_info;
//int j = (timestamp()/100)%num_slots; // fireing point cycleing for TBP
for ( int j = 0; j < num_slots; j++ ){
fbfire_info.accuracy = 0.0f;
fbfire_info.beam_info_index = shipp->weapons.primary_bank_weapons[bank_to_fire];
fbfire_info.beam_info_override = NULL;
fbfire_info.shooter = &Objects[shipp->objnum];
fbfire_info.target = NULL;
fbfire_info.target_subsys = NULL;
fbfire_info.turret = NULL;
fbfire_info.targeting_laser_offset = po->gun_banks[bank_to_fire].pnt[j];
beam_fire_targeting(&fbfire_info);
//shipp->targeting_laser_objnum = beam_fire_targeting(&fire_info);
}
}else{ //if this insn't a fighter beam, do it normaly -Bobboau
//Assert (!(winfo_p->wi_flags & WIF_BEAM))
// fail unless we're forcing (energy based primaries)
if ( (shipp->weapon_energy < num_slots*winfo_p->energy_consumed) && !force) {
swp->next_primary_fire_stamp[bank_to_fire] = timestamp(swp->next_primary_fire_stamp[bank_to_fire]);
if ( obj == Player_obj ) {
if ( ship_maybe_play_primary_fail_sound() ) {
}
}
continue;
}
// deplete the weapon reserve energy by the amount of energy used to fire the weapon
shipp->weapon_energy -= num_slots*winfo_p->energy_consumed;
// Mark all these weapons as in the same group
int new_group_id = weapon_create_group_id();
for ( j = 0; j < num_slots; j++ ) {
pnt = po->gun_banks[bank_to_fire].pnt[j];
vm_vec_unrotate(&gun_point, &pnt, &obj->orient);
vm_vec_add(&firing_pos, &gun_point, &obj->pos);
// create the weapon -- the network signature for multiplayer is created inside
// of weapon_create
weapon_objnum = weapon_create( &firing_pos, &obj->orient, weapon, OBJ_INDEX(obj),0, new_group_id );
weapon_set_tracking_info(weapon_objnum, OBJ_INDEX(obj), aip->target_objnum, aip->current_target_is_locked, aip->targeted_subsys);
// create the muzzle flash effect
shipfx_flash_create( obj, shipp, &pnt, &obj->orient.fvec, 1, weapon );
// maybe shudder the ship - if its me
if((winfo_p->wi_flags & WIF_SHUDDER) && (obj == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
// calculate some arbitrary value between 100
// (mass * velocity) / 10
game_shudder_apply(500, (winfo_p->mass * winfo_p->max_speed) / 10.0f);
}
num_fired++;
}
}
if(shipp->weapon_energy < 0.0f){
shipp->weapon_energy = 0.0f;
}
banks_fired |= (1< // mark this bank as fired.
}
// Only play the weapon fired sound if it hasn't been played yet. This is to
// avoid playing the same sound multiple times when banks are linked with the
// same weapon.
if ( sound_played != winfo_p->launch_snd ) {
sound_played = winfo_p->launch_snd;
if ( obj == Player_obj ) {
if ( winfo_p->launch_snd != -1 ) {
weapon_info *wip;
ship_weapon *swp;
// HACK
if(winfo_p->launch_snd == SND_AUTOCANNON_SHOT){
snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_TRIPLE_INSTANCE );
} else {
snd_play( &Snds[winfo_p->launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
}
// snd_play( &Snds[winfo_p->launch_snd] );
swp = &Player_ship->weapons;
if (swp->current_primary_bank >= 0) {
wip = &Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]];
joy_ff_play_primary_shoot((int) ((wip->armor_factor + wip->shield_factor * 0.2f) * (wip->damage * wip->damage - 7.5f) * 0.45f + 0.6f) * 10 + 2000);
}
}
}
else {
if ( winfo_p->launch_snd != -1 ) {
snd_play_3d( &Snds[winfo_p->launch_snd], &obj->pos, &View_position );
}
}
}
} // end for (go to next primary bank)
// if multiplayer and we're client-side firing, send the packet
// if((Game_mode & GM_MULTIPLAYER) && (Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING)){
if(Game_mode & GM_MULTIPLAYER){
// if i'm a client, and this is not me, don't send
if(!(MULTIPLAYER_CLIENT && (shipp != Player_ship))){
send_NEW_primary_fired_packet( shipp, banks_fired );
}
}
// post a primary fired event
if(Game_mode & GM_DEMO_RECORD){
demo_POST_primary_fired(obj, swp->current_primary_bank, shipp->flags & SF_PRIMARY_LINKED);
}
// STATS
if (obj->flags & OF_PLAYER_SHIP) {
// in multiplayer -- only the server needs to keep track of the stats. Call the cool
// function to find the player given the object *. It had better return a valid player
// or our internal structure as messed up.
if( Game_mode & GM_MULTIPLAYER ) {
if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
int player_num;
player_num = multi_find_player_by_object ( obj );
Assert ( player_num != -1 );
Net_players[player_num].player->stats.mp_shots_fired += num_fired;
}
} else {
Player->stats.mp_shots_fired += num_fired;
}
}
return num_fired;
}