/**
 * Called when a ship disengages the afterburners.
 *
 * @param *objp			pointer to the object starting afterburners
 * @param key_released	OPTIONAL parameter (default value 0) This is only used for the player object, to manage starting/stopping
 */
void afterburners_stop(object *objp, int key_released)
{
	Assert( objp != NULL );
	Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
	
	ship_info *sip;
	ship *shipp;

	shipp = &Ships[objp->instance];

	Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
	sip = &Ship_info[shipp->ship_info_index];

	if ( (objp->flags[Object::Object_Flags::Player_ship]) && key_released ) {
		objp->phys_info.flags &= ~PF_AFTERBURNER_WAIT;
	}

	if ( !(sip->flags[Ship::Info_Flags::Afterburner]) )	{
		nprintf(("Warning","Ship type %s does not have afterburner capability\n", sip->name));
		return;
	}

	if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) {
		return;
	}

	Script_system.SetHookObjects(1, "Ship", objp);
	Script_system.RunCondition(CHA_AFTERBURNEND, 0, NULL, objp);
	Script_system.RemHookVars(1, "Ship");

	objp->phys_info.flags &= ~PF_AFTERBURNER_ON;

	//Do anim
	model_anim_start_type(shipp, TRIGGER_TYPE_AFTERBURNER, ANIMATION_SUBTYPE_ALL, -1);

	if ( objp == Player_obj ) {

		if ( !key_released ) {
			snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) );
		}

		if ( Player_afterburner_loop_id > -1 )	{
			Player_disengage_timer = timestamp(DISENGAGE_TIME);
		}

		joy_ff_afterburn_off();
	}
}
Example #2
0
void cmeasure_maybe_alert_success(object *objp)
{
	//Is this a countermeasure, and does it have a parent
	if ( objp->type != OBJ_WEAPON || objp->parent < 0) {
		return;
	}

	Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Cmeasure]);

	if ( objp->parent == OBJ_INDEX(Player_obj) ) {
		hud_start_text_flash(XSTR("Evaded", 1430), 800);
		snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)));
	} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
		send_countermeasure_success_packet( objp->parent );
	}
}
// target the next ship in the escort list
void hud_escort_target_next()
{
	int objnum;

	if ( Num_escort_ships == 0 ) {
		snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f );
		return;
	}

	Last_target_index++;
	if ( Last_target_index >= Num_escort_ships ) {
		Last_target_index = 0;
	}

	objnum = Escort_ships[Last_target_index].objnum;
	set_target_objnum( Player_ai,  objnum);
	hud_restore_subsystem_target(&Ships[Objects[objnum].instance]);
}
void HudGaugeRadarDradis::doLoopSnd()
{
	if (!this->m_loop_snd.isValid())
	{
		return;
	}

	if (!this->shouldDoSounds())
	{
		if (loop_sound_handle >= 0 && snd_is_playing(loop_sound_handle))
		{
			snd_stop(loop_sound_handle);
			loop_sound_handle = -1;
		}
	}
	else if (this->loop_sound_handle < 0 || !snd_is_playing(this->loop_sound_handle))
	{
		loop_sound_handle = snd_play(gamesnd_get_game_sound(m_loop_snd), 0.0f, loop_sound_volume);
	}
}
Example #5
0
/**
 * Start the sequence of a piece of debris writhing in unholy agony!!!
 */
