// Checks debris-weapon collisions.  pair->a is debris and pair->b is weapon.
// Returns 1 if all future collisions between these can be ignored
int collide_debris_weapon( obj_pair * pair )
{
	vector	hitpos;
	int		hit;
	object *pdebris = pair->a;
	object *weapon = pair->b;

	Assert( pdebris->type == OBJ_DEBRIS );
	Assert( weapon->type == OBJ_WEAPON );

	// first check the bounding spheres of the two objects.
	hit = fvi_segment_sphere(&hitpos, &weapon->last_pos, &weapon->pos, &pdebris->pos, pdebris->radius);
	if (hit) {
		hit = debris_check_collision(pdebris, weapon, &hitpos );
		if ( !hit )
			return 0;

		weapon_hit( weapon, pdebris, &hitpos );
		debris_hit( pdebris, weapon, &hitpos, Weapon_info[Weapons[weapon->instance].weapon_info_index].damage );
		return 0;

	} else {
		return weapon_will_never_hit( weapon, pdebris, pair );
	}
}				
/**
 * Checks debris-weapon collisions.  
 * @param pair obj_pair pointer to the two objects. pair->a is debris and pair->b is weapon.
 * @return 1 if all future collisions between these can be ignored
 */
int collide_debris_weapon( obj_pair * pair )
{
	vec3d	hitpos, hitnormal;
	int		hit;
	object *pdebris = pair->a;
	object *weapon_obj = pair->b;

	Assert( pdebris->type == OBJ_DEBRIS );
	Assert( weapon_obj->type == OBJ_WEAPON );

	// first check the bounding spheres of the two objects.
	hit = fvi_segment_sphere(&hitpos, &weapon_obj->last_pos, &weapon_obj->pos, &pdebris->pos, pdebris->radius);
	if (hit) {
		hit = debris_check_collision(pdebris, weapon_obj, &hitpos, NULL, &hitnormal );

		if ( !hit )
			return 0;

		Script_system.SetHookObjects(4, "Weapon", weapon_obj, "Debris", pdebris, "Self", weapon_obj, "Object", pdebris);
		bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, weapon_obj);

		Script_system.SetHookObjects(2, "Self", pdebris, "Object", weapon_obj);
		bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, pdebris);

		if(!weapon_override && !debris_override)
		{
			weapon_hit( weapon_obj, pdebris, &hitpos, -1, &hitnormal );
			debris_hit( pdebris, weapon_obj, &hitpos, Weapon_info[Weapons[weapon_obj->instance].weapon_info_index].damage );
		}

		Script_system.SetHookObjects(2, "Self", weapon_obj, "Object", pdebris);
		if(!(debris_override && !weapon_override))
			Script_system.RunCondition(CHA_COLLIDEDEBRIS, '\0', NULL, weapon_obj);

		Script_system.SetHookObjects(2, "Self", pdebris, "Object", weapon_obj);
		if((debris_override && !weapon_override) || (!debris_override && !weapon_override))
			Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, pdebris, Weapons[weapon_obj->instance].weapon_info_index);

		Script_system.RemHookVars(4, "Weapon", "Debris", "Self", "Object");
		return 0;

	} else {
		return weapon_will_never_hit( weapon_obj, pdebris, pair );
	}
}				
/**
 * Checks debris-ship collisions.  
 * @param pair obj_pair pointer to the two objects. pair->a is debris and pair->b is ship.
 * @return 1 if all future collisions between these can be ignored
 */
