// What we're doing here is projecting each object extent onto the directrix, calculating the distance between the // projected point and the origin, and then taking the maximum distance as the semilatus rectum. We're actually // maintaining the square of the distance rather than the actual distance, as it's faster to calculate and it gives // the same result in a greater-than or less-than comparison. When we're done calculating everything for all // objects (i.e. when we return to the parent function) we take the square root of the final value. void dock_calc_max_semilatus_rectum_squared_parallel_to_directrix_helper(object *objp, dock_function_info *infop) { vec3d world_point, local_point[6], nearest; polymodel *pm; int i; float temp, dist_squared; // line parameters vec3d *line_start = infop->parameter_variables.vecp_value; vec3d *line_end = infop->parameter_variables.vecp_value2; // We must find world coordinates for each of the six endpoints on the three axes of the object. I looked up // which axis is front/back, left/right, and up/down, as well as which endpoint is which. It doesn't really // matter, though, as all we need are the distances. // grab our model Assert(objp->type == OBJ_SHIP); pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num); // set up the points we want to check memset(local_point, 0, sizeof(vec3d) * 6); local_point[0].xyz.x = pm->maxs.xyz.x; // right point (max x) local_point[1].xyz.x = pm->mins.xyz.x; // left point (min x) local_point[2].xyz.y = pm->maxs.xyz.y; // top point (max y) local_point[3].xyz.y = pm->mins.xyz.y; // bottom point (min y) local_point[4].xyz.z = pm->maxs.xyz.z; // front point (max z) local_point[5].xyz.z = pm->mins.xyz.z; // rear point (min z) // check points for (i = 0; i < 6; i++) { // calculate position of point vm_vec_rotate(&world_point, &local_point[i], &objp->orient); vm_vec_add2(&world_point, &objp->pos); // find the nearest point along the line vm_vec_dist_squared_to_line(&world_point, line_start, line_end, &nearest, &temp); // find the distance squared between the origin of the line and the point on the line dist_squared = vm_vec_dist_squared(line_start, &nearest); // update with farthest distance squared if (dist_squared > infop->maintained_variables.float_value) infop->maintained_variables.float_value = dist_squared; } }
/** * Checks ship-weapon collisions. * @param pair obj_pair pointer to the two objects. pair->a is ship and pair->b is weapon. * @return 1 if all future collisions between these can be ignored */ int collide_ship_weapon( obj_pair * pair ) { int did_hit; object *ship = pair->a; object *weapon_obj = pair->b; Assert( ship->type == OBJ_SHIP ); Assert( weapon_obj->type == OBJ_WEAPON ); ship_info *sip = &Ship_info[Ships[ship->instance].ship_info_index]; // Don't check collisions for player if past first warpout stage. if ( Player->control_mode > PCM_WARPOUT_STAGE1) { if ( ship == Player_obj ) return 0; } if (reject_due_collision_groups(ship, weapon_obj)) return 0; // Cull lasers within big ship spheres by casting a vector forward for (1) exit sphere or (2) lifetime of laser // If it does hit, don't check the pair until about 200 ms before collision. // If it does not hit and is within error tolerance, cull the pair. if ( (sip->is_big_or_huge()) && (Weapon_info[Weapons[weapon_obj->instance].weapon_info_index].subtype == WP_LASER) ) { // Check when within ~1.1 radii. // This allows good transition between sphere checking (leaving the laser about 200 ms from radius) and checking // within the sphere with little time between. There may be some time for "small" big ships // Note: culling ships with auto spread shields seems to waste more performance than it saves, // so we're not doing that here if ( !(sip->flags[Ship::Info_Flags::Auto_spread_shields]) && vm_vec_dist_squared(&ship->pos, &weapon_obj->pos) < (1.2f*ship->radius*ship->radius) ) { return check_inside_radius_for_big_ships( ship, weapon_obj, pair ); } } did_hit = ship_weapon_check_collision( ship, weapon_obj ); if ( !did_hit ) { // Since we didn't hit, check to see if we can disable all future collisions // between these two. return weapon_will_never_hit( weapon_obj, ship, pair ); } return 0; }
// Checks ship-weapon collisions. pair->a is ship and pair->b is weapon. // Returns 1 if all future collisions between these can be ignored int collide_ship_weapon( obj_pair * pair ) { int did_hit; object *ship = pair->a; object *weapon = pair->b; Assert( ship->type == OBJ_SHIP ); Assert( weapon->type == OBJ_WEAPON ); // Don't check collisions for player if past first warpout stage. if ( Player->control_mode > PCM_WARPOUT_STAGE1) { if ( ship == Player_obj ) return 0; } // Cull lasers within big ship spheres by casting a vector forward for (1) exit sphere or (2) lifetime of laser // If it does hit, don't check the pair until about 200 ms before collision. // If it does not hit and is within error tolerance, cull the pair. if ( (Ship_info[Ships[ship->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) && (Weapon_info[Weapons[weapon->instance].weapon_info_index].subtype == WP_LASER) ) { // if ( (ship->radius > 50) && (Weapon_info[Weapons[weapon->instance].weapon_info_index].subtype == WP_LASER) ) { // Check when within ~1.1 radii. // This allows good transition between sphere checking (leaving the laser about 200 ms from radius) and checking // within the sphere with little time between. There may be some time for "small" big ships if ( vm_vec_dist_squared(&ship->pos, &weapon->pos) < (1.2f*ship->radius*ship->radius) ) { return check_inside_radius_for_big_ships( ship, weapon, pair ); } } // demo_do_rand_test(); did_hit = ship_weapon_check_collision( ship, weapon ); // demo_do_rand_test(); if ( !did_hit ) { // Since we didn't hit, check to see if we can disable all future collisions // between these two. return weapon_will_never_hit( weapon, ship, pair ); } return 0; }
// Adds the pair to the pair list void obj_add_pair( object *A, object *B, int check_time, int add_to_end ) { uint ctype; int (*check_collision)( obj_pair *pair ); int swapped = 0; check_collision = NULL; if ( Num_pairs_allocated == 0 ) return; // don't have anything to add the pair too if ( A==B ) return; // Don't check collisions with yourself if ( !(A->flags&OF_COLLIDES) ) return; // This object doesn't collide with anything if ( !(B->flags&OF_COLLIDES) ) return; // This object doesn't collide with anything // Make sure you're not checking a parent with it's kid or vicy-versy // if ( A->parent_sig == B->signature && !(A->type == OBJ_SHIP && B->type == OBJ_DEBRIS) ) return; // if ( B->parent_sig == A->signature && !(A->type == OBJ_DEBRIS && B->type == OBJ_SHIP) ) return; if ( reject_obj_pair_on_parent(A,B) ) { return; } Assert( A->type < 127 ); Assert( B->type < 127 ); ctype = COLLISION_OF(A->type,B->type); switch( ctype ) { case COLLISION_OF(OBJ_WEAPON,OBJ_SHIP): swapped = 1; check_collision = collide_ship_weapon; break; case COLLISION_OF(OBJ_SHIP, OBJ_WEAPON): check_collision = collide_ship_weapon; break; case COLLISION_OF(OBJ_DEBRIS, OBJ_WEAPON): check_collision = collide_debris_weapon; break; case COLLISION_OF(OBJ_WEAPON, OBJ_DEBRIS): swapped = 1; check_collision = collide_debris_weapon; break; case COLLISION_OF(OBJ_DEBRIS, OBJ_SHIP): check_collision = collide_debris_ship; break; case COLLISION_OF(OBJ_SHIP, OBJ_DEBRIS): check_collision = collide_debris_ship; swapped = 1; break; case COLLISION_OF(OBJ_ASTEROID, OBJ_WEAPON): // Only check collision's with player weapons // if ( Objects[B->parent].flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_weapon; // } break; case COLLISION_OF(OBJ_WEAPON, OBJ_ASTEROID): swapped = 1; // Only check collision's with player weapons // if ( Objects[A->parent].flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_weapon; // } break; case COLLISION_OF(OBJ_ASTEROID, OBJ_SHIP): // Only check collisions with player ships // if ( B->flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_ship; // } break; case COLLISION_OF(OBJ_SHIP, OBJ_ASTEROID): // Only check collisions with player ships // if ( A->flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_ship; // } swapped = 1; break; case COLLISION_OF(OBJ_SHIP,OBJ_SHIP): check_collision = collide_ship_ship; break; case COLLISION_OF(OBJ_BEAM, OBJ_SHIP): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_ship; break; case COLLISION_OF(OBJ_BEAM, OBJ_ASTEROID): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_asteroid; break; case COLLISION_OF(OBJ_BEAM, OBJ_DEBRIS): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_debris; break; case COLLISION_OF(OBJ_BEAM, OBJ_WEAPON): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_missile; break; case COLLISION_OF(OBJ_WEAPON, OBJ_WEAPON): { weapon_info *awip, *bwip; awip = &Weapon_info[Weapons[A->instance].weapon_info_index]; bwip = &Weapon_info[Weapons[B->instance].weapon_info_index]; if ((awip->weapon_hitpoints > 0) || (bwip->weapon_hitpoints > 0)) { if (bwip->weapon_hitpoints == 0) { check_collision = collide_weapon_weapon; swapped=1; } else { check_collision = collide_weapon_weapon; } } /* if (awip->subtype != WP_LASER || bwip->subtype != WP_LASER) { if (awip->subtype == WP_LASER) { if ( bwip->wi_flags & WIF_BOMB ) { check_collision = collide_weapon_weapon; } } else if (bwip->subtype == WP_LASER) { if ( awip->wi_flags & WIF_BOMB ) { check_collision = collide_weapon_weapon; swapped=1; } } else { if ( (awip->wi_flags&WIF_BOMB) || (bwip->wi_flags&WIF_BOMB) ) { check_collision = collide_weapon_weapon; } } } */ /* int atype, btype; atype = Weapon_info[Weapons[A->instance].weapon_info_index].subtype; btype = Weapon_info[Weapons[B->instance].weapon_info_index].subtype; if ((atype == WP_LASER) && (btype == WP_MISSILE)) check_collision = collide_weapon_weapon; else if ((atype == WP_MISSILE) && (btype == WP_LASER)) { check_collision = collide_weapon_weapon; swapped = 1; } else if ((atype == WP_MISSILE) && (btype == WP_MISSILE)) check_collision = collide_weapon_weapon; */ break; } default: return; } // Swap them if needed if ( swapped ) { object *tmp = A; A = B; B = tmp; } // if there are any more obj_pair checks // we should then add function int maybe_not_add_obj_pair() // MWA -- 4/1/98 -- I'd do it, but I don't want to bust anything, so I'm doing my stuff here instead :-) //if ( MULTIPLAYER_CLIENT && !(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){ // multiplayer clients will only do ship/ship collisions, and their own ship to boot // if ( check_collision != collide_ship_ship ){ // return; // } // if ( (A != Player_obj) && (B != Player_obj) ){ // return; // } //} // only check debris:weapon collisions for player if (check_collision == collide_debris_weapon) { // weapon is B if ( !(Weapon_info[Weapons[B->instance].weapon_info_index].wi_flags & WIF_TURNS) ) { // check for dumbfire weapon // check if debris is behind laser float vdot; if (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) { vec3d velocity_rel_weapon; vm_vec_sub(&velocity_rel_weapon, &B->phys_info.vel, &A->phys_info.vel); vdot = -vm_vec_dot(&velocity_rel_weapon, &B->orient.vec.fvec); } else { vdot = vm_vec_dot( &A->phys_info.vel, &B->phys_info.vel); } if ( vdot <= 0.0f ) { // They're heading in opposite directions... // check their positions vec3d weapon2other; vm_vec_sub( &weapon2other, &A->pos, &B->pos ); float pdot = vm_vec_dot( &B->orient.vec.fvec, &weapon2other ); if ( pdot <= -A->radius ) { // The other object is behind the weapon by more than // its radius, so it will never hit... return; } } // check dist vs. dist moved during weapon lifetime vec3d delta_v; vm_vec_sub(&delta_v, &B->phys_info.vel, &A->phys_info.vel); if (vm_vec_dist_squared(&A->pos, &B->pos) > (vm_vec_mag_squared(&delta_v)*Weapons[B->instance].lifeleft*Weapons[B->instance].lifeleft)) { return; } // for nonplayer ships, only create collision pair if close enough if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (vm_vec_dist(&B->pos, &A->pos) < (4.0f*A->radius + 200.0f)) ) return; } } // don't check same team laser:ship collisions on small ships if not player if (check_collision == collide_ship_weapon) { // weapon is B if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (Ships[Objects[B->parent].instance].team == Ships[A->instance].team) && (Ship_info[Ships[A->instance].ship_info_index].flags & SIF_SMALL_SHIP) && (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) ) { pairs_not_created++; return; } } if ( !check_collision ) return; Pairs_created++; // At this point, we have determined that collisions between // these two should be checked, so add the pair to the // collision pair list. if ( pair_free_list.next == NULL ) { nprintf(( "collision", "Out of object pairs!! Not all collisions will work!\n" )); return; } Num_pairs++; /* if (Num_pairs > Num_pairs_hwm) { Num_pairs_hwm = Num_pairs; //nprintf(("AI", "Num_pairs high water mark = %i\n", Num_pairs_hwm)); } */ if ( Num_pairs >= (Num_pairs_allocated - 20) ) { int i; Assert( Obj_pairs != NULL ); int old_pair_count = Num_pairs_allocated; obj_pair *old_pairs_ptr = Obj_pairs; // determine where we need to update the "previous" ptrs to int prev_free_mark = (pair_free_list.next - old_pairs_ptr); int prev_used_mark = (pair_used_list.next - old_pairs_ptr); Obj_pairs = (obj_pair*) vm_realloc_q( Obj_pairs, sizeof(obj_pair) * (Num_pairs_allocated + PAIRS_BUMP) ); // allow us to fail here and only if we don't do we setup the new pairs if (Obj_pairs == NULL) { // failed, just go back to the way we were and use only the pairs we have already Obj_pairs = old_pairs_ptr; } else { Num_pairs_allocated += PAIRS_BUMP; Assert( Obj_pairs != NULL ); // have to reset all of the "next" ptrs for the old set and handle the new set for (i = 0; i < Num_pairs_allocated; i++) { if (i >= old_pair_count) { memset( &Obj_pairs[i], 0, sizeof(obj_pair) ); Obj_pairs[i].next = &Obj_pairs[i+1]; } else { if (Obj_pairs[i].next != NULL) { // the "next" ptr will end up going backwards for used pairs so we have // to allow for that with this craziness... int next_mark = (Obj_pairs[i].next - old_pairs_ptr); Obj_pairs[i].next = &Obj_pairs[next_mark]; } // catch that last NULL from the previously allocated set if ( i == (old_pair_count-1) ) { Obj_pairs[i].next = &Obj_pairs[i+1]; } } } Obj_pairs[Num_pairs_allocated-1].next = NULL; // reset the "previous" ptrs pair_free_list.next = &Obj_pairs[prev_free_mark]; pair_used_list.next = &Obj_pairs[prev_used_mark]; } } // get a new obj_pair from the free list obj_pair * new_pair = pair_free_list.next; pair_free_list.next = new_pair->next; if ( add_to_end ) { obj_pair *last, *tmp; last = tmp = pair_used_list.next; while( tmp != NULL ) { if ( tmp->next == NULL ) last = tmp; tmp = tmp->next; } if ( last == NULL ) last = &pair_used_list; last->next = new_pair; Assert(new_pair != NULL); new_pair->next = NULL; } else { new_pair->next = pair_used_list.next; pair_used_list.next = new_pair; } A->num_pairs++; B->num_pairs++; new_pair->a = A; new_pair->b = B; new_pair->check_collision = check_collision; if ( check_time == -1 ){ new_pair->next_check_time = timestamp(0); // 0 means instantly time out } else { new_pair->next_check_time = check_time; } }
void obj_collide_pair(object *A, object *B) { uint ctype; int (*check_collision)( obj_pair *pair ); int swapped = 0; check_collision = NULL; if ( A==B ) return; // Don't check collisions with yourself if ( !(A->flags&OF_COLLIDES) ) return; // This object doesn't collide with anything if ( !(B->flags&OF_COLLIDES) ) return; // This object doesn't collide with anything // Make sure you're not checking a parent with it's kid or vicy-versy // if ( A->parent_sig == B->signature && !(A->type == OBJ_SHIP && B->type == OBJ_DEBRIS) ) return; // if ( B->parent_sig == A->signature && !(A->type == OBJ_DEBRIS && B->type == OBJ_SHIP) ) return; if ( reject_obj_pair_on_parent(A,B) ) { return; } Assert( A->type < 127 ); Assert( B->type < 127 ); ctype = COLLISION_OF(A->type,B->type); switch( ctype ) { case COLLISION_OF(OBJ_WEAPON,OBJ_SHIP): swapped = 1; check_collision = collide_ship_weapon; break; case COLLISION_OF(OBJ_SHIP, OBJ_WEAPON): check_collision = collide_ship_weapon; break; case COLLISION_OF(OBJ_DEBRIS, OBJ_WEAPON): check_collision = collide_debris_weapon; break; case COLLISION_OF(OBJ_WEAPON, OBJ_DEBRIS): swapped = 1; check_collision = collide_debris_weapon; break; case COLLISION_OF(OBJ_DEBRIS, OBJ_SHIP): check_collision = collide_debris_ship; break; case COLLISION_OF(OBJ_SHIP, OBJ_DEBRIS): check_collision = collide_debris_ship; swapped = 1; break; case COLLISION_OF(OBJ_ASTEROID, OBJ_WEAPON): // Only check collision's with player weapons // if ( Objects[B->parent].flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_weapon; // } break; case COLLISION_OF(OBJ_WEAPON, OBJ_ASTEROID): swapped = 1; // Only check collision's with player weapons // if ( Objects[A->parent].flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_weapon; // } break; case COLLISION_OF(OBJ_ASTEROID, OBJ_SHIP): // Only check collisions with player ships // if ( B->flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_ship; // } break; case COLLISION_OF(OBJ_SHIP, OBJ_ASTEROID): // Only check collisions with player ships // if ( A->flags & OF_PLAYER_SHIP ) { check_collision = collide_asteroid_ship; // } swapped = 1; break; case COLLISION_OF(OBJ_SHIP,OBJ_SHIP): check_collision = collide_ship_ship; break; case COLLISION_OF(OBJ_SHIP, OBJ_BEAM): if(beam_collide_early_out(B, A)){ return; } swapped = 1; check_collision = beam_collide_ship; break; case COLLISION_OF(OBJ_BEAM, OBJ_SHIP): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_ship; break; case COLLISION_OF(OBJ_ASTEROID, OBJ_BEAM): if(beam_collide_early_out(B, A)) { return; } swapped = 1; check_collision = beam_collide_asteroid; break; case COLLISION_OF(OBJ_BEAM, OBJ_ASTEROID): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_asteroid; break; case COLLISION_OF(OBJ_DEBRIS, OBJ_BEAM): if(beam_collide_early_out(B, A)) { return; } swapped = 1; check_collision = beam_collide_debris; break; case COLLISION_OF(OBJ_BEAM, OBJ_DEBRIS): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_debris; break; case COLLISION_OF(OBJ_WEAPON, OBJ_BEAM): if(beam_collide_early_out(B, A)) { return; } swapped = 1; check_collision = beam_collide_missile; break; case COLLISION_OF(OBJ_BEAM, OBJ_WEAPON): if(beam_collide_early_out(A, B)){ return; } check_collision = beam_collide_missile; break; case COLLISION_OF(OBJ_WEAPON, OBJ_WEAPON): { weapon_info *awip, *bwip; awip = &Weapon_info[Weapons[A->instance].weapon_info_index]; bwip = &Weapon_info[Weapons[B->instance].weapon_info_index]; if ((awip->weapon_hitpoints > 0) || (bwip->weapon_hitpoints > 0)) { if (bwip->weapon_hitpoints == 0) { check_collision = collide_weapon_weapon; swapped=1; } else { check_collision = collide_weapon_weapon; } } break; } default: return; } if ( !check_collision ) return; // Swap them if needed if ( swapped ) { object *tmp = A; A = B; B = tmp; } collider_pair *collision_info = NULL; bool valid = false; uint key = (OBJ_INDEX(A) << 12) + OBJ_INDEX(B); collision_info = &Collision_cached_pairs[key]; if ( collision_info->initialized ) { // make sure we're referring to the correct objects in case the original pair was deleted if ( collision_info->signature_a == collision_info->a->signature && collision_info->signature_b == collision_info->b->signature ) { valid = true; } else { collision_info->a = A; collision_info->b = B; collision_info->signature_a = A->signature; collision_info->signature_b = B->signature; collision_info->next_check_time = timestamp(0); } } else { collision_info->a = A; collision_info->b = B; collision_info->signature_a = A->signature; collision_info->signature_b = B->signature; collision_info->initialized = true; collision_info->next_check_time = timestamp(0); } if ( valid && A->type != OBJ_BEAM ) { // if this signature is valid, make the necessary checks to see if we need to collide check if ( collision_info->next_check_time == -1 ) { return; } else { if ( !timestamp_elapsed(collision_info->next_check_time) ) { return; } } } else { //if ( A->type == OBJ_BEAM ) { //if(beam_collide_early_out(A, B)){ //collision_info->next_check_time = -1; //return; //} //} // only check debris:weapon collisions for player if (check_collision == collide_debris_weapon) { // weapon is B if ( !(Weapon_info[Weapons[B->instance].weapon_info_index].wi_flags & WIF_TURNS) ) { // check for dumbfire weapon // check if debris is behind laser float vdot; if (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) { vec3d velocity_rel_weapon; vm_vec_sub(&velocity_rel_weapon, &B->phys_info.vel, &A->phys_info.vel); vdot = -vm_vec_dot(&velocity_rel_weapon, &B->orient.vec.fvec); } else { vdot = vm_vec_dot( &A->phys_info.vel, &B->phys_info.vel); } if ( vdot <= 0.0f ) { // They're heading in opposite directions... // check their positions vec3d weapon2other; vm_vec_sub( &weapon2other, &A->pos, &B->pos ); float pdot = vm_vec_dot( &B->orient.vec.fvec, &weapon2other ); if ( pdot <= -A->radius ) { // The other object is behind the weapon by more than // its radius, so it will never hit... collision_info->next_check_time = -1; return; } } // check dist vs. dist moved during weapon lifetime vec3d delta_v; vm_vec_sub(&delta_v, &B->phys_info.vel, &A->phys_info.vel); if (vm_vec_dist_squared(&A->pos, &B->pos) > (vm_vec_mag_squared(&delta_v)*Weapons[B->instance].lifeleft*Weapons[B->instance].lifeleft)) { collision_info->next_check_time = -1; return; } // for nonplayer ships, only create collision pair if close enough if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (vm_vec_dist(&B->pos, &A->pos) < (4.0f*A->radius + 200.0f)) ) { collision_info->next_check_time = -1; return; } } } // don't check same team laser:ship collisions on small ships if not player if (check_collision == collide_ship_weapon) { // weapon is B if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (Ships[Objects[B->parent].instance].team == Ships[A->instance].team) && (Ship_info[Ships[A->instance].ship_info_index].flags & SIF_SMALL_SHIP) && (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) ) { collision_info->next_check_time = -1; return; } } } obj_pair new_pair; new_pair.a = A; new_pair.b = B; new_pair.check_collision = check_collision; new_pair.next_check_time = collision_info->next_check_time; if ( check_collision(&new_pair) ) { // don't have to check ever again collision_info->next_check_time = -1; } else { collision_info->next_check_time = new_pair.next_check_time; } }