static void debris_start_death_roll(object *debris_obj, debris *debris_p)
{
	if (debris_p->is_hull)	{
		// tell everyone else to blow up the piece of debris
		if( MULTIPLAYER_MASTER )
			send_debris_update_packet(debris_obj,DEBRIS_UPDATE_NUKE);

		int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]);
		if(fireball_type < 0) {
			fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS;
		}
		fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f);

		// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
		if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
			snd_play_3d( gamesnd_get_game_sound(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius );
			
		}
	}

    debris_obj->flags.set(Object::Object_Flags::Should_be_dead);
}
// ------------------------------------------------------------------
// hud_shield_equalize()
//
// Equalize all shield quadrants for an object
//
void hud_shield_equalize(object *objp, player *pl)
{
	float penalty;

	Assert(objp != NULL);
	if (objp == NULL)
		return;

	Assert(pl != NULL);
	if (pl == NULL)
		return;

	Assert(objp->type == OBJ_SHIP);
	if (objp->type != OBJ_SHIP)
		return;

	// Goober5000 - quick out if we have no shields
	if (objp->flags[Object::Object_Flags::No_shields])
		return;

	// maybe impose a 2% penalty - server side and single player only
	if (!MULTIPLAYER_CLIENT && ((pl->shield_penalty_stamp < 0) || timestamp_elapsed_safe(pl->shield_penalty_stamp, 1000)) ) {
		penalty = 0.02f;

		// reset the penalty timestamp
		pl->shield_penalty_stamp = timestamp(1000);

	} else {
		penalty = 0.0f;
	}

	shield_balance(objp, 1, penalty);

	// beep
	if (objp == Player_obj) {
		snd_play(gamesnd_get_game_sound(SND_SHIELD_XFER_OK));
	}
}
// ----------------------------------------------------------------------
// hud_add_remove_ship_escort()
//
void hud_add_remove_ship_escort(int objnum, int supress_feedback)
{
	int in_escort, i;

	// no ships on the escort list in multiplayer dogfight
	if(MULTI_DOGFIGHT){
		return;
	}

	if ( objnum < 0 ) {
		Int3();
		return;
	}

	if ( Objects[objnum].type != OBJ_SHIP ) {
		if ( !supress_feedback ) {
			snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
		}
		return;
	}

	in_escort = 0;
	for ( i = 0; i < Num_escort_ships; i++ ) {
		if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) {
			in_escort = 1;
			break;
		}
	}

	if ( in_escort ) {				
		hud_remove_ship_from_escort_index(i, objnum);
		return;
	}

	hud_add_ship_to_escort(objnum, supress_feedback);
}
Example #8
0
/**
 * Do various updates to debris:  check if time to die, start fireballs
 * Maybe delete debris if it's very far away from player.
 *
 * @param obj			pointer to debris object
 * @param frame_time	time elapsed since last debris_move() called
 */
void debris_process_post(object * obj, float frame_time)
{
	int i, num;
	num = obj->instance;

	int objnum = OBJ_INDEX(obj);
	Assert( Debris[num].objnum == objnum );
	debris *db = &Debris[num];

	if ( db->is_hull ) {
		MONITOR_INC(NumHullDebris,1);
		radar_plot_object( obj );

		if ( timestamp_elapsed(db->sound_delay) ) {
			obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
			db->sound_delay = 0;
		}
	} else {
		MONITOR_INC(NumSmallDebris,1);
	}

	if ( db->lifeleft >= 0.0f) {
		db->lifeleft -= frame_time;
		if ( db->lifeleft < 0.0f )	{
			debris_start_death_roll(obj, db);
		}
	}

	maybe_delete_debris(db);	//	Make this debris go away if it's very far away.

	// ================== DO THE ELECTRIC ARCING STUFF =====================
	if ( db->arc_frequency <= 0 )	{
		return;			// If arc_frequency <= 0, this piece has no arcs on it
	}

	if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball))	{		

		db->next_fireball = timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
		db->arc_frequency += 100;	

		if (db->is_hull)	{

			int n, n_arcs = ((rand()>>5) % 3)+1;		// Create 1-3 sparks

			vec3d v1, v2, v3, v4;

			if ( Cmdline_old_collision_sys ) {
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 );
			} else {
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 );
			}

			n = 0;

			int a = 100, b = 1000;
			int lifetime = (myrand()%((b)-(a)+1))+(a);

			// Create the spark effects
			for (i=0; i<MAX_DEBRIS_ARCS; i++ )	{
				if ( !timestamp_valid( db->arc_timestamp[i] ) )	{

					db->arc_timestamp[i] = timestamp(lifetime);	// live up to a second

					switch( n )	{
					case 0:
						db->arc_pts[i][0] = v1;
						db->arc_pts[i][1] = v2;
						break;
					case 1:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v3;
						break;

					case 2:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v4;
						break;

					default:
						Int3();
					}
						
					n++;
					if ( n == n_arcs )
						break;	// Don't need to create anymore
				}
			}

	
			// rotate v2 out of local coordinates into world.
			// Use v2 since it is used in every bolt.  See above switch().
			vec3d snd_pos;
			vm_vec_unrotate(&snd_pos, &v2, &obj->orient);
			vm_vec_add2(&snd_pos, &obj->pos );

			//Play a sound effect
			if ( lifetime > 750 )	{
				// 1.00 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  500 )	{
				// 0.75 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  250 )	{
				// 0.50 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  100 )	{
				// 0.25 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
			} else {
				// 0.10 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
			}
		}
