Beispiel #1
0
void update_aircraft_weapon_fire (entity *en)
{
   aircraft
      *raw;

	ASSERT (en);

	ASSERT (get_comms_model () == COMMS_MODEL_SERVER);

   raw = get_local_entity_data (en);

	if (raw->weapon_burst_timer > 0.0)
	{
		//
		// check valid selected weapon
		//

		if (raw->selected_weapon == ENTITY_SUB_TYPE_WEAPON_NO_WEAPON)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->selected_weapon);

			raw->weapon_burst_timer = 0.0;

			return;
		}

		//
		// check selected weapon is ready
		//

		if (!raw->selected_weapon_system_ready)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->selected_weapon);

			raw->weapon_burst_timer = 0.0;

			return;
		}

		//
		// check valid target
		//

		if (!raw->mob.target_link.parent)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->selected_weapon);

			raw->weapon_burst_timer = 0.0;

			return;
		}
	
		//
		// fire weapon
		//

		launch_client_server_weapon (en, raw->selected_weapon);

		//
		// update burst timer
		//
		
		raw->weapon_burst_timer -= get_delta_time ();

		if (raw->weapon_burst_timer <= 0.0)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->selected_weapon);

			raw->weapon_burst_timer = 0.0;

			return;
		}
	}
}
Beispiel #2
0
void update_anti_aircraft_weapon_fire (entity *en)
{
   anti_aircraft
      *raw;

	int
		continue_burst_fire;

	float
		launch_angle_error;

	vec3d
		*weapon_vector,
		*weapon_to_target_vector;

	ASSERT (en);

	ASSERT (get_comms_model () == COMMS_MODEL_SERVER);

   raw = get_local_entity_data (en);

	//
	// check valid selected weapon
	//

	if (raw->vh.selected_weapon == ENTITY_SUB_TYPE_WEAPON_NO_WEAPON)
	{
		raw->vh.weapon_burst_timer = 0.0;

		return;
	}

	//
	// check selected weapon is ready
	//

	if (!raw->vh.selected_weapon_system_ready)
	{
		if (raw->vh.weapon_burst_timer > 0.0)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon);
		}

		return;
	}

	//
	// check valid target
	//

	if (!raw->vh.mob.target_link.parent)
	{
		if (raw->vh.weapon_burst_timer > 0.0)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon);
		}

		return;
	}

	//
	// check within max launch angle error
	//

	if (!get_local_entity_int_value (en, INT_TYPE_WEAPON_AND_TARGET_VECTORS_VALID))
	{
		if (raw->vh.weapon_burst_timer > 0.0)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon);
		}

		return;
	}

	weapon_vector = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_WEAPON_VECTOR);

	ASSERT (weapon_vector);

	weapon_to_target_vector = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_WEAPON_TO_TARGET_VECTOR);

	ASSERT (weapon_to_target_vector);

	launch_angle_error = acos (get_3d_unit_vector_dot_product (weapon_vector, weapon_to_target_vector));

	if (fabs (launch_angle_error) > weapon_database[raw->vh.selected_weapon].max_launch_angle_error)
	{
		if (raw->vh.weapon_burst_timer > 0.0)
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon);
		}

		return;
	}

	//
	// update burst
	//

	continue_burst_fire = FALSE;

	if (raw->vh.weapon_burst_timer > 0.0)
	{
		raw->vh.weapon_burst_timer -= get_delta_time ();

		if (raw->vh.weapon_burst_timer > 0.0)
		{
			continue_burst_fire = TRUE;
		}
		else
		{
			pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon);
		}
	}

	//
	// fire weapon
	//

	if (raw->vh.ready_to_fire || continue_burst_fire)
	{
		if (!get_local_entity_int_value (get_session_entity (), INT_TYPE_SUPPRESS_AI_FIRE))
		{
			launch_client_server_weapon (en, raw->vh.selected_weapon);
		}
	}
}
Beispiel #3
0
static void update_client (entity *en)
{
	helicopter
		*raw;

	int
		loop;

	aircraft_damage_types
		damage_type;

	raw = get_local_entity_data (en);

	update_local_entity_view_interest_level (en);

	update_local_helicopter_rotor_sounds (en);

	damage_type = aircraft_critically_damaged (en);

	if (raw->ac.mob.alive)
	{
		switch (raw->player)
		{
			////////////////////////////////////////
			case ENTITY_PLAYER_AI:
			////////////////////////////////////////
			{

				////////////////////////////////////////

				for (loop = 0; loop < get_entity_movement_iterations (); loop ++)
				{

					if ((damage_type == AIRCRAFT_DAMAGE_CRITICAL) || (get_local_entity_int_value (en, INT_TYPE_EJECTED)))
					{

						helicopter_death_movement (en);
					}
					else
					{

						if (!get_local_entity_int_value (en, INT_TYPE_LANDED))
						{

							get_3d_terrain_point_data (raw->ac.mob.position.x, raw->ac.mob.position.z, &raw->ac.terrain_info);
						}

						helicopter_movement (en);
					}
				}

				////////////////////////////////////////

				////////////////////////////////////////
				//
				// ORDER IS CRITICAL
				//

				if (raw->ac.mob.alive)
				{
					update_rotors (en);

					update_aircraft_loading_doors (en);

					update_aircraft_cargo_doors (en);

					update_aircraft_undercarriage (en);

					update_aircraft_weapon_system_ready (en);

					update_entity_weapon_systems (en);

					update_entity_weapon_system_weapon_and_target_vectors (en);
				}

				//
				////////////////////////////////////////

				break;
			}
			////////////////////////////////////////
			case ENTITY_PLAYER_LOCAL:
			////////////////////////////////////////
			{

				if (en != get_gunship_entity ())
				{

					//
					// Client might be waiting for server to set old gunship to AI controlled.
					//

					return;
				}

				if (raw->invulnerable_timer > 0.0)
				{

					raw->invulnerable_timer -= get_delta_time ();
				}

				update_current_flight_dynamics_fuel_weight ();

				if ((!fire_continuous_weapon) && (get_local_entity_sound_type_valid (en, weapon_database [raw->ac.selected_weapon].launch_sound_effect_sub_type)))
				{
					pause_client_server_continuous_weapon_sound_effect (en, raw->ac.selected_weapon);
				}

				//helicopter_death_movement (en);
				////////////////////////////////////////
				if ((!get_local_entity_int_value (en, INT_TYPE_AUTO_PILOT)) && (!get_local_entity_int_value (en, INT_TYPE_EJECTED)))
				{

					update_flight_dynamics ();

					transmit_entity_comms_message (ENTITY_COMMS_UPDATE, en);
				}
				else
				{

					if (get_local_entity_int_value (en, INT_TYPE_LANDED))
					{

						if (get_local_entity_int_value (en, INT_TYPE_AUTO_PILOT))
						{

							set_current_flight_dynamics_rotor_brake (TRUE);

							set_current_flight_dynamics_auto_pilot (FALSE);

							current_flight_dynamics->input_data.collective.value = 0.0;
						}
					}

					if ((damage_type == AIRCRAFT_DAMAGE_CRITICAL) || (get_local_entity_int_value (en, INT_TYPE_EJECTED)) || (get_local_entity_int_value (en, INT_TYPE_LANDED)))
					{

						set_current_flight_dynamics_auto_pilot (FALSE);
					}

					for (loop = 0; loop < get_entity_movement_iterations (); loop ++)
					{

						if ((damage_type == AIRCRAFT_DAMAGE_CRITICAL) || (get_local_entity_int_value (en, INT_TYPE_EJECTED)))
						{

							helicopter_death_movement (en);
						}
						else
						{

							if (!get_local_entity_int_value (en, INT_TYPE_LANDED))
							{

								get_3d_terrain_point_data (raw->ac.mob.position.x, raw->ac.mob.position.z, &raw->ac.terrain_info);
							}

							helicopter_movement (en);

							if (get_local_entity_int_value (en, INT_TYPE_AUTO_PILOT))
							{

								set_dynamics_entity_values (get_gunship_entity ());
							}
						}
					}
				}

				////////////////////////////////////////
				//
				// ORDER IS CRITICAL
				//

				if (raw->ac.mob.alive)
				{
					update_aircraft_loading_doors (en);

					update_aircraft_cargo_doors (en);

					update_aircraft_undercarriage (en);

					update_aircraft_weapon_system_ready (en);

					update_entity_weapon_systems (en);

					update_entity_weapon_system_weapon_and_target_vectors (en);

					update_avionics ();

					update_cockpits ();

					update_aircraft_decoy_release (en);
				}

				//
				////////////////////////////////////////

				//
				// Check if gunship has a task - if not then set gunship entity to NULL
				//

				if (!get_local_entity_parent (en, LIST_TYPE_FOLLOWER))
				{
					if (!get_local_entity_int_value (en, INT_TYPE_EJECTED))
					{
						if (en == get_gunship_entity ())
						{
							set_gunship_entity (NULL);
						}
					}
				}

				break;
			}
			////////////////////////////////////////
			case ENTITY_PLAYER_REMOTE:
			////////////////////////////////////////
			{
				////////////////////////////////////////
				//
				// ORDER IS CRITICAL
				//

				if (raw->ac.mob.alive)
				{
					update_aircraft_loading_doors (en);

					update_aircraft_cargo_doors (en);

					update_aircraft_undercarriage (en);

					update_aircraft_weapon_system_ready (en);

					update_entity_weapon_systems (en);

					update_entity_weapon_system_weapon_and_target_vectors (en);
				}

				if ((get_local_entity_int_value (en, INT_TYPE_AUTO_PILOT)) || (get_local_entity_int_value (en, INT_TYPE_EJECTED)))
				{

					for (loop = 0; loop < get_entity_movement_iterations (); loop ++)
					{

						// no need for death_movement as if the remote_player is damaged it will default back to manual flight.
						if (get_local_entity_int_value (en, INT_TYPE_EJECTED))
						{

							helicopter_death_movement (en);
						}
						else
						{

							if (!get_local_entity_int_value (en, INT_TYPE_LANDED))
							{

								get_3d_terrain_point_data (raw->ac.mob.position.x, raw->ac.mob.position.z, &raw->ac.terrain_info);
							}

							helicopter_movement (en);
						}
					}
				}
				else
				{

					interpolate_entity_position (en);
				}

				//
				////////////////////////////////////////

				break;
			}
		}
	}
	else
	{
		if (get_local_entity_int_value (en, INT_TYPE_OPERATIONAL_STATE) == OPERATIONAL_STATE_DEAD)
		{
		}
		else
		{
			for (loop = 0; loop < get_entity_movement_iterations (); loop ++)
			{
				helicopter_death_movement (en);
			}
		}
	}
}
Beispiel #4
0
void create_client_server_entity_weapon (entity *launcher, entity_sub_types weapon_sub_type, int weapon_index, int burst_size, int *smoke_trail_indices)
{
	entity
		*force,
		*target,
		*weapon;

	meta_smoke_list_types
		smoke_trail_type;

	int
		i,
		num_smoke_trail_entities,
		valid_sound_effect,
		current_weapon_count,
		new_weapon_count;

	ASSERT (launcher);

	ASSERT (entity_sub_type_weapon_valid (weapon_sub_type));

	//
	// get target
	//

	if (!(weapon_database[weapon_sub_type].weapon_class & (WEAPON_CLASS_DECOY | WEAPON_CLASS_CARGO | WEAPON_CLASS_DEBRIS)))
	{
		target = get_local_entity_parent (launcher, LIST_TYPE_TARGET);

/*		if (weapon_database[weapon_sub_type].hellfire_flight_profile)
		{
			if (get_local_entity_int_value (launcher, INT_TYPE_LOCK_ON_AFTER_LAUNCH))
			{
				target = NULL;
			}
		} */
	}
	else
	{
		target = NULL;
	}

	if (get_comms_model () == COMMS_MODEL_SERVER)
	{
		////////////////////////////////////////
		//
		// SERVER/TX and SERVER/RX
		//
		////////////////////////////////////////

		ASSERT (weapon_index == ENTITY_INDEX_DONT_CARE);

		ASSERT (burst_size == BURST_SIZE_DONT_CARE);

		ASSERT (!smoke_trail_indices);

		// NOTE: The clients' weapon counters lag the servers' so it is possible that the
		//       client may unknowingly attempt to create more weapons than are available.
		//       This is prone to happen during rapid firing.

		current_weapon_count = get_local_entity_weapon_count (launcher, weapon_sub_type);

		if (current_weapon_count > 0)
		{
			int loal_mode = weapon_database[weapon_sub_type].hellfire_flight_profile && get_local_entity_int_value (launcher, INT_TYPE_LOCK_ON_AFTER_LAUNCH);

			if (get_comms_data_flow () == COMMS_DATA_FLOW_RX)
			{
				set_force_local_entity_create_stack_attributes (TRUE);
			}

			//
			// get burst size wrt rate of fire
			//

			if (weapon_database[weapon_sub_type].rate_of_fire != FIRE_SINGLE_WEAPON)
			{
				float time_per_shot = weapon_database[weapon_sub_type].inverse_rate_of_fire * ONE_MINUTE;
				unsigned int* last_shot = NULL;

				switch (launcher->type)
				{
				case ENTITY_TYPE_HELICOPTER:
					last_shot = &((helicopter*)get_local_entity_data(launcher))->ac.weapon_salvo_timer;
					break;

				case ENTITY_TYPE_FIXED_WING:
					last_shot = &((fixed_wing*)get_local_entity_data(launcher))->ac.weapon_salvo_timer;
					break;

				case ENTITY_TYPE_ANTI_AIRCRAFT:
					last_shot = &((anti_aircraft*)get_local_entity_data(launcher))->vh.weapon_salvo_timer;
					break;

				case ENTITY_TYPE_PERSON:
					last_shot = &((person*)get_local_entity_data(launcher))->vh.weapon_salvo_timer;
					break;

				case ENTITY_TYPE_ROUTED_VEHICLE:
					last_shot = &((routed_vehicle*)get_local_entity_data(launcher))->vh.weapon_salvo_timer;
					break;

				case ENTITY_TYPE_SHIP_VEHICLE:
					last_shot = &((ship_vehicle*)get_local_entity_data(launcher))->vh.weapon_salvo_timer;
					break;
				}

				if (last_shot)
				{
					unsigned int current_time = get_system_time();
					float elapsed_time = 1;

					if (*last_shot > 0)
					{
						if (current_time < *last_shot)
							return;
						elapsed_time = (current_time - *last_shot) * 0.001;
					}
					else
						elapsed_time = get_delta_time();

					burst_size = (int)(weapon_database[weapon_sub_type].rate_of_fire * ONE_OVER_ONE_MINUTE * elapsed_time);
					if (burst_size < 1)
					{
						if (*last_shot == 0)  // first shot in salvo always get fired
							burst_size = 1;
						else
							return;
					}

					if (*last_shot)
						*last_shot += (int)(burst_size * time_per_shot * 1000.0);
					else
						*last_shot = current_time;
				}
				else
				{
					ASSERT(FALSE);
					burst_size = 1;
				}
			}
			else
			{
				burst_size = 1;
			}

			//
			// set burst timer
			//

			valid_sound_effect = FALSE;

			if (get_local_entity_float_value (launcher, FLOAT_TYPE_WEAPON_BURST_TIMER) == 0.0)
			{
				set_local_entity_float_value (launcher, FLOAT_TYPE_WEAPON_BURST_TIMER, weapon_database[weapon_sub_type].burst_duration);

				valid_sound_effect = TRUE;
			}

			//
			// create weapon
			//

			weapon = create_local_entity
			(
				ENTITY_TYPE_WEAPON,
				ENTITY_INDEX_DONT_CARE,
				ENTITY_ATTR_INT_VALUE (INT_TYPE_ENTITY_SUB_TYPE, weapon_sub_type),
				ENTITY_ATTR_INT_VALUE (INT_TYPE_WEAPON_BURST_SIZE, burst_size),
				ENTITY_ATTR_INT_VALUE (INT_TYPE_WEAPON_MISSILE_PHASE, MISSILE_PHASE1),
				ENTITY_ATTR_INT_VALUE (INT_TYPE_LOCK_ON_AFTER_LAUNCH, loal_mode),
				ENTITY_ATTR_PARENT (LIST_TYPE_LAUNCHED_WEAPON, launcher),
				ENTITY_ATTR_PARENT (LIST_TYPE_TARGET, target),
				ENTITY_ATTR_END
			);

			if (weapon)
			{
				//
				// send FIRE message to force (unless it's a decoy/cargo/debris being launched)
				//

				if ((target) && (!(weapon_database[weapon_sub_type].weapon_class & (WEAPON_CLASS_DECOY | WEAPON_CLASS_CARGO | WEAPON_CLASS_DEBRIS))))
				{
					force = get_local_force_entity ((entity_sides) get_local_entity_int_value (target, INT_TYPE_SIDE));

					if (force)
					{
						notify_local_entity (ENTITY_MESSAGE_ENTITY_FIRED_AT, force, launcher, target);
					}
				}

				//
				// create sound effect(s)
				//

				if (valid_sound_effect)
				{
					create_weapon_launched_sound_effects (launcher, weapon_sub_type);
				}

				//
				// create smoke trail
				//

				smoke_trail_type = (meta_smoke_list_types) get_local_entity_int_value (weapon, INT_TYPE_WEAPON_SMOKE_TRAIL_TYPE);

				if (smoke_trail_type != META_SMOKE_LIST_TYPE_NONE)
				{
					struct OBJECT_3D_BOUNDS
						*bounding_box;

					vec3d
						exhaust_offset;

					num_smoke_trail_entities = count_entities_in_meta_smoke_list (smoke_trail_type);

					ASSERT (num_smoke_trail_entities > 0);

					smoke_trail_indices = (int *) malloc_fast_mem (sizeof (int) * num_smoke_trail_entities);

					for (i = 0; i < num_smoke_trail_entities; i++)
					{
						smoke_trail_indices[i] = ENTITY_INDEX_DONT_CARE;
					}

					bounding_box = get_object_3d_bounding_box (get_local_entity_int_value (weapon, INT_TYPE_DEFAULT_3D_SHAPE));

					if ((weapon_sub_type == ENTITY_SUB_TYPE_WEAPON_HOKUM_PILOT) ||(weapon_sub_type == ENTITY_SUB_TYPE_WEAPON_HOKUM_CO_PILOT))
					{
						exhaust_offset.x = 0.0;
						exhaust_offset.y = 0.0;
						exhaust_offset.z = 0.0;
					}
					else
					{
						exhaust_offset.x = 0.0;
						exhaust_offset.y = 0.0;
						exhaust_offset.z = bounding_box->zmin;
					}

					create_meta_smoke_list_specified_offset (smoke_trail_type, weapon, &exhaust_offset, smoke_trail_indices);
				}

				transmit_entity_comms_message
				(
					ENTITY_COMMS_CREATE_WEAPON,
					NULL,
					launcher,
					weapon_sub_type,
					get_local_entity_safe_index (weapon),
					burst_size,
					smoke_trail_indices
				);

				if (smoke_trail_indices)
				{
					free_mem (smoke_trail_indices);
				}

				//
				// out of weapons (if infinite weapons then reload else select next weapon)
				//

				new_weapon_count = get_local_entity_weapon_count (launcher, weapon_sub_type);

				if (new_weapon_count <= 0)
				{
					#if !DEMO_VERSION
					if (get_local_entity_int_value (get_session_entity (), INT_TYPE_INFINITE_WEAPONS))
					{
						weapon_config_types
							config_type;

						config_type = (weapon_config_types) get_local_entity_int_value (launcher, INT_TYPE_WEAPON_CONFIG_TYPE);

						set_client_server_entity_int_value (launcher, INT_TYPE_WEAPON_CONFIG_TYPE, config_type);
					}
					else
					#endif
					{
						//
						// play weapon out of ammo speech
						//

						play_entity_weapon_out_speech (launcher, weapon_sub_type);

						//
						// select next weapon
						//
/*
						if (!(weapon_database[weapon_sub_type].weapon_class & (WEAPON_CLASS_DECOY | WEAPON_CLASS_CARGO | WEAPON_CLASS_DEBRIS)))
						{
							entity_sub_types
								next_weapon_sub_type;

							if (get_local_entity_int_value (launcher, INT_TYPE_PLAYER) != ENTITY_PLAYER_AI)
							{
								next_weapon_sub_type = get_next_available_weapon_sub_type (launcher);
							}
							else
							{
								next_weapon_sub_type = ENTITY_SUB_TYPE_WEAPON_NO_WEAPON;
							}

							set_client_server_entity_int_value (launcher, INT_TYPE_SELECTED_WEAPON, next_weapon_sub_type);
						}
*/
					}
				}
				else
				{
					int
						report_ammo_low_count;

					report_ammo_low_count = weapon_database[weapon_sub_type].report_ammo_low_count;

					if ((current_weapon_count > report_ammo_low_count) && (new_weapon_count <= report_ammo_low_count))
					{
						//
						// play weapon low speech
						//

						play_entity_weapon_low_speech (launcher, weapon_sub_type);
					}
					else
					{
						//
						// weapon launch speech
						//

						play_entity_weapon_launched_speech (launcher, weapon_sub_type);
					}
				}
			}

			set_force_local_entity_create_stack_attributes (FALSE);
		}
		else
		{
			pause_client_server_continuous_weapon_sound_effect (launcher, weapon_sub_type);
		}
	}
	else
	{
		if (get_comms_data_flow () == COMMS_DATA_FLOW_TX)
		{
			////////////////////////////////////////
			//
			// CLIENT/TX
			//
			////////////////////////////////////////

			ASSERT (weapon_index == ENTITY_INDEX_DONT_CARE);

			ASSERT (burst_size == BURST_SIZE_DONT_CARE);

			ASSERT (!smoke_trail_indices);

			// NOTE: The clients' weapon counters lag the servers' so it is possible that the
			//       client may unknowingly attempt to create more weapons than are available.
			//       This is prone to happen during rapid firing.

			if (get_local_entity_weapon_available (launcher, weapon_sub_type))
			{
				transmit_entity_comms_message
				(
					ENTITY_COMMS_CREATE_WEAPON,
					NULL,
					launcher,
					weapon_sub_type,
					ENTITY_INDEX_DONT_CARE,
					burst_size,
					NULL
				);
			}
		}
		else
		{
			////////////////////////////////////////
			//
			// CLIENT/RX
			//
			////////////////////////////////////////

			ASSERT (weapon_index != ENTITY_INDEX_DONT_CARE);

			ASSERT (burst_size > 0);

			set_force_local_entity_create_stack_attributes (TRUE);

			weapon = create_local_entity
			(
				ENTITY_TYPE_WEAPON,
				weapon_index,
				ENTITY_ATTR_INT_VALUE (INT_TYPE_ENTITY_SUB_TYPE, weapon_sub_type),
				ENTITY_ATTR_INT_VALUE (INT_TYPE_WEAPON_BURST_SIZE, burst_size),
				ENTITY_ATTR_PARENT (LIST_TYPE_LAUNCHED_WEAPON, launcher),
				ENTITY_ATTR_PARENT (LIST_TYPE_TARGET, target),
				ENTITY_ATTR_END
			);

			ASSERT (weapon);

			//
			// create smoke trail
			//

			smoke_trail_type = (meta_smoke_list_types) get_local_entity_int_value (weapon, INT_TYPE_WEAPON_SMOKE_TRAIL_TYPE);

			if (smoke_trail_type != META_SMOKE_LIST_TYPE_NONE)
			{
				struct OBJECT_3D_BOUNDS
					*bounding_box;

				vec3d
					exhaust_offset;

				ASSERT (smoke_trail_indices);

				bounding_box = get_object_3d_bounding_box (get_local_entity_int_value (weapon, INT_TYPE_DEFAULT_3D_SHAPE));

				if ((weapon_sub_type == ENTITY_SUB_TYPE_WEAPON_HOKUM_PILOT) ||(weapon_sub_type == ENTITY_SUB_TYPE_WEAPON_HOKUM_CO_PILOT))
				{
					exhaust_offset.x = 0.0;
					exhaust_offset.y = 0.0;
					exhaust_offset.z = 0.0;
				}
				else
				{
					exhaust_offset.x = 0.0;
					exhaust_offset.y = 0.0;
					exhaust_offset.z = bounding_box->zmin;
				}

				create_meta_smoke_list_specified_offset (smoke_trail_type, weapon, &exhaust_offset, smoke_trail_indices);
			}
			else
			{
				ASSERT (!smoke_trail_indices);
			}

			set_force_local_entity_create_stack_attributes (FALSE);
		}
	}
}