int collide_debris_ship( obj_pair * pair )
{
	float dist;
	object *pdebris = pair->a;
	object *pship = pair->b;

	// Don't check collisions for warping out player
	if ( Player->control_mode != PCM_NORMAL )	{
		if ( pship == Player_obj )
			return 0;
	}

	Assert( pdebris->type == OBJ_DEBRIS );
	Assert( pship->type == OBJ_SHIP );

	// don't check collision if it's our own debris and we are dying
	if ( (pdebris->parent == OBJ_INDEX(pship)) && (Ships[pship->instance].flags[Ship::Ship_Flags::Dying]) )
		return 0;

	dist = vm_vec_dist( &pdebris->pos, &pship->pos );
	if ( dist < pdebris->radius + pship->radius )	{
		int hit;
		vec3d	hitpos;
		// create and initialize ship_ship_hit_info struct
		collision_info_struct debris_hit_info;
		init_collision_info_struct(&debris_hit_info);

		if ( pdebris->phys_info.mass > pship->phys_info.mass ) {
			debris_hit_info.heavy = pdebris;
			debris_hit_info.light = pship;
		} else {
			debris_hit_info.heavy = pship;
			debris_hit_info.light = pdebris;
		}

		hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info );
		if ( hit )
		{
			Script_system.SetHookObjects(4, "Ship", pship, "Debris", pdebris, "Self", pship, "Object", pdebris);
			bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, pship);

			Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
			bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pdebris);
			if(!ship_override && !debris_override)
			{
				float		ship_damage;	
				float		debris_damage;

				// do collision physics
				calculate_ship_ship_collision_physics( &debris_hit_info );

				if ( debris_hit_info.impulse < 0.5f )
					return 0;

				// calculate ship damage
				ship_damage = 0.005f * debris_hit_info.impulse;	//	Cut collision-based damage in half.
				//	Decrease heavy damage by 2x.
				if (ship_damage > 5.0f)
					ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f;

				// calculate debris damage and set debris damage to greater or debris and ship
				// debris damage is needed since we can really whack some small debris with afterburner and not do
				// significant damage to ship but the debris goes off faster than afterburner speed.
				debris_damage = debris_hit_info.impulse/pdebris->phys_info.mass;	// ie, delta velocity of debris
				debris_damage = (debris_damage > ship_damage) ? debris_damage : ship_damage;

				// modify ship damage by debris damage multiplier
				ship_damage *= Debris[pdebris->instance].damage_mult;

				// supercaps cap damage at 10-20% max hull ship damage
				if (Ship_info[Ships[pship->instance].ship_info_index].flags[Ship::Info_Flags::Supercap]) {
					float cap_percent_damage = frand_range(0.1f, 0.2f);
					ship_damage = MIN(ship_damage, cap_percent_damage * Ships[pship->instance].ship_max_hull_strength);
				}

				// apply damage to debris
				debris_hit( pdebris, pship, &hitpos, debris_damage);		// speed => damage
				int quadrant_num, apply_ship_damage;

				// apply damage to ship unless 1) debris is from ship
				apply_ship_damage = !(pship->signature == pdebris->parent_sig);

				if ( debris_hit_info.heavy == pship ) {
					quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
					if ((pship->flags[Object::Object_Flags::No_shields]) || !ship_is_shield_up(pship, quadrant_num) ) {
						quadrant_num = -1;
					}
					if (apply_ship_damage) {
						ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, debris_hit_info.submodel_num);
					}
				} else {
					// don't draw sparks using sphere hit position
					if (apply_ship_damage) {
						ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS);
					}
				}

				// maybe print Collision on HUD
				if ( pship == Player_obj ) {					
					hud_start_text_flash(XSTR("Collision", 1431), 2000);
				}

				collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj);
			}

			Script_system.SetHookObjects(2, "Self",pship, "Object", pdebris);
			if(!(debris_override && !ship_override))
				Script_system.RunCondition(CHA_COLLIDEDEBRIS, '\0', NULL, pship);

			Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
			if((debris_override && !ship_override) || (!debris_override && !ship_override))
				Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, pdebris);

			Script_system.RemHookVars(4, "Ship", "Debris", "Self", "Object");

			return 0;
		}
	} else {	//	Bounding spheres don't intersect, set timestamp for next collision check.
		float	ship_max_speed, debris_speed;
		float	time;
		ship *shipp;

		shipp = &Ships[pship->instance];

		if (ship_is_beginning_warpout_speedup(pship)) {
			ship_max_speed = MAX(ship_get_max_speed(shipp), ship_get_warpout_speed(pship));
		} else {
			ship_max_speed = ship_get_max_speed(shipp);
		}
		ship_max_speed = MAX(ship_max_speed, 10.0f);
		ship_max_speed = MAX(ship_max_speed, pship->phys_info.vel.xyz.z);

		debris_speed = pdebris->phys_info.speed;

		time = 1000.0f * (dist - pship->radius - pdebris->radius - 10.0f) / (ship_max_speed + debris_speed);		// 10.0f is a safety factor
		time -= 200.0f;		// allow one frame slow frame at ~5 fps

		if (time > 100) {
			pair->next_check_time = timestamp( fl2i(time) );
		} else {
			pair->next_check_time = timestamp(0);	// check next time
		}
	}

	return 0;
}
Example #4
0
// Checks debris-ship collisions.  pair->a is debris and pair->b is ship.
// Returns 1 if all future collisions between these can be ignored
int collide_debris_ship( obj_pair * pair )
{
	float dist;
	object *pdebris = pair->a;
	object *pship = pair->b;

		// Don't check collisions for warping out player
	if ( Player->control_mode != PCM_NORMAL )	{
		if ( pship == Player_obj )
			return 0;
	}

	Assert( pdebris->type == OBJ_DEBRIS );
	Assert( pship->type == OBJ_SHIP );

/*	Debris_ship_count++;
	if (Debris_ship_count % 100 == 0)
		nprintf(("AI", "Done %i debris:ship checks in %i frames = %.2f checks/frame\n", Debris_ship_count, Framecount, (float) Debris_ship_count/Framecount));
*/
	dist = vm_vec_dist( &pdebris->pos, &pship->pos );
	if ( dist < pdebris->radius + pship->radius )	{
		int hit;
		vector	hitpos;
		// create and initialize ship_ship_hit_info struct
		collision_info_struct debris_hit_info;
		memset( &debris_hit_info, -1, sizeof(collision_info_struct) );

		if ( pdebris->phys_info.mass > pship->phys_info.mass ) {
			debris_hit_info.heavy = pdebris;
			debris_hit_info.light = pship;
		} else {
			debris_hit_info.heavy = pship;
			debris_hit_info.light = pdebris;
		}

		hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info );
		if ( hit ) {
			float		ship_damage;	
			float		debris_damage;

			// do collision physics
			calculate_ship_ship_collision_physics( &debris_hit_info );

			if ( debris_hit_info.impulse < 0.5f )
				return 0;

			// calculate ship damage
			ship_damage = 0.005f * debris_hit_info.impulse;	//	Cut collision-based damage in half.
			//	Decrease heavy damage by 2x.
			if (ship_damage > 5.0f)
				ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f;

			// calculate debris damage and set debris damage to greater or debris and ship
			// debris damage is needed since we can really whack some small debris with afterburner and not do
			// significant damage to ship but the debris goes off faster than afterburner speed.
			debris_damage = debris_hit_info.impulse/pdebris->phys_info.mass;	// ie, delta velocity of debris
			debris_damage = (debris_damage > ship_damage) ? debris_damage : ship_damage;

			// supercaps cap damage at 10-20% max hull ship damage
			if (Ship_info[Ships[pship->instance].ship_info_index].flags & SIF_SUPERCAP) {
				float cap_percent_damage = frand_range(0.1f, 0.2f);
				ship_damage = min(ship_damage, cap_percent_damage * Ship_info[Ships[pship->instance].ship_info_index].initial_hull_strength);
			}

			// apply damage to debris
			debris_hit( pdebris, pship, &hitpos, debris_damage);		// speed => damage
			int quadrant_num, apply_ship_damage;

			// apply damage to ship unless 1) debris is from ship
			// apply_ship_damage = !((pship->signature == pdebris->parent_sig) && ship_is_beginning_warpout_speedup(pship));
			apply_ship_damage = !(pship->signature == pdebris->parent_sig);

			if ( debris_hit_info.heavy == pship ) {
				quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
				if ((pship->flags & OF_NO_SHIELDS) || !ship_is_shield_up(pship, quadrant_num) ) {
					quadrant_num = -1;
				}
				if (apply_ship_damage) {
					ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, debris_hit_info.submodel_num);
				}
			} else {
				// don't draw sparks using sphere hit position
				if (apply_ship_damage) {
					ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS);
				}
			}

			// maybe print Collision on HUD
			if ( pship == Player_obj ) {					
				hud_start_text_flash(XSTR("Collision", 1431), 2000);
			}

			collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj);

			return 0;
		}
	} else {	//	Bounding spheres don't intersect, set timestamp for next collision check.
		float	ship_max_speed, debris_speed;
		float	time;
		ship *shipp;

		shipp = &Ships[pship->instance];

		if (ship_is_beginning_warpout_speedup(pship)) {
			ship_max_speed = max(ship_get_max_speed(shipp), ship_get_warp_speed(pship));
		} else {
			ship_max_speed = ship_get_max_speed(shipp);
		}
		ship_max_speed = max(ship_max_speed, 10.0f);
		ship_max_speed = max(ship_max_speed, pship->phys_info.vel.xyz.z);

		debris_speed = pdebris->phys_info.speed;

		time = 1000.0f * (dist - pship->radius - pdebris->radius - 10.0f) / (ship_max_speed + debris_speed);		// 10.0f is a safety factor
		time -= 200.0f;		// allow one frame slow frame at ~5 fps

		if (time > 100) {
			//nprintf(("AI", "Ship %s debris #%i delay time = %.1f seconds\n", Ships[pship->instance].ship_name, pdebris-Objects, time/1000.0f));
			pair->next_check_time = timestamp( fl2i(time) );
		} else {
			pair->next_check_time = timestamp(0);	// check next time
		}
	}

	return 0;
}