void shield_transfer(object *objp, int quadrant, float rate) {
	Assert(objp);
	Assert(objp->type == OBJ_SHIP);

	Assert(quadrant >= 0 && quadrant < objp->n_quadrants);
	Assert((0.0f < rate) && (rate <= 1.0f));

	// The energy to Xfer to the quadrant
	float xfer_amount = shield_get_max_strength(objp) * rate;

	// The max amount of energy a quad can have
	float max_quadrant_val = shield_get_max_quad(objp);

	if ((objp->shield_quadrant[quadrant] + xfer_amount) > max_quadrant_val) {
		xfer_amount = max_quadrant_val - objp->shield_quadrant[quadrant];
	}

	Assert(xfer_amount >= 0);
	if (xfer_amount == 0) {
		// TODO: provide a feedback sound
		return;
	
	} else if (objp == Player_obj) {
		snd_play(gamesnd_get_game_sound(SND_SHIELD_XFER_OK));
	}

	float energy_avail = 0.0f;	// Energy available from the other quadrants that we can transfer

	for (int i = 0; i < objp->n_quadrants; i++) {
		if (i == quadrant)
			continue;
		energy_avail += objp->shield_quadrant[i];
	}

	// Percent energy to take from each quadrant
	float percent_to_take = xfer_amount / energy_avail;

	if (percent_to_take > 1.0f) {
		percent_to_take = 1.0f;
	}

	for (int i = 0; i < objp->n_quadrants; i++) {
		float delta;

		if (i == quadrant) {
			// Don't take energy from our target
			continue;
		}

		delta = percent_to_take * objp->shield_quadrant[i];
		objp->shield_quadrant[i] -= delta;

		Assert(objp->shield_quadrant[i] >= 0);

		objp->shield_quadrant[quadrant] += delta;

		if (objp->shield_quadrant[quadrant] > max_quadrant_val) {
			// Already reached the max quadrant value. Clamp and bail before losing more any energy.
			objp->shield_quadrant[quadrant] = max_quadrant_val;
			break;
		}
	}
}
/**
 * Called when a ship engages the afterburners.
 * This function should only be called once when afterburners first start.  This is
 * to start an appropriate sound effect and do any one-time initializations.
 *
 * @param *objp pointer to the object starting afterburners
 */          
void afterburners_start(object *objp)
{
	ship_info	*sip;
	ship			*shipp;
	float			percent_left;

	Assert( objp != NULL );

	if(objp->type == OBJ_OBSERVER)
		return;

	Assert( objp->type == OBJ_SHIP);
	Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );

	shipp = &Ships[objp->instance];
	Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
	sip = &Ship_info[shipp->ship_info_index];
	
	// bail if afterburners are locked
	if (shipp->flags[Ship::Ship_Flags::Afterburner_locked])	{
		return;
	}

	if ( (objp->flags[Object::Object_Flags::Player_ship]) && (objp == Player_obj) ) {
		unsigned int now;
		now = timer_get_milliseconds();

		if ( (now - Player_afterburner_start_time) < 1300 ) {
			snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) );
			return;
		}

		if ( objp->phys_info.flags & PF_AFTERBURNER_WAIT ){
			return;
		}
	}

	if ( objp->phys_info.flags & PF_AFTERBURNER_ON )	{
		return;		// afterburners are already engaged, nothing to do here
	}

	//boosters take precedence
	if (objp->phys_info.flags & PF_BOOSTER_ON)
		return;	
	    
	if ( !(sip->flags[Ship::Info_Flags::Afterburner]) )	{
		return;
	}

	// Check if there is enough afterburner fuel
	if ( (shipp->afterburner_fuel < MIN_AFTERBURNER_FUEL_TO_ENGAGE) && !MULTIPLAYER_CLIENT ) {
		if ( objp == Player_obj ) {
			snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) );
		}
		return;
	}

	objp->phys_info.flags |= PF_AFTERBURNER_ON;

	objp->phys_info.afterburner_decay = timestamp(ABURN_DECAY_TIME);

	percent_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity;

	//Do anim
	model_anim_start_type(shipp, TRIGGER_TYPE_AFTERBURNER, ANIMATION_SUBTYPE_ALL, 1);

	if ( objp == Player_obj ) {
		Player_afterburner_start_time = timer_get_milliseconds();
		Player_disengage_timer = 1;
		Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL;

		if ( percent_left > AFTERBURNER_PERCENT_FOR_LOOP_SND ) {
			Player_afterburner_loop_delay = timestamp(AFTERBURNER_LOOP_DELAY);
		}
		else {
			Player_afterburner_loop_delay = 0;
		}

		snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_ENGAGE)), 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
		joy_ff_afterburn_on();
	} else {
		snd_play_3d( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_ENGAGE)), &objp->pos, &View_position, objp->radius );
	}

	Script_system.SetHookObjects(1, "Ship", objp);
	Script_system.RunCondition(CHA_AFTERBURNSTART, 0, NULL, objp);
	Script_system.RemHookVars(1, "Ship");
	
	objp->phys_info.flags |= PF_AFTERBURNER_WAIT;
}
/**
 * Update the state of the afterburner fuel remaining for an object using the afterburner.  
 *
 * For the player ship, key_up_time() is called for the afterburner key to
 * detect when afterburners disengage.
 *
 * @param *objp			pointer to the object starting afterburners
 * @param fl_frametime	time in seconds of the last frame
 */
