示例#1
0
文件: cyclic.c 项目: Comanche93/eech
void damage_hydraulics(int damaging)
{
	if (damaging)
	{
		hydraulic_pressure = 0.65 + (sfrand1() * 0.1);  // lose some hydraulics pressure immediately
		// lock cyclic in a random position
		damaged_lock_x_pos = sfrand1() * 50.0;
		damaged_lock_y_pos = 25.0 + sfrand1() * 50.0;
		hydraulic_pressure_loss_rate = hydraulic_pressure * frand1() * (MAX_HYDRAULICS_LOSS_RATE - MIN_HYDRAULICS_LOSS_RATE) + MIN_HYDRAULICS_LOSS_RATE;
	}
	else
	{
		hydraulic_pressure = 1.0;
		hydraulic_pressure_loss_rate = 0.0;
	}
}
示例#2
0
文件: rv_anim.c 项目: Comanche93/eech
int set_initial_rotation_angle_of_routed_vehicle_wheels (object_3d_instance *inst3d)
{
	object_3d_sub_object_search_data
		search;

	int
		depth;

	float
		ang;

	//
	// vary wheel start positions (ok to use a random number as this is for visual effect only)
	//

	ASSERT (inst3d);

	//
	// fixed wheels
	//

	depth = 0;

	while (TRUE)
	{
		search.search_depth = depth;
		search.search_object = inst3d;
		search.sub_object_index = OBJECT_3D_SUB_OBJECT_FIXED_WHEEL;

		if (find_object_3d_sub_object (&search) == SUB_OBJECT_SEARCH_RESULT_OBJECT_FOUND)
		{
			ang = sfrand1() * PI;

			search.result_sub_object->relative_pitch = ang;
		}
		else
		{
			break;
		}

		depth++;
	}

	//
	// steerable wheels
	//

	depth = 0;

	while (TRUE)
	{
		search.search_depth = depth;
		search.search_object = inst3d;
		search.sub_object_index = OBJECT_3D_SUB_OBJECT_STEERABLE_WHEEL;

		if (find_object_3d_sub_object (&search) == SUB_OBJECT_SEARCH_RESULT_OBJECT_FOUND)
		{
			ang = sfrand1() * PI;

			search.result_sub_object->relative_pitch = ang;
		}
		else
		{
			break;
		}

		depth++;
	}

	return TRUE;
}
示例#3
0
void dynamics_damage_model (unsigned int damage, int random)
{

	dynamics_damage_types
		damage_array [NUM_DYNAMIC_DAMAGES];

	int
		count;

	dynamics_damage_types
		this_damage;

	if (!get_session_entity ())
	{

		return;
	}

	if (get_local_entity_int_value (get_gunship_entity (), INT_TYPE_INVULNERABLE_FROM_COLLISIONS))
	{

		// if invulnerable only allow damage/use of fire extinguisher

		damage = damage & DYNAMICS_DAMAGE_FIRE_EXTINGUISHER;
	}

	if (random)
	{

		damage_array [0] = DYNAMICS_DAMAGE_NONE;

		this_damage = DYNAMICS_DAMAGE_NONE;

		count = 1;

		while (this_damage < NUM_DYNAMICS_DAMAGE_TYPES)
		{

			if (damage & this_damage)
			{

				damage_array [count] = this_damage;

				count ++;
			}

			this_damage = this_damage << 1;
		}

		damage = damage_array [rand16 () % count];

		#if DYNAMICS_DEBUG

		debug_log ("DYNAMICS: randomly selecting damage %d", damage);

		#endif
	}

	notify_avionics_of_dynamics_fault (damage);

	this_damage = DYNAMICS_DAMAGE_NONE;

	while (this_damage < NUM_DYNAMICS_DAMAGE_TYPES)
	{

		if ((damage & this_damage) && (!(current_flight_dynamics->dynamics_damage & this_damage)))
		{

			switch (this_damage)
			{

				case DYNAMICS_DAMAGE_NONE:
				{

					#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: no damage");

					#endif

					current_flight_dynamics->dynamics_damage = DYNAMICS_DAMAGE_NONE;

					current_flight_dynamics->main_blade_pitch.damaged = FALSE;

					current_flight_dynamics->main_rotor_roll_angle.damaged = FALSE;

					current_flight_dynamics->main_rotor_pitch_angle.damaged = FALSE;

					current_flight_dynamics->main_rotor_rpm.damaged = FALSE;

					current_flight_dynamics->tail_blade_pitch.damaged = FALSE;

					current_flight_dynamics->tail_rotor_rpm.damaged = FALSE;

					current_flight_dynamics->left_engine_torque.damaged = FALSE;

					current_flight_dynamics->left_engine_rpm.damaged = FALSE;

					current_flight_dynamics->right_engine_torque.damaged = FALSE;

					current_flight_dynamics->right_engine_rpm.damaged = FALSE;

					current_flight_dynamics->cross_coupling_effect.damaged = FALSE;

					current_flight_dynamics->input_data.cyclic_x.damaged = FALSE;

					current_flight_dynamics->input_data.cyclic_y.damaged = FALSE;

					current_flight_dynamics->input_data.cyclic_x_trim.damaged = FALSE;

					current_flight_dynamics->input_data.cyclic_y_trim.damaged = FALSE;

					break;
				}
				case DYNAMICS_DAMAGE_MAIN_ROTOR:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: main rotor damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_MAIN_ROTOR;

					current_flight_dynamics->main_blade_pitch.damaged = TRUE;

					current_flight_dynamics->main_rotor_roll_angle.damaged = TRUE;

					current_flight_dynamics->main_rotor_pitch_angle.damaged = TRUE;

					current_flight_dynamics->main_rotor_rpm.damaged = TRUE;

					set_client_server_entity_int_value (get_gunship_entity (), INT_TYPE_MAIN_ROTOR_DAMAGED, TRUE);

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_MAIN_ROTOR_DAMAGED);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_TAIL_ROTOR:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: tail rotor damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_TAIL_ROTOR;

					current_flight_dynamics->tail_blade_pitch.damaged = TRUE;

					current_flight_dynamics->tail_rotor_rpm.damaged = TRUE;

					current_flight_dynamics->cross_coupling_effect.damaged = TRUE;

					set_client_server_entity_int_value (get_gunship_entity (), INT_TYPE_TAIL_ROTOR_DAMAGED, TRUE);

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_TAIL_ROTOR_DAMAGED);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_LEFT_ENGINE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: left engine damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_LEFT_ENGINE;

					current_flight_dynamics->left_engine_torque.damaged = TRUE;

					current_flight_dynamics->left_engine_rpm.damaged = TRUE;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_LEFT_ENGINE_FAILURE);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_RIGHT_ENGINE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: right engine damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_RIGHT_ENGINE;

					current_flight_dynamics->right_engine_torque.damaged = TRUE;

					current_flight_dynamics->right_engine_rpm.damaged = TRUE;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_RIGHT_ENGINE_FAILURE);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_LEFT_ENGINE_FIRE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: left engine fire damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_LEFT_ENGINE_FIRE;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_LEFT_ENGINE_FIRE);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_RIGHT_ENGINE_FIRE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: right engine fire damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_RIGHT_ENGINE_FIRE;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_RIGHT_ENGINE_FIRE);

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_LOW_HYDRAULICS:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: LOW HYDRAULICS damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_LOW_HYDRAULICS;

					current_flight_dynamics->input_data.cyclic_x.damaged = TRUE;

					current_flight_dynamics->input_data.cyclic_y.damaged = TRUE;

					if (sfrand1 () < 0.0)
					{

						play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_HYDRAULIC_PRESSURE_FAILURE);
					}
					else
					{

						play_client_server_cpg_message (get_gunship_entity (), 0.5, 1.0, SPEECH_CATEGORY_CPG_SYSTEMS, 1.0, SPEECH_CPG_CONTROL_SYSTEMS_DAMAGED);
					}

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_STABILISER:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: STABILISER damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_STABILISER;

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					if (sfrand1 () < 0.0)
					{

						play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_STABILISER_DAMAGED);
					}
					else
					{

						play_client_server_cpg_message (get_gunship_entity (), 0.5, 1.0, SPEECH_CATEGORY_CPG_SYSTEMS, 1.0, SPEECH_CPG_CONTROL_SYSTEMS_DAMAGED);
					}

					break;
				}
				case DYNAMICS_DAMAGE_FUEL_LEAK:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: FUEL_LEAK damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_FUEL_LEAK;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_FUEL_LEAK);

					break;
				}
				case DYNAMICS_DAMAGE_LOW_OIL_PRESSURE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: LOW_OIL_PRESSURE damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_LOW_OIL_PRESSURE;

					current_flight_dynamics->input_data.cyclic_y.damaged = TRUE;

					if (sfrand1 () < 0.0)
					{

						play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_LOW_ENGINE_OIL_PRESSURE);
					}
					else
					{

						play_client_server_cpg_message (get_gunship_entity (), 0.5, 1.0, SPEECH_CATEGORY_CPG_SYSTEMS, 1.0, SPEECH_CPG_CONTROL_SYSTEMS_DAMAGED);
					}

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_HIGH_OIL_PRESSURE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: HIGH_OIL_PRESSURE damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_HIGH_OIL_PRESSURE;

					current_flight_dynamics->input_data.collective.damaged = TRUE;

					if (sfrand1 () < 0.0)
					{

						play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_HIGH_ENGINE_OIL_TEMPERATURE);
					}
					else
					{

						play_client_server_cpg_message (get_gunship_entity (), 0.5, 1.0, SPEECH_CATEGORY_CPG_SYSTEMS, 1.0, SPEECH_CPG_CONTROL_SYSTEMS_DAMAGED);
					}

					set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);

					set_current_flight_dynamics_auto_pilot (FALSE);

					break;
				}
				case DYNAMICS_DAMAGE_AVIONICS:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: AVIONICS damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_AVIONICS;

					break;
				}
				case DYNAMICS_DAMAGE_FIRE_EXTINGUISHER:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: FIRE_EXTINGUISHER damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_FIRE_EXTINGUISHER;

					break;
				}
				case DYNAMICS_DAMAGE_UNDERCARRIAGE:
				{

					//#if DYNAMICS_DEBUG

					debug_log ("DYNAMICS: UNDERCARRIAGE damage");

					//#endif

					current_flight_dynamics->dynamics_damage |= DYNAMICS_DAMAGE_UNDERCARRIAGE;

					current_flight_dynamics->undercarriage_state.damaged = TRUE;

					play_client_server_warning_message (get_gunship_entity (), SPEECH_SYSTEM_GEAR_DAMAGED);

					break;
				}
				default:
				{

					debug_fatal ("DYNAMICS: unknown damage %d", this_damage);
				}
			}
		}

		this_damage = this_damage << 1;
	}
}
示例#4
0
文件: collect.c 项目: Comanche93/eech
void update_collective_pressure_inputs (void)
{

	current_flight_dynamics->input_data.collective.delta = current_flight_dynamics->input_data.collective.value;

	switch (get_global_collective_input ())
	{

		case KEYBOARD_INPUT:
		case MOUSE_INPUT:
		{
		
			if (current_flight_dynamics->input_data.collective_input_pressure & COLLECTIVE_PRESSURE_BACKWARD)
			{
		
				current_flight_dynamics->input_data.collective_pressure.value = min (0.0f, current_flight_dynamics->input_data.collective_pressure.value);
		
				current_flight_dynamics->input_data.collective_pressure.value -= 5.0 * get_delta_time ();
			}
			else if (current_flight_dynamics->input_data.collective_input_pressure & COLLECTIVE_PRESSURE_FORWARD)
			{
		
				current_flight_dynamics->input_data.collective_pressure.value = max (0.0f, current_flight_dynamics->input_data.collective_pressure.value);
		
				current_flight_dynamics->input_data.collective_pressure.value += 5.0 * get_delta_time ();
			}
			else
			{
		
				current_flight_dynamics->input_data.collective_pressure.value = 0.0;
			}
		
			current_flight_dynamics->input_data.collective_pressure.value = bound (current_flight_dynamics->input_data.collective_pressure.value,
																											current_flight_dynamics->input_data.collective_pressure.min,
																											current_flight_dynamics->input_data.collective_pressure.max);
	
			break;
		}
		case THROTTLE_INPUT:
		{

			int
				joyval;

			float
				input;

			// 030418 loke
			// implemented multiple joystick device selection
			if (command_line_collective_joystick_index == -1)
			{
				joyval = get_joystick_axis (current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_THROTTLE);
			}
			else
			{
				joyval = get_joystick_axis (command_line_collective_joystick_index, command_line_collective_joystick_axis);
			}


			if (non_linear_collective)
			{
				input = 0.5 + ((float) joyval ) / ((float) JOYSTICK_AXIS_MAXIMUM - (float) JOYSTICK_AXIS_MINIMUM);

				if (input < command_line_collective_zone_1_limit)
				{
					// start variable percentage at zone1 by GCsDriver 08-12-2007
					input *= command_line_collective_percentage_at_zone1 * zone_1_scale;
					input -= command_line_collective_percentage_at_zone1;  // 0% -> -60
					// original
					//input *= 60.0 * zone_1_scale;
					//input -= 60.0;  // 0% -> -60
				}
				else if (input < command_line_collective_zone_2_limit)
				{
					// find amount over limit
					input -= command_line_collective_zone_1_limit;
					input *= (100.0-command_line_collective_percentage_at_zone1) * zone_2_scale;
					// original
					//input -= command_line_collective_zone_1_limit;
					//input *= 40.0 * zone_2_scale;
				}
				else
				{
					// find amount over limit
					input -= command_line_collective_zone_2_limit;
					input *= 20.0 * zone_3_scale;
					input += (100.0-command_line_collective_percentage_at_zone1);   // 100% -> +40
					// original
					//input -= command_line_collective_zone_2_limit;
					//input *= 20.0 * zone_3_scale;
					//input += 40.0;   // 100% -> +40
					// end variable percentage at zone1 by GCsDriver 08-12-2007
				}
			}
			else
				input = (float) (120.0 * (float) joyval ) / ((float) JOYSTICK_AXIS_MAXIMUM - (float) JOYSTICK_AXIS_MINIMUM);

			if ((current_flight_dynamics->auto_hover != HOVER_HOLD_STABLE) && (current_flight_dynamics->auto_hover != HOVER_HOLD_ALTITUDE_LOCK))
			{
		
				if (get_current_dynamics_options (DYNAMICS_OPTIONS_REVERSE_THROTTLE_INPUT))
				{
	
					current_flight_dynamics->input_data.collective.value = (float) 60.0 - input;
				}
				else
				{
	
					current_flight_dynamics->input_data.collective.value = (float) 60.0 + input;
				}
			}
			break;
		}
	}

	// recalculate collective position

	if (current_flight_dynamics->input_data.collective_pressure.value)
	{
	
		current_flight_dynamics->input_data.collective.value += 10.0 * current_flight_dynamics->input_data.collective_pressure.value * get_delta_time ();
	}
	else
	{

		// restore
	}

	if (current_flight_dynamics->input_data.collective.damaged)
	{

		current_flight_dynamics->input_data.collective.value += (get_model_delta_time ()) * (7.5 * sfrand1 () * current_flight_dynamics->input_data.collective.delta);
	}

	current_flight_dynamics->input_data.collective.value = bound (current_flight_dynamics->input_data.collective.value,
																						current_flight_dynamics->input_data.collective.min,
																						current_flight_dynamics->input_data.collective.max);
		
	current_flight_dynamics->input_data.collective.delta -= current_flight_dynamics->input_data.collective.value;
	current_flight_dynamics->input_data.collective.delta *= -1.0;
}
示例#5
0
int create_downwash_effect_component(downwash_component *this_downwash_component, downwash_types downwash_type, vec3d *position, int *entity_index_list, float main_rotor_radius, float main_rotor_rpm, float min_altitude)
{
	int
		loop,
		count,
		terrain_type,
		trail_type;

	short int
		quadrant_x,
		quadrant_z;
	
	unsigned char
		alpha_percentage;

	float
		lifetime,
		lifetime_min,
		lifetime_max,
		scale_min,
		scale_max,
		scale,
		angle,
		radius,
		relative_radius,
		height,
		altitude,
		half_altitude,
		main_rotor_radius_minus_altitude;

	vec3d
		pos,
		offset,
		iv;

	terrain_3d_point_data
		terrain_info;

	entity
		*new_entity;

	memset (&terrain_info, 0, sizeof (terrain_3d_point_data));

	count = this_downwash_component->trail_count;

	if ( count < 1 )
	{
		return 0;
	}

	// Xhit: This is the altitude of the helicopter relative to the ground level. (030328)
	altitude = position->y - min_altitude;
	half_altitude = (altitude / 2.0);

	main_rotor_radius_minus_altitude = main_rotor_radius - altitude;

	scale_min = this_downwash_component->scale_min;
	scale_max = this_downwash_component->scale_max;

	lifetime_min = this_downwash_component->lifetime_min;
	lifetime_max = this_downwash_component->lifetime_max;

	// Xhit: initialising quadrant variables (030328)
	quadrant_x = 1;
	quadrant_z = 1;

	//
	// create smoke trails
	//

	for ( loop = 0 ; loop < count ; loop ++ )
	{
		lifetime = lifetime_min + fabs( ( lifetime_max - lifetime_min ) * sfrand1() );

		angle = frand1() * PI_OVER_TWO;

		relative_radius = main_rotor_radius * frand1();

		scale = relative_radius + scale_min;
		if(scale > scale_max)
				scale = scale_max;

		switch(downwash_type)
		{
			case DOWNWASH_TYPE_LAND:
			case DOWNWASH_TYPE_LAND_DUAL_ROTORS:
			{
				//Xhit: If altitude bigger than main rotor radius then the smoke should be centered beneath the helicopter. (030328)
				if(altitude >= main_rotor_radius)
				{
					radius = relative_radius;
					height = (half_altitude * (radius / main_rotor_radius) + half_altitude) * frand1();
			
				}else
				{
					radius = relative_radius + main_rotor_radius_minus_altitude;
					height = (half_altitude * ((radius - main_rotor_radius_minus_altitude) / main_rotor_radius) + half_altitude + scale ) * frand1();
				}
				break;
			}
			case DOWNWASH_TYPE_WATER:
			case DOWNWASH_TYPE_WATER_DUAL_ROTORS:
			{
				if(altitude >= main_rotor_radius)
				{
					radius = relative_radius;
			
				}else
				{
					radius = relative_radius + main_rotor_radius_minus_altitude;
				}

				// Xhit: Changed to 2 instead of main_rotor_radius so smoke is created just over water level (030515)
				height =  2 * frand1();
				break;
			}
			default:
			{
				debug_fatal("DOWNWASH : trying to create an unrecogniseable downwash effect");
				break;
			}
		}


		//Xhit: If main rotor(s) only (not displaced main rotors) then. (030328)
		if((this_downwash_component->create_in_all_quadrants) && (loop < 4))
		{
			//Xhit:	This cryptical thing is to determine in which quadrant this sprite is going to be created. (030328)
			//		 ^z
			//		 |
			//		1|0  x
			//		-+--->
			//		3|2
			//
			//		loop = 0 -> x=	1,	z=	1; loop = 1 -> x=	-1, z=	 1;
			//		loop = 2 -> x=   1,	z= -1; loop = 3 -> x=	-1, z=	-1;
			quadrant_x = 1 | -(loop & 1);
			quadrant_z = 1 | -(loop & 2);
						
			offset.x = quadrant_x * radius * ( cos ( angle ) );
			offset.y = height;
			offset.z = quadrant_z * radius * ( sin ( angle ) );

		}else
		//Xhit:	If scattered downwash effect and if the heli got more than one main rotor (on different axis) then 
		//			add two more trails at the sides of the heli. (030328)
		if((this_downwash_component->create_in_all_quadrants) && (loop >= 4) && (count == 6))
		{
			//Xhit: loop = 4 -> x=	1; loop = 5 -> x=	-1; (030328)
			quadrant_x = 1 | -(loop & 1);

			relative_radius = main_rotor_radius * frand1();

			offset.x = quadrant_x * radius;
			offset.y = height;
			offset.z = frand1() * (main_rotor_radius / 2);
		}else
		{
			debug_fatal("DOWNWASH : trying to create an unrecogniseable downwash effect");
		}

		pos.x = position->x + offset.x ;
		pos.z = position->z + offset.z;

		//Xhit: This is necessary if it's going to work on tilting terrain. (030328)
		get_3d_terrain_point_data (pos.x, pos.z, &terrain_info);
		pos.y = get_3d_terrain_point_data_elevation (&terrain_info);

		pos.y = pos.y + offset.y;

		bound_position_to_map_volume( &pos );

		//Xhit: Decide which trail type is going to be used, this makes mapping to type of downwash effect fast. (030328)
		terrain_type = get_3d_terrain_point_data_type(&terrain_info);
		trail_type = get_terrain_surface_type(terrain_type) + SMOKE_LIST_TYPE_DOWNWASH_START;

		#if DEBUG_MODULE
		
		debug_log("DOWNWASH.C: terrain_type: %d, trail_type: %d", terrain_type, trail_type);

		#endif		

		iv.x = pos.x - position->x;
		iv.y = relative_radius;
		iv.z = pos.z - position->z;

		//Xhit:	If heli on ground then let the dust-smoke fade in according to increasing main_rotor_rpm
		//		otherwise set it according to the altitude of the heli (higher = less dust smoke) (030328)
		if(altitude < 1.0)
		{
			alpha_percentage = (unsigned char)(main_rotor_rpm);
		}else
		{
			//Xhit: "+ 1.0" is to guarantee that alpha_percentage > 0. (030328)
			alpha_percentage = (unsigned char)((1.0 - (altitude / (DOWNWASH_EFFECT_MAX_ALTITUDE + 1.0))) * 100);
		}

		new_entity = create_local_entity
		(
			ENTITY_TYPE_SMOKE_LIST,
			entity_index_list[ loop ],
			ENTITY_ATTR_INT_VALUE (INT_TYPE_ENTITY_SUB_TYPE, ENTITY_SUB_TYPE_EFFECT_SMOKE_LIST_DOWNWASH),
			ENTITY_ATTR_INT_VALUE (INT_TYPE_SMOKE_TYPE, trail_type),
			ENTITY_ATTR_INT_VALUE (INT_TYPE_COLOUR_ALPHA, alpha_percentage),
			ENTITY_ATTR_FLOAT_VALUE (FLOAT_TYPE_GENERATOR_LIFETIME, this_downwash_component->generator_lifetime),
			ENTITY_ATTR_FLOAT_VALUE (FLOAT_TYPE_FREQUENCY, this_downwash_component->frequency),
			ENTITY_ATTR_FLOAT_VALUE (FLOAT_TYPE_SMOKE_LIFETIME, lifetime),
			ENTITY_ATTR_FLOAT_VALUE (FLOAT_TYPE_SCALE, scale),
			ENTITY_ATTR_VEC3D (VEC3D_TYPE_INITIAL_VELOCITY, iv.x, iv.y, iv.z),
			ENTITY_ATTR_VEC3D (VEC3D_TYPE_POSITION, pos.x, pos.y, pos.z),
			ENTITY_ATTR_END
		);

		entity_index_list[ loop ] = get_local_entity_index( new_entity );
	}

	return count;
}
示例#6
0
文件: cyclic.c 项目: Comanche93/eech
void damage_primary_hydralics_only(void)
{
	hydraulic_pressure *= 0.75 + (sfrand1() * 0.1);  // lose some hydraulics pressure
}
示例#7
0
文件: cyclic.c 项目: Comanche93/eech
void update_cyclic_pressure_inputs (void)
{

	float
		trim_x,
		trim_y;

	if (!current_flight_dynamics)
	{

		return;
	}

	if (hydraulic_pressure_loss_rate && hydraulic_pressure > 0.0)
	{
		hydraulic_pressure -= hydraulic_pressure_loss_rate * get_delta_time();

		if (hydraulic_pressure < 0.0)
			hydraulic_pressure = 0.0;
	}

	trim_x = current_flight_dynamics->input_data.cyclic_x_trim.value;
	trim_y = current_flight_dynamics->input_data.cyclic_y_trim.value;

	if (trim_button_held)
	{
		current_flight_dynamics->input_data.cyclic_x.value = current_flight_dynamics->input_data.cyclic_x_trim.value;
		current_flight_dynamics->input_data.cyclic_y.value = current_flight_dynamics->input_data.cyclic_y_trim.value;
	}
	else
		switch (get_global_cyclic_input ())
		{

			case KEYBOARD_INPUT:
			case MOUSE_INPUT:
			{

				if (current_flight_dynamics->input_data.cyclic_input_pressure & CYCLIC_PRESSURE_LEFT)
				{

					current_flight_dynamics->input_data.cyclic_horizontal_pressure.value = min (0.0f, current_flight_dynamics->input_data.cyclic_horizontal_pressure.value);

					current_flight_dynamics->input_data.cyclic_x.value = min ((current_flight_dynamics->input_data.cyclic_x.value) / 2.0f, current_flight_dynamics->input_data.cyclic_x.value);

					current_flight_dynamics->input_data.cyclic_horizontal_pressure.value -= MODEL_FRAME_RATE * get_model_delta_time ();

					if ((current_flight_dynamics->auto_hover == HOVER_HOLD_NORMAL) ||
						(current_flight_dynamics->auto_hover == HOVER_HOLD_STABLE))
					{

						set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);
						set_current_flight_dynamics_auto_pilot (FALSE);
					}
				}
				else if (current_flight_dynamics->input_data.cyclic_input_pressure & CYCLIC_PRESSURE_RIGHT)
				{

					current_flight_dynamics->input_data.cyclic_horizontal_pressure.value = max (0.0f, current_flight_dynamics->input_data.cyclic_horizontal_pressure.value);

					current_flight_dynamics->input_data.cyclic_x.value = max ((current_flight_dynamics->input_data.cyclic_x.value) / 2.0f, current_flight_dynamics->input_data.cyclic_x.value);

					current_flight_dynamics->input_data.cyclic_horizontal_pressure.value += MODEL_FRAME_RATE * get_model_delta_time ();

					if ((current_flight_dynamics->auto_hover == HOVER_HOLD_NORMAL) ||
						(current_flight_dynamics->auto_hover == HOVER_HOLD_STABLE))
					{

						set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);
						set_current_flight_dynamics_auto_pilot (FALSE);
					}
				}
				else
				{

					if (fabs (current_flight_dynamics->input_data.cyclic_horizontal_pressure.value) < 1.0)
					{

						current_flight_dynamics->input_data.cyclic_horizontal_pressure.value = 0.0;
					}
					else
					{

						current_flight_dynamics->input_data.cyclic_horizontal_pressure.value -= ((MODEL_FRAME_RATE * get_model_delta_time ()) / 2.0) * (current_flight_dynamics->input_data.cyclic_horizontal_pressure.value);
					}
				}



				if (current_flight_dynamics->input_data.cyclic_input_pressure & CYCLIC_PRESSURE_BACKWARD)
				{

					current_flight_dynamics->input_data.cyclic_vertical_pressure.value = min (0.0f, current_flight_dynamics->input_data.cyclic_vertical_pressure.value);

					current_flight_dynamics->input_data.cyclic_y.value = min (current_flight_dynamics->input_data.cyclic_y.value / 2.0f, current_flight_dynamics->input_data.cyclic_y.value);

					current_flight_dynamics->input_data.cyclic_vertical_pressure.value -= MODEL_FRAME_RATE * get_model_delta_time ();

					if ((current_flight_dynamics->auto_hover == HOVER_HOLD_NORMAL) ||
						(current_flight_dynamics->auto_hover == HOVER_HOLD_STABLE))
					{

						set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);
						set_current_flight_dynamics_auto_pilot (FALSE);
					}
				}
				else if (current_flight_dynamics->input_data.cyclic_input_pressure & CYCLIC_PRESSURE_FORWARD)
				{

					current_flight_dynamics->input_data.cyclic_vertical_pressure.value = max (0.0f, current_flight_dynamics->input_data.cyclic_vertical_pressure.value);

					current_flight_dynamics->input_data.cyclic_y.value = max (current_flight_dynamics->input_data.cyclic_y.value / 2.0f, current_flight_dynamics->input_data.cyclic_y.value);

					current_flight_dynamics->input_data.cyclic_vertical_pressure.value += MODEL_FRAME_RATE * get_model_delta_time ();

					if ((current_flight_dynamics->auto_hover == HOVER_HOLD_NORMAL) ||
						(current_flight_dynamics->auto_hover == HOVER_HOLD_STABLE))
					{

						set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);
						set_current_flight_dynamics_auto_pilot (FALSE);
					}
				}
				else
				{

					if (fabs (current_flight_dynamics->input_data.cyclic_vertical_pressure.value) < 1.0)
					{

						current_flight_dynamics->input_data.cyclic_vertical_pressure.value = 0.0;
					}
					else
					{

						current_flight_dynamics->input_data.cyclic_vertical_pressure.value -= ((MODEL_FRAME_RATE * get_model_delta_time ()) / 2.0) * (current_flight_dynamics->input_data.cyclic_vertical_pressure.value);
					}
				}

				// limit pressure inputs

				current_flight_dynamics->input_data.cyclic_horizontal_pressure.value = bound (
																					current_flight_dynamics->input_data.cyclic_horizontal_pressure.value,
																					current_flight_dynamics->input_data.cyclic_horizontal_pressure.min,
																					current_flight_dynamics->input_data.cyclic_horizontal_pressure.max
																					);

				current_flight_dynamics->input_data.cyclic_vertical_pressure.value = bound (current_flight_dynamics->input_data.cyclic_vertical_pressure.value,
																					current_flight_dynamics->input_data.cyclic_vertical_pressure.min,
																					current_flight_dynamics->input_data.cyclic_vertical_pressure.max
																					);

				// recalculate cyclic position

				if (current_flight_dynamics->input_data.cyclic_horizontal_pressure.value)
				{

					current_flight_dynamics->input_data.cyclic_x.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * current_flight_dynamics->input_data.cyclic_horizontal_pressure.value;
					//current_flight_dynamics->input_data.cyclic_x.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_horizontal_pressure.value);// + current_flight_dynamics->input_data.cyclic_x_trim.value);
				}
				else
				{

					// restore x
					//Werewolf: Removed old debug code, removed redundant multiplications

					if (get_global_cyclic_input () == KEYBOARD_INPUT)
					{
						if (get_current_dynamics_options (DYNAMICS_OPTIONS_KEYBOARD_ASSISTANCE))
						{
							current_flight_dynamics->input_data.cyclic_x.value += ((1.0 / 16.0) * MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_x_trim.value - current_flight_dynamics->input_data.cyclic_x.value);
						}
						else
						{
							current_flight_dynamics->input_data.cyclic_x.value += ((3.0 / 4.0) * MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_x_trim.value - current_flight_dynamics->input_data.cyclic_x.value);
						}
					}
					else if (get_global_cyclic_input () == MOUSE_INPUT)
					{
						if (fabs (current_flight_dynamics->input_data.cyclic_x.value) < 5.0)
						{
							current_flight_dynamics->input_data.cyclic_x.value *= 0.8;
						}
					}
				}

				if (current_flight_dynamics->input_data.cyclic_vertical_pressure.value)
				{
					//current_flight_dynamics->input_data.cyclic_y.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_vertical_pressure.value + current_flight_dynamics->input_data.cyclic_y_trim.value);
					current_flight_dynamics->input_data.cyclic_y.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_vertical_pressure.value);// + current_flight_dynamics->input_data.cyclic_y_trim.value);
				}
				else
				{

					// restore y

					if (get_global_cyclic_input () == KEYBOARD_INPUT)
					{
						if (get_current_dynamics_options (DYNAMICS_OPTIONS_KEYBOARD_ASSISTANCE))
						{
							current_flight_dynamics->input_data.cyclic_y.value += ((1.0 / 16.0) * MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_y_trim.value - current_flight_dynamics->input_data.cyclic_y.value);
						}
						else
						{
							current_flight_dynamics->input_data.cyclic_y.value += ((3.0 / 4.0) * MODEL_FRAME_RATE * get_model_delta_time ()) * (current_flight_dynamics->input_data.cyclic_y_trim.value - current_flight_dynamics->input_data.cyclic_y.value);
						}
					}
					else if (get_global_cyclic_input () == MOUSE_INPUT)
					{
						if (fabs (current_flight_dynamics->input_data.cyclic_y.value) < 5.0)
						{
							debug_fatal ("CYCLIC: code with delta time");
							current_flight_dynamics->input_data.cyclic_y.value *= 0.8;
						}
					}
				}

				break;
			}

			case JOYSTICK_INPUT:
			{

				int
					joyval;

				float
					input;

				// 030418 loke
				// implemented multiple joystick device selection

				// x

				if (command_line_cyclic_joystick_index == -1)
				{
					joyval = get_joystick_axis (current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_ROLL);
				}
				else
				{
					joyval = get_joystick_axis (command_line_cyclic_joystick_index, command_line_cyclic_joystick_x_axis);
				}

				if (command_line_nonlinear_cyclic)
				{
					// in non-linear mode it uses a curve described by f(x) = x*x + x
					// gives a not so sensitive control around centre
					input = (2.0 * (float) joyval ) / ((float) JOYSTICK_AXIS_MAXIMUM - (float) JOYSTICK_AXIS_MINIMUM);
					if (input >= 0)
						input *= input;
					else
						input *= -input;
					input += input;
					input *= 50;
				}
				else
					input = (float) (200.0 * (float) joyval ) / ((float) JOYSTICK_AXIS_MAXIMUM - (float) JOYSTICK_AXIS_MINIMUM);

				if (fabs (input) < command_line_dynamics_cyclic_dead_zone)
				{

					input = 0.0;
				}

				current_flight_dynamics->input_data.cyclic_x.value = input;
        
        //ataribaby 1/1/2009 allow trim with ALT HOLD
				if (current_flight_dynamics->auto_hover == HOVER_HOLD_NONE || current_flight_dynamics->auto_hover == HOVER_HOLD_ALTITUDE_LOCK)
					current_flight_dynamics->input_data.cyclic_x.value += current_flight_dynamics->input_data.cyclic_x_trim.value;

				// y

				if (command_line_cyclic_joystick_index == -1)
				{
					joyval = get_joystick_axis (current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_PITCH);
				}
				else
				{
					joyval = get_joystick_axis (command_line_cyclic_joystick_index, command_line_cyclic_joystick_y_axis);
				}

				if (command_line_nonlinear_cyclic)
				{
					// in non-linear mode it uses a curve described by f(x) = x*x + x
					// gives a not so sensitive control around centre
					input = -2.0 * ((float) joyval ) / ((float) JOYSTICK_AXIS_MAXIMUM - (float) JOYSTICK_AXIS_MINIMUM);
					if (input >= 0)
						input *= input;
					else
						input *= -input;
					input += input;
					input *= 50.0;
				}
				else
					input = -(float) (200.0 * joyval) / (JOYSTICK_AXIS_MAXIMUM - JOYSTICK_AXIS_MINIMUM);

				if (fabs (input) < command_line_dynamics_cyclic_dead_zone)
				{

					input = 0.0;
				}

				current_flight_dynamics->input_data.cyclic_y.value = input;
        
        //ataribaby 1/1/2009 allow trim with ALT HOLD 
				if (current_flight_dynamics->auto_hover == HOVER_HOLD_NONE || current_flight_dynamics->auto_hover == HOVER_HOLD_ALTITUDE_LOCK)
					current_flight_dynamics->input_data.cyclic_y.value += current_flight_dynamics->input_data.cyclic_y_trim.value;

				/*
				debug_log ("CYCLIC: x %f, y %f", ((float) fabs (200.0 * get_joystick_axis(current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_ROLL) / (JOYSTICK_AXIS_MAXIMUM - JOYSTICK_AXIS_MINIMUM)),
					((float) fabs (200.0 * get_joystick_axis(current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_PITCH)) / (JOYSTICK_AXIS_MAXIMUM - JOYSTICK_AXIS_MINIMUM)));
				*/

				{
					// 030418 loke
					// implemented multiple joystick device selection

					int
						joystick_x_pos,
						joystick_y_pos;

					if (command_line_cyclic_joystick_index == -1)
					{
						joystick_x_pos = get_joystick_axis (current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_ROLL);
						joystick_y_pos = get_joystick_axis (current_flight_dynamics->input_data.cyclic_joystick_device_index, JOYSTICK_DEFAULT_AXIS_PITCH);
					}
					else
					{
						joystick_x_pos = get_joystick_axis (command_line_cyclic_joystick_index, command_line_cyclic_joystick_x_axis);
						joystick_y_pos = get_joystick_axis (command_line_cyclic_joystick_index, command_line_cyclic_joystick_y_axis);
					}

					if (((float) fabs (200.0 * joystick_x_pos) / (JOYSTICK_AXIS_MAXIMUM - JOYSTICK_AXIS_MINIMUM) > 10.0) ||
						((float) fabs (200.0 * joystick_y_pos) / (JOYSTICK_AXIS_MAXIMUM - JOYSTICK_AXIS_MINIMUM) > 10.0))
					{

						if ((current_flight_dynamics->auto_hover == HOVER_HOLD_NORMAL) ||
							(current_flight_dynamics->auto_hover == HOVER_HOLD_STABLE))
						{

							set_current_flight_dynamics_auto_hover (HOVER_HOLD_NONE);
							set_current_flight_dynamics_auto_pilot (FALSE);
						}
					}
				}

				break;
			}
		}

	//
	// DEBUG - to get the coolie hat working
	//
	#if 0
	{

		joystick_hat_position
			coolie_position;

		coolie_position = get_joystick_hat( &joystick_devices [current_flight_dynamics->input_data.cyclic_joystick_device_index], 0 );

		switch( coolie_position ) {
		case HAT_CENTERED:
			debug_log ("CYCLIC: coolie centered");
			break;
		case HAT_UP:
			debug_log ("CYCLIC: coolie up");
			break;
		case HAT_LEFT:
			debug_log ("CYCLIC: coolie left");
			break;
		case HAT_DOWN:
			debug_log ("CYCLIC: coolie down");
			break;
		case HAT_RIGHT:
			debug_log ("CYCLIC: coolie right");
			break;
		case HAT_LEFTUP:
			debug_log ("CYCLIC: coolie left+up");
			break;
		case HAT_LEFTDOWN:
			debug_log ("CYCLIC: coolie left+down");
			break;
		case HAT_RIGHTUP:
			debug_log ("CYCLIC: coolie right+up");
			break;
		case HAT_RIGHTDOWN:
			debug_log ("CYCLIC: coolie right+down");
			break;
		default:
			debug_log ("CYCLIC: coolie is on fire");
		}
	}
	#endif

	//
	// Damaged hydraulics
	//

	if (current_flight_dynamics->input_data.cyclic_x.damaged)
	{
		current_flight_dynamics->input_data.cyclic_x.value *= hydraulic_pressure;
		current_flight_dynamics->input_data.cyclic_x.value += damaged_lock_x_pos * (1.0 - hydraulic_pressure);
	}

	if (current_flight_dynamics->input_data.cyclic_y.damaged)
	{
		current_flight_dynamics->input_data.cyclic_y.value *= hydraulic_pressure;
		current_flight_dynamics->input_data.cyclic_y.value += damaged_lock_y_pos * (1.0 - hydraulic_pressure);
	}

	//
	// Damaged Stabaliser
	//

	if (current_flight_dynamics->input_data.cyclic_x_trim.damaged)
		current_flight_dynamics->input_data.cyclic_x_trim.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * (0.5 * sfrand1 () * current_flight_dynamics->input_data.cyclic_x_trim.value);

	if (current_flight_dynamics->input_data.cyclic_y_trim.damaged)
		current_flight_dynamics->input_data.cyclic_y_trim.value += (MODEL_FRAME_RATE * get_model_delta_time ()) * (0.5 * sfrand1 () * current_flight_dynamics->input_data.cyclic_y_trim.value);

	// limit cyclic position

	current_flight_dynamics->input_data.cyclic_x.value = bound (
												//current_flight_dynamics->input_data.cyclic_x.value + current_flight_dynamics->input_data.cyclic_x_trim.value,
												current_flight_dynamics->input_data.cyclic_x.value,
												current_flight_dynamics->input_data.cyclic_x.min,
												current_flight_dynamics->input_data.cyclic_x.max
												);

	current_flight_dynamics->input_data.cyclic_y.value = bound (
												//current_flight_dynamics->input_data.cyclic_y.value + current_flight_dynamics->input_data.cyclic_y_trim.value,
												current_flight_dynamics->input_data.cyclic_y.value,
												current_flight_dynamics->input_data.cyclic_y.min,
												current_flight_dynamics->input_data.cyclic_y.max
												);
}
示例#8
0
void update_3d_rain ( env_3d *env, float time, matrix3x3 view_attitude )
{

	int
		start_raindrop_number,
		end_raindrop_number,
		total_raindrop_number,

		start_snowdrop_number,
		end_snowdrop_number,
		total_snowdrop_number,

		creation_allowed,
		count;

	float
		displacement_magnitude,
		snow_displacement_magnitude,
		snow_fall_displacement,
		weather_t;

	vec3d
		distance_moved,
		rain_displacement,
		snow_drift_displacement,
		rain_streak_displacement,
		creation_vector;

	//
	// Calculate how many rain drops we should have. This is a linear scale, from 0, to TOTAL_3D_RAINDROPS.
	//  DRY = 0
	//  LIGHT_RAIN = TOTAL_3D_RAINDROPS / 2
	//  HEAVY_RAIN = TOTAL_3D_RAINDROPS
	//

	if ( visual_3d_vp )
	{

		if ( visual_3d_vp->position.y > get_cloud_3d_base_height () )
		{

			creation_allowed = FALSE;
		}
		else
		{

			creation_allowed = TRUE;
		}
	}
	else
	{

		creation_allowed = FALSE;
	}

	start_raindrop_number = number_of_weather_particles_allowed[env->weathermode].number_of_raindrops;
	start_snowdrop_number = number_of_weather_particles_allowed[env->weathermode].number_of_snowdrops;

	end_raindrop_number = number_of_weather_particles_allowed[env->target_weathermode].number_of_raindrops;
	end_snowdrop_number = number_of_weather_particles_allowed[env->target_weathermode].number_of_snowdrops;

	weather_t = env->weather_targetdistance;

	if ( weather_t == 0 )
	{

		total_raindrop_number = start_raindrop_number;
		total_snowdrop_number = start_snowdrop_number;
	}
	else if ( weather_t == 1 )
	{

		total_raindrop_number = end_raindrop_number;
		total_snowdrop_number = end_snowdrop_number;
	}
	else
	{

		total_raindrop_number = start_raindrop_number + ( ( ( float ) ( end_raindrop_number - start_raindrop_number ) ) * weather_t );
		total_snowdrop_number = start_snowdrop_number + ( ( ( float ) ( end_snowdrop_number - start_snowdrop_number ) ) * weather_t );
	}

	//
	// Special snow flag stuff
	//

	if ( special_snow_flag )
	{
/*
		if ( visual_3d_vp )
		{

			int
				x,
				z;

			int
				near_snow;

			float
				old_rain_total;

			near_snow = FALSE;

			for ( z = -1; z <= 1; z++ )
			{

				for ( x = -1; x <= 1; x++ )
				{

					float
						x_pos,
						z_pos;

					x_pos = visual_3d_vp->x + x * TERRAIN_3D_SECTOR_SIDE_LENGTH;
					z_pos = visual_3d_vp->z + z * TERRAIN_3D_SECTOR_SIDE_LENGTH;

					x_pos = bound ( x_pos, terrain_3d_min_map_x, terrain_3d_max_map_x );
					z_pos = bound ( z_pos, terrain_3d_min_map_z, terrain_3d_max_map_z );

					get_terrain_3d_types_in_sector ( x_pos, z_pos );

					if ( terrain_types_in_sector[TERRAIN_TYPE_ALTERED_LAND3] )
					{

						near_snow = TRUE;
					}
				}
			}

			if ( near_snow )
			{

				old_rain_total = total_raindrop_number;

				total_raindrop_number = old_rain_total * 0.0;
				total_snowdrop_number = old_rain_total * 1.0;
			}
		}
		*/
	}

	//
	//
	//

	rain_3d_delta_time = time - time_rain_last_updated;

	time_rain_last_updated = time;

	//
	// Calculate the distance moved by each raindrop.
	//

	distance_moved.x = rain_3d_wind_direction.x * rain_3d_wind_speed * rain_3d_delta_time;
	distance_moved.y = rain_3d_wind_direction.y * rain_3d_wind_speed * rain_3d_delta_time;
	distance_moved.z = rain_3d_wind_direction.z * rain_3d_wind_speed * rain_3d_delta_time;

	rain_displacement.x = distance_moved.x;
	rain_displacement.y = distance_moved.y + ( rain_3d_speed * rain_3d_delta_time );
	rain_displacement.z = distance_moved.z;

	//
	// Calculate the distance moved by each snowdrop.
	//

	snow_drift_displacement.x = distance_moved.x;
	snow_drift_displacement.y = distance_moved.y;
	snow_drift_displacement.z = distance_moved.z;

	snow_fall_displacement = ( rain_3d_speed / 4 ) * rain_3d_delta_time;

	snow_displacement_magnitude = get_3d_vector_magnitude ( &snow_drift_displacement );

	//
	// Calculate the 'streak' effect - this is now NOT framerate related
	//

	rain_streak_displacement = rain_displacement;

	displacement_magnitude = get_3d_vector_magnitude ( &rain_streak_displacement );

	if ( displacement_magnitude != 0 )
	{

		displacement_magnitude = 1.5 / displacement_magnitude;

		rain_streak_displacement.x *= displacement_magnitude;
		rain_streak_displacement.y *= displacement_magnitude;
		rain_streak_displacement.z *= displacement_magnitude;
	}
	else
	{

		//
		// Put artificial streaking in there ( game paused )
		//

		rain_streak_displacement.x = rain_3d_wind_direction.x * rain_3d_wind_speed * 0.05;
		rain_streak_displacement.y = rain_3d_wind_direction.y * rain_3d_wind_speed * 0.05 + ( rain_3d_speed * 0.05 );
		rain_streak_displacement.z = rain_3d_wind_direction.z * rain_3d_wind_speed * 0.05;

		displacement_magnitude = get_3d_vector_magnitude ( &rain_streak_displacement );

		if ( displacement_magnitude != 0 )
		{

			displacement_magnitude = 1.5 / displacement_magnitude;

			rain_streak_displacement.x *= displacement_magnitude;
			rain_streak_displacement.y *= displacement_magnitude;
			rain_streak_displacement.z *= displacement_magnitude;
		}
	}

	//
	// Remove any raindrops that have strayed out of the area of effect
	//

	creation_vector.x = rain_3d_wind_direction.x * rain_3d_wind_speed * 0.5;
	creation_vector.y = rain_3d_wind_direction.y * rain_3d_wind_speed * 0.5 + ( rain_3d_speed * 0.5 );
	creation_vector.z = rain_3d_wind_direction.z * rain_3d_wind_speed * 0.5;

	normalise_any_3d_vector ( &creation_vector );

	for ( count = 0; count < TOTAL_3D_RAINDROPS; count++ )
	{

		switch ( rain_3d_drops[count].type )
		{

			case RAINDROP_RAIN:
			{

				vec3d
					rel;

				//
				// Update the rain position
				//

				rain_3d_drops[count].current_position.x -= rain_displacement.x;
				rain_3d_drops[count].current_position.y -= rain_displacement.y;
				rain_3d_drops[count].current_position.z -= rain_displacement.z;

				rel.x = rain_3d_drops[count].current_position.x - visual_3d_vp->x;
				rel.y = rain_3d_drops[count].current_position.y - visual_3d_vp->y;
				rel.z = rain_3d_drops[count].current_position.z - visual_3d_vp->z;

				if (
						( rel.x > RAINDROPS_AREA_WIDTH ) || ( rel.x < ( -RAINDROPS_AREA_WIDTH ) ) ||
						( rel.y > RAINDROPS_AREA_HEIGHT ) || ( rel.y < ( -RAINDROPS_AREA_HEIGHT ) ) ||
						( rel.z > RAINDROPS_AREA_DEPTH ) || ( rel.z < ( -RAINDROPS_AREA_DEPTH ) )
					)
				{


					rain_3d_raindrops_valid--;

					rain_3d_drops[count].type = RAINDROP_INVALID;
				}

				break;
			}

			case RAINDROP_SNOW:
			{

				vec3d
					snow_noise,
					rel;

				float
					relative_speed;

				//
				// Update the rain position
				//

				snow_noise.x = sfrand1 () * rain_3d_delta_time;	//0.1	;//snow_displacement_magnitude;
				snow_noise.y = sfrand1 () * rain_3d_delta_time;	//0.1	;//snow_displacement_magnitude;
				snow_noise.z = sfrand1 () * rain_3d_delta_time;	//0.1	;//snow_displacement_magnitude;

				relative_speed = rain_3d_drops[count].relative_speed;

				rain_3d_drops[count].current_position.x -= ( snow_drift_displacement.x + snow_noise.x );
				rain_3d_drops[count].current_position.y -= ( snow_drift_displacement.y );
				rain_3d_drops[count].current_position.z -= ( snow_drift_displacement.z + snow_noise.x );

				rain_3d_drops[count].current_position.y -= ( snow_fall_displacement * relative_speed );

				rel.x = rain_3d_drops[count].current_position.x - visual_3d_vp->x;
				rel.y = rain_3d_drops[count].current_position.y - visual_3d_vp->y;
				rel.z = rain_3d_drops[count].current_position.z - visual_3d_vp->z;

				if (
						( rel.x > SNOWDROPS_AREA_WIDTH ) || ( rel.x < ( -SNOWDROPS_AREA_WIDTH ) ) ||
						( rel.y > SNOWDROPS_AREA_HEIGHT ) || ( rel.y < ( -SNOWDROPS_AREA_HEIGHT ) ) ||
						( rel.z > SNOWDROPS_AREA_DEPTH ) || ( rel.z < ( -SNOWDROPS_AREA_DEPTH ) )
					)
				{

					rain_3d_snowdrops_valid--;

					rain_3d_drops[count].type = RAINDROP_INVALID;
				}

				break;
			}
		}

		if ( ( rain_3d_drops[count].type == RAINDROP_INVALID ) && ( creation_allowed ) )
		{

			if ( rain_3d_raindrops_valid < total_raindrop_number )
			{

				float
					x,
					y,
					z,
					creation_distance;

				//
				// Generate a new rain drop randomly
				//

				z = ( ( frand1 () * 0.8 ) + 0.2 ) * ( RAINDROPS_AREA_DEPTH / 5 );
				x = sfrand1 () * ( RAINDROPS_AREA_WIDTH / 5 );
				y = sfrand1 () * ( RAINDROPS_AREA_HEIGHT / 5 );

				x *= z / 50;
				y *= z / 50;

				//
				// Now project along the motion vector
				//

				creation_distance = frand1 () * 8;
				x += creation_vector.x * creation_distance;
				y += creation_vector.y * creation_distance;
				z += creation_vector.z * creation_distance;

				//
				// Rotate this back into the view coordinate system
				//

				rain_3d_drops[count].current_position.x = x * view_attitude[0][0] + y * view_attitude[1][0] + z * view_attitude[2][0];
				rain_3d_drops[count].current_position.y = x * view_attitude[0][1] + y * view_attitude[1][1] + z * view_attitude[2][1];
				rain_3d_drops[count].current_position.z = x * view_attitude[0][2] + y * view_attitude[1][2] + z * view_attitude[2][2];

				rain_3d_drops[count].current_position.x += visual_3d_vp->x;
				rain_3d_drops[count].current_position.y += visual_3d_vp->y;
				rain_3d_drops[count].current_position.z += visual_3d_vp->z;

				rain_3d_drops[count].type = RAINDROP_RAIN;

				rain_3d_raindrops_valid++;
			}
			else if ( rain_3d_snowdrops_valid < total_snowdrop_number )
			{

				float
					x,
					y,
					z,
					creation_distance;

				//
				// Generate a new snowdrop
				//

				z = ( ( frand1 () * 0.8 ) + 0.2 ) * ( SNOWDROPS_AREA_DEPTH / 5 );
				x = sfrand1 () * ( SNOWDROPS_AREA_WIDTH / 5 );
				y = sfrand1 () * ( SNOWDROPS_AREA_HEIGHT / 5 );

				x *= z / 50;
				y *= z / 50;

				//
				// Now project along the motion vector
				//

				creation_distance = frand1 () * 8;
				x += creation_vector.x * creation_distance;
				y += creation_vector.y * creation_distance;
				z += creation_vector.z * creation_distance;

				//
				// Rotate this back into the view coordinate system
				//

				rain_3d_drops[count].current_position.x = x * view_attitude[0][0] + y * view_attitude[1][0] + z * view_attitude[2][0];
				rain_3d_drops[count].current_position.y = x * view_attitude[0][1] + y * view_attitude[1][1] + z * view_attitude[2][1];
				rain_3d_drops[count].current_position.z = x * view_attitude[0][2] + y * view_attitude[1][2] + z * view_attitude[2][2];

				rain_3d_drops[count].current_position.x += visual_3d_vp->x;
				rain_3d_drops[count].current_position.y += visual_3d_vp->y;
				rain_3d_drops[count].current_position.z += visual_3d_vp->z;

				rain_3d_drops[count].relative_speed = ( frand1() * 0.5 ) + 0.5;

				rain_3d_drops[count].type = RAINDROP_SNOW;

				rain_3d_snowdrops_valid++;
			}
		}
	}

	//
	// Now calculate the predicted positions for rendering
	//

	for ( count = 0; count < TOTAL_3D_RAINDROPS; count++ )
	{

		if ( rain_3d_drops[count].type == RAINDROP_RAIN )
		{

			rain_3d_drops[count].predicted_position.x = rain_3d_drops[count].current_position.x - rain_streak_displacement.x;
			rain_3d_drops[count].predicted_position.y = rain_3d_drops[count].current_position.y - rain_streak_displacement.y;
			rain_3d_drops[count].predicted_position.z = rain_3d_drops[count].current_position.z - rain_streak_displacement.z;
		}
	}
}