void afterburners_update(object *objp, float fl_frametime)
{
	Assert( objp != NULL );
	Assert( objp->type == OBJ_SHIP );
	Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS );
	
	ship_info *sip;
	ship *shipp;
	static int volume_chg_timer = 1;

	shipp = &Ships[objp->instance];

	Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) );
	sip = &Ship_info[shipp->ship_info_index];

	if ( (objp->flags[Object::Object_Flags::Player_ship] ) && (Game_mode & GM_DEAD) ) {
		return;
	}

	if ( !(sip->flags[Ship::Info_Flags::Afterburner]) )	{
		return;		// nothing to update, afterburners are not even on the ship
	}

	//shut the afterburners off if we're using the booster tertiary
	if ( objp->phys_info.flags & PF_BOOSTER_ON)
	{
		if (objp==Player_obj) afterburner_stop_sounds();
		afterburners_stop(objp);
		return;
	}

	if ( objp == Player_obj ) {
		if ( !timestamp_elapsed(Player_disengage_timer) ) {
			float remaining;
			remaining = timestamp_until(Player_disengage_timer) / i2fl(DISENGAGE_TIME);
			if ( remaining <= 0 ) {
				afterburner_stop_sounds();
			}
			else {
				snd_set_volume( Player_afterburner_loop_id, remaining*Player_afterburner_vol);
			}
		}
		else {
			if ( Player_disengage_timer != 1 ) {
				afterburner_stop_sounds();
			}
		}
	}

	// single player, multiplayer servers, and clients for their own ships
	if(!(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_MASTER || (objp == Player_obj)) {
		if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) {
			// Recover afterburner fuel

			if ( shipp->afterburner_fuel < sip->afterburner_fuel_capacity ) {
				float recharge_scale;
				recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level];
				shipp->afterburner_fuel += (sip->afterburner_recover_rate * fl_frametime * recharge_scale);

				if ( shipp->afterburner_fuel >  sip->afterburner_fuel_capacity){
					shipp->afterburner_fuel = sip->afterburner_fuel_capacity;
				}
			}
			return;
		} else {
			// Check if there is enough afterburner fuel
			if ( shipp->afterburner_fuel <= 0 ) {
				shipp->afterburner_fuel = 0.0f;
				afterburners_stop(objp);
				return;
			}
		}

		// afterburners are firing at this point

		// Reduce the afterburner fuel
		shipp->afterburner_fuel -= (sip->afterburner_burn_rate * fl_frametime);
		if ( shipp->afterburner_fuel < 0.0f ) {
			shipp->afterburner_fuel = 0.0f;
		}
	}

	if ( objp == Player_obj ) {
		if ( timestamp_elapsed(Player_afterburner_loop_delay) ) {
			Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL;
			Player_afterburner_loop_delay = 0;
			if ( Player_afterburner_loop_id == -1 ) {
				Player_afterburner_loop_id = snd_play_looping( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_LOOP)), 0.0f , -1, -1);
				snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol);
			}
		}

		// Reduce the volume of the afterburner sound if near the end
		if ( timestamp_elapsed(volume_chg_timer) ) {
			float percent_afterburner_left;
			percent_afterburner_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity;
			volume_chg_timer = timestamp(AFTERBURNER_VOLUME_UPDATE);
			if ( percent_afterburner_left < AFTERBURNER_PERCENT_VOL_ATTENUATE ) {
				Player_afterburner_vol = percent_afterburner_left*(1/AFTERBURNER_PERCENT_VOL_ATTENUATE)*AFTERBURNER_DEFAULT_VOL;
				snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol);
			}
		}	// end if (timestamp_elapsed(volume_chg_timer))
	}
}
Example #12
0
// hud_calculate_lock_position()  will determine where on the screen to draw the lock 
// indicator, and will determine when a lock has occurred.  If the lock indicator is not
// on the screen yet, hud_calculate_lock_start_pos() is called to pick a starting location
void hud_calculate_lock_position(float frametime)
{
	ship_weapon *swp;
	weapon_info	*wip;

	static float pixels_moved_while_locking;
	static float pixels_moved_while_degrading;
	static int Need_new_start_pos = 0;

	static double accumulated_x_pixels, accumulated_y_pixels;
	double int_portion;

	static float last_dist_to_target;
	
	static int catching_up;

	static int maintain_lock_count = 0;

	static float catch_up_distance = 0.0f;

	double hypotenuse, delta_x, delta_y;

	swp = &Player_ship->weapons;
	wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];

	if (Player->target_in_lock_cone) {
		if (!Players[Player_num].lock_indicator_visible) {
			hud_calculate_lock_start_pos();
			last_dist_to_target = 0.0f;

			Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x;
			Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y;
			Players[Player_num].lock_indicator_visible = 1;

			Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time);
			catching_up = 0;
		}

		Need_new_start_pos = 1;

		if (Player_ai->current_target_is_locked) {
			Players[Player_num].lock_indicator_x = Player->current_target_sx;
			Players[Player_num].lock_indicator_y = Player->current_target_sy;
			return;
		}

		delta_x = Players[Player_num].lock_indicator_x - Player->current_target_sx;
		delta_y = Players[Player_num].lock_indicator_y - Player->current_target_sy;

		if (!delta_y && !delta_x) {
			hypotenuse = 0;
		}
		else {
			hypotenuse = _hypot(delta_y, delta_x);
		}

		Players[Player_num].lock_dist_to_target = (float)hypotenuse;

		if (last_dist_to_target == 0) {
			last_dist_to_target = Players[Player_num].lock_dist_to_target;
		}

		//nprintf(("Alan","dist to target: %.2f\n",Players[Player_num].lock_dist_to_target));
		//nprintf(("Alan","last to target: %.2f\n\n",last_dist_to_target));

		if (catching_up) {
			//nprintf(("Alan","IN CATCH UP MODE  catch_up_dist is %.2f\n",catch_up_distance));	
			if ( Players[Player_num].lock_dist_to_target < catch_up_distance )
				catching_up = 0;
		}
		else {
			//nprintf(("Alan","IN NORMAL MODE\n"));
			if ( (Players[Player_num].lock_dist_to_target - last_dist_to_target) > 2.0f ) {
				catching_up = 1;
				catch_up_distance = last_dist_to_target + wip->catchup_pixel_penalty;
			}
		}

		last_dist_to_target = Players[Player_num].lock_dist_to_target;

		if (!catching_up) {
			Players[Player_num].lock_time_to_target -= frametime;
			if (Players[Player_num].lock_time_to_target < 0.0f)
				Players[Player_num].lock_time_to_target = 0.0f;
		}

		float lock_pixels_per_sec;
		if (Players[Player_num].lock_time_to_target > 0) {
			lock_pixels_per_sec = Players[Player_num].lock_dist_to_target / Players[Player_num].lock_time_to_target;
		} else {
			lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec);
		}

		if (lock_pixels_per_sec > wip->lock_pixels_per_sec) {
			lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec);
		}
		
		if (catching_up) {
			pixels_moved_while_locking = wip->catchup_pixels_per_sec * frametime;
		} else {
			pixels_moved_while_locking = lock_pixels_per_sec * frametime;
		}
		
		if ((delta_x != 0) && (hypotenuse != 0)) {
			accumulated_x_pixels += pixels_moved_while_locking * delta_x/hypotenuse; 
		}

		if ((delta_y != 0) && (hypotenuse != 0)) {
			accumulated_y_pixels += pixels_moved_while_locking * delta_y/hypotenuse; 
		}

		if (fl_abs((float)accumulated_x_pixels) > 1.0f) {
			modf(accumulated_x_pixels, &int_portion);

			Players[Player_num].lock_indicator_x -= (int)int_portion;

			if ( fl_abs((float)Players[Player_num].lock_indicator_x - (float)Player->current_target_sx) < fl_abs((float)int_portion) )
				Players[Player_num].lock_indicator_x = Player->current_target_sx;

			accumulated_x_pixels -= int_portion;
		}

		if (fl_abs((float)accumulated_y_pixels) > 1.0f) {
			modf(accumulated_y_pixels, &int_portion);

			Players[Player_num].lock_indicator_y -= (int)int_portion;

			if ( fl_abs((float)Players[Player_num].lock_indicator_y - (float)Player->current_target_sy) < fl_abs((float)int_portion) )
				Players[Player_num].lock_indicator_y = Player->current_target_sy;

			accumulated_y_pixels -= int_portion;
		}

		if ( Missile_track_loop == -1 ) {
			if (wip->hud_tracking_snd.isValid())
			{
				Missile_track_loop = snd_play_looping( gamesnd_get_game_sound(wip->hud_tracking_snd), 0.0f , -1, -1);
			}
			else
			{
				Missile_track_loop = snd_play_looping( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_TRACKING)), 0.0f , -1, -1);
			}
		}

		if (!Players[Player_num].lock_time_to_target) {
			if ( (Players[Player_num].lock_indicator_x == Player->current_target_sx) && (Players[Player_num].lock_indicator_y == Player->current_target_sy) ) {
				if (maintain_lock_count++ > 1) {
					Player_ai->current_target_is_locked = 1;
				}
			} else {
				maintain_lock_count = 0;
			}
		}

	} else {

		if ( Missile_track_loop > -1 )	{
			snd_stop(Missile_track_loop);
			Missile_track_loop = -1;
		}

		Player_ai->current_target_is_locked = 0;

		if (!Players[Player_num].lock_indicator_visible) {
			return;
		}

		catching_up = 0;
		last_dist_to_target = 0.0f;

		if (Need_new_start_pos) {
			hud_calculate_lock_start_pos();
			Need_new_start_pos = 0;
			accumulated_x_pixels = 0.0f;
			accumulated_y_pixels = 0.0f;
		}

		delta_x = Players[Player_num].lock_indicator_x - Players[Player_num].lock_indicator_start_x;
		delta_y = Players[Player_num].lock_indicator_y - Players[Player_num].lock_indicator_start_y;

		if (!delta_y && !delta_x) {
			hypotenuse = 0;
		}
		else {
			hypotenuse = _hypot(delta_y, delta_x);
		}

		Players[Player_num].lock_time_to_target += frametime;

		if (Players[Player_num].lock_time_to_target > wip->min_lock_time)
			Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time);

		pixels_moved_while_degrading = 2.0f * wip->lock_pixels_per_sec * frametime;

		if ((delta_x != 0) && (hypotenuse != 0))
			accumulated_x_pixels += pixels_moved_while_degrading * delta_x/hypotenuse; 

		if ((delta_y != 0) && (hypotenuse != 0))
			accumulated_y_pixels += pixels_moved_while_degrading * delta_y/hypotenuse; 

		if (fl_abs((float)accumulated_x_pixels) > 1.0f) {
			modf(accumulated_x_pixels, &int_portion);

			Players[Player_num].lock_indicator_x -= (int)int_portion;

			if ( fl_abs((float)Players[Player_num].lock_indicator_x - (float)Players[Player_num].lock_indicator_start_x) < fl_abs((float)int_portion) )
				Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x;

			accumulated_x_pixels -= int_portion;
		}

		if (fl_abs((float)accumulated_y_pixels) > 1.0f) {
			modf(accumulated_y_pixels, &int_portion);

			Players[Player_num].lock_indicator_y -= (int)int_portion;

			if ( fl_abs((float)Players[Player_num].lock_indicator_y - (float)Players[Player_num].lock_indicator_start_y) < fl_abs((float)int_portion) )
				Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y;

			accumulated_y_pixels -= int_portion;
		}

		if ( (Players[Player_num].lock_indicator_x == Players[Player_num].lock_indicator_start_x) && (Players[Player_num].lock_indicator_y == Players[Player_num].lock_indicator_start_y) ) {
			Players[Player_num].lock_indicator_visible = 0;
		}
	}
}
Example #13
0
// hud_do_lock_indicator() manages missle locking, both the non-rendering calculations and the 2D HUD rendering
void hud_do_lock_indicator(float frametime)
{
	ship_weapon *swp;
	weapon_info	*wip;

	// if i'm a multiplayer observer, bail here
	if((Game_mode & GM_MULTIPLAYER) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
		return;
	}

	Assert(Player_ai->target_objnum >= 0);

	// be sure to unset this flag, then possibly set later in this function so that
	// threat indicators work properly.
	Player_ai->ai_flags.remove(AI::AI_Flags::Seek_lock);

	if ( hud_abort_lock() ) {
		hud_lock_reset();
		return;
	}

	// if there is an EMP effect active, never update lock
	if(emp_active_local()){
		hud_lock_reset();
		return;
	}

	swp = &Player_ship->weapons;
	wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];

	Lock_start_dist = wip->min_lock_time * wip->lock_pixels_per_sec;

	// if secondary weapons change, reset the lock
	if ( hud_lock_secondary_weapon_changed(swp) ) {
		hud_lock_reset();
	}
		
	Player_ai->last_secondary_index = swp->current_secondary_bank;

	object *tobjp = &Objects[Player_ai->target_objnum];
	vec3d dir_to_target;
	vm_vec_normalized_dir(&dir_to_target, &tobjp->pos, &Player_obj->pos);

	if ( !(wip->is_locked_homing()) ) {
		hud_lock_reset();
		return;		
	}

	// Allow locking on ships and bombs (only targeted weapon allowed is a bomb, so don't bother checking flags)
	if ( (Objects[Player_ai->target_objnum].type != OBJ_SHIP) && (Objects[Player_ai->target_objnum].type != OBJ_WEAPON) ) {	
		hud_lock_reset();
		return;
	}

	// Javelins must lock on engines if locking on a ship and those must be in sight
	if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && 
		tobjp->type == OBJ_SHIP &&
		Player->locking_subsys != NULL) {
			vec3d subobj_pos;
			vm_vec_unrotate(&subobj_pos, &Player->locking_subsys->system_info->pnt, &tobjp->orient);
			vm_vec_add2(&subobj_pos, &tobjp->pos);
			int target_subsys_in_sight = ship_subsystem_in_sight(tobjp, Player->locking_subsys, &Player_obj->pos, &subobj_pos);

			if (!target_subsys_in_sight || Player->locking_subsys->system_info->type != SUBSYSTEM_ENGINE) {
				Player->locking_subsys =
					ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);
			}
	}

	if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && 
		tobjp->type == OBJ_SHIP &&
		Player->locking_subsys == NULL) {
			Player->locking_subsys =
				ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);

			if (Player->locking_subsys == NULL) {
				hud_lock_reset();
				return;
			}
	}

	hud_lock_determine_lock_point(&lock_world_pos);

	if ( !hud_lock_has_homing_point() ) {
		Player->target_in_lock_cone=0;
	}

	hud_lock_check_if_target_in_lock_cone();

	// check if the target is within range of the current secondary weapon.  If it is not,
	// a lock will not be detected
	if ( !hud_lock_target_in_range() ) {
		Player->target_in_lock_cone = 0;
	}

	// If locking on a subsystem, and not in sight... can't lock
	//	Changed by MK on 4/3/98.  It was confusing me that my hornets would not lock on my target.
	//	It will now be confusing that they lock, but don't home on your subsystem, but I think that's preferable.
	//	Often you really care about destroying the target, not just the subsystem.
	/*if ( Player_ai->targeted_subsys ) {
		if ( !hud_lock_on_subsys_ok() ) {
			Player->target_in_lock_cone=0;
		}
	}*/

	if ( !Player->target_in_lock_cone ) {
		Player->locking_on_center=0;
		Player->locking_subsys_parent=-1;
		Player->locking_subsys=NULL;
	}
		
	hud_calculate_lock_position(frametime);

	if (!Players[Player_num].lock_indicator_visible)
		return;

	if (Player_ai->current_target_is_locked) {
		if ( Missile_track_loop > -1 )	{
			snd_stop(Missile_track_loop);
			Missile_track_loop = -1;

			if (wip->hud_locked_snd.isValid())
			{
				Missile_lock_loop = snd_play(gamesnd_get_game_sound(wip->hud_locked_snd));
			}
			else
			{
				Missile_lock_loop = snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_LOCK)));
			}
		}
	}
	else {
		Player_ai->ai_flags.set(AI::AI_Flags::Seek_lock);		// set this flag so multiplayer's properly track lock on other ships
		if ( Missile_lock_loop != -1 && snd_is_playing(Missile_lock_loop) ) {
			snd_stop(Missile_lock_loop);
			Missile_lock_loop = -1;
		}
	}
}
void HudGaugeRadarDradis::doBeeps()
{
	if (!this->shouldDoSounds())
	{
		return;
	}

	if (Missiontime == 0 || Missiontime == Frametime)
	{
		// don't play sounds in first frame
		return;
	}

	if (!arrival_beep_snd.isValid() &&
		!departure_beep_snd.isValid() &&
		!m_stealth_arrival_snd.isValid() &&
		!stealth_departure_snd.isValid())
	{
		return;
	}

	bool departure_happened = false;
	bool stealth_departure_happened = false;

	bool arrival_happened = false;
	bool stealth_arrival_happened = false;
	
	for (int i = 0; i < MAX_SHIPS; i++)
	{
		ship * shipp = &Ships[i];

		if (shipp->objnum >= 0)
		{
			if (shipp->radar_visible_since >= 0 || shipp->radar_last_contact >= 0)
			{
				if (shipp->radar_visible_since == Missiontime)
				{
					if (shipp->radar_current_status == DISTORTED)
					{
						stealth_arrival_happened = true;
					}
					else
					{
						arrival_happened = true;
					}
				}
				else if (shipp->radar_visible_since < 0 && shipp->radar_last_contact == Missiontime)
				{
					if (shipp->radar_last_status == DISTORTED)
					{
						stealth_departure_happened = true;
					}
					else
					{
						departure_happened = true;
					}
				}
			}
		}
	}
	
	if (timestamp_elapsed(arrival_beep_next_check))
	{
		if (arrival_beep_snd.isValid() && arrival_happened)
		{
			snd_play(gamesnd_get_game_sound(arrival_beep_snd));

			arrival_beep_next_check = timestamp(arrival_beep_delay);
		}
		else if (m_stealth_arrival_snd.isValid() && stealth_arrival_happened)
		{
			snd_play(gamesnd_get_game_sound(m_stealth_arrival_snd));

			arrival_beep_next_check = timestamp(arrival_beep_delay);
		}

	}

	if (timestamp_elapsed(departure_beep_next_check))
	{
		if (departure_beep_snd.isValid() && departure_happened)
		{
			snd_play(gamesnd_get_game_sound(departure_beep_snd));

			departure_beep_next_check = timestamp(departure_beep_delay);
		}
		else if (stealth_departure_snd.isValid() && stealth_departure_happened)
		{
			snd_play(gamesnd_get_game_sound(stealth_departure_snd));

			departure_beep_next_check = timestamp(departure_beep_delay);
		}
	}
}
void HudGaugeRadarDradis::render(float  /*frametime*/)
{
	float sensors_str;
	int   ok_to_blit_radar;
	
	ok_to_blit_radar = 1;

	sensors_str = ship_get_subsystem_strength(Player_ship, SUBSYSTEM_SENSORS);

	if (ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS))
		sensors_str = MIN_SENSOR_STR_TO_RADAR - 1;

	// note that on lowest skill level, there is no radar effects due to sensors damage
	if ((Game_skill_level == 0) || (sensors_str > SENSOR_STR_RADAR_NO_EFFECTS))
	{
		Radar_static_playing = 0;
		Radar_static_next = 0;
		Radar_death_timer = 0;
		Radar_avail_prev_frame = 1;
	}
	else
		if (sensors_str < MIN_SENSOR_STR_TO_RADAR)
		{
			if (Radar_avail_prev_frame)
			{
				Radar_death_timer = timestamp(2000);
				Radar_static_next = 1;
			}

			Radar_avail_prev_frame = 0;
		}
		else
		{
			Radar_death_timer = 0;

			if (Radar_static_next == 0)
				Radar_static_next = 1;
		}

	if (timestamp_elapsed(Radar_death_timer))
		ok_to_blit_radar = 0;

	setupViewHtl();

	//WMC - This strikes me as a bit hackish
	bool g3_yourself = !g3_in_frame();
	if(g3_yourself)
		g3_start_frame(1);

	drawSweeps();

	if (timestamp_elapsed(Radar_static_next))
	{
		Radar_static_playing ^= 1;
		Radar_static_next = timestamp_rand(50, 750);
	}

	// if the emp effect is active, always draw the radar wackily
	if (emp_active_local())
		Radar_static_playing = 1;

	if (ok_to_blit_radar)
	{
		if (Radar_static_playing)
		{
			drawBlipsSorted(1);	// passing 1 means to draw distorted

			if (Radar_static_looping == -1)
				Radar_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC));
		}
		else
		{
			drawBlipsSorted(0);

			if (Radar_static_looping != -1)
			{
				snd_stop(Radar_static_looping);
				Radar_static_looping = -1;
			}
		}
	}
	else
	{
		if (Radar_static_looping != -1)
		{
			snd_stop(Radar_static_looping);
			Radar_static_looping = -1;
		}
	}

	if(g3_yourself)
		g3_end_frame();

	doneDrawingHtl();
}
// try to add a ship to the escort list, if slot available
void hud_add_ship_to_escort(int objnum, int supress_feedback)
{
	escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST];
	int num_complete_escorts, idx, found;

	// get complete escort list
	hud_create_complete_escort_list(complete_escorts, &num_complete_escorts);

    // ensure the complete escort list is not full already
    if (num_complete_escorts == MAX_COMPLETE_ESCORT_LIST)
    {
        return;
    }

	// check if ship is already on complete escort list
	found = 0;
	for (idx=0; idx<num_complete_escorts; idx++) {
		if (complete_escorts[idx].obj_signature == Objects[objnum].signature) {
			found = 1;
			break;
		}
	}

	// add new ship into complete list
	if ( !found ) {
		complete_escorts[num_complete_escorts].objnum = objnum;
		complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature;
		complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority;
		complete_escorts[num_complete_escorts].escort_hit_timer = 0;
		complete_escorts[num_complete_escorts].escort_hit_next_flash = 0;
		complete_escorts[num_complete_escorts].escort_show_bright = false;

		// add him to escort list
        Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort);

		num_complete_escorts++;
	}

	// sort escort list by priority
	insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func);

	// merge list
	merge_escort_lists(complete_escorts, num_complete_escorts);

	// maybe do feedback
	if ( (Num_escort_ships == Max_escort_ships) && !supress_feedback) {
		found = 0;
		// search thru list for objnum
		for (idx=0; idx<Num_escort_ships; idx++) {
			if (Escort_ships[idx].objnum == objnum) {
				found = 1;
				break;
			}
		}

		if (!found) {
			HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships);
			snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL));
		}
	}

	hud_gauge_popup_start(HUD_ESCORT_VIEW);
}