AFlareSpacecraft* UFlareSpacecraftNavigationSystem::GetDockStation()
{
	if (IsDocked())
	{
		for (int32 SpacecraftIndex = 0; SpacecraftIndex < Spacecraft->GetGame()->GetActiveSector()->GetSpacecrafts().Num(); SpacecraftIndex++)
		{
			AFlareSpacecraft* Station = Spacecraft->GetGame()->GetActiveSector()->GetSpacecrafts()[SpacecraftIndex];

			if (Station && Station->GetParent()->GetImmatriculation() == Data->DockedTo)
			{
				return Station;
			}
		}
	}
	return NULL;
}
bool UFlareSpacecraftNavigationSystem::Undock()
{
	// Try undocking
	if (IsDocked())
	{
		FLOGV("UFlareSpacecraftNavigationSystem::Undock : '%s' undocking from '%s'",
			*Spacecraft->GetParent()->GetImmatriculation().ToString(),
			*Data->DockedTo.ToString());

		// Detach from station
		if(DockConstraint)
		{
			DockConstraint->BreakConstraint();
			DockConstraint->DestroyComponent();
			DockConstraint = NULL;
		}

		AFlareSpacecraft* DockStation = GetDockStation();
		DockStation->GetDockingSystem()->ReleaseDock(Spacecraft, Data->DockedAt);

		// Update data
		SetStatus(EFlareShipStatus::SS_AutoPilot);
		Data->DockedTo = NAME_None;
		Data->DockedAt = -1;

		// Update Angular acceleration rate : when it's docked the mass is the ship mass + the station mass
		Spacecraft->SetRCSDescription(Spacecraft->GetRCSDescription());
		Spacecraft->OnUndocked(DockStation);

		// Leave
		PushCommandLocation(Spacecraft->GetRootComponent()->GetComponentTransform().TransformPositionNoScale(5000 * FVector(-1, 0, 0)));
		FLOG("UFlareSpacecraftNavigationSystem::Undock : successful");

		// Hack for bug #195: for ue4 to reweld all.
		Spacecraft->Airframe->SetSimulatePhysics(false);
		Spacecraft->Airframe->SetSimulatePhysics(true);

		return true;
	}

	// Failed
	else
	{
		FLOGV("UFlareSpacecraftNavigationSystem::Undock : '%s' is not docked", *Spacecraft->GetParent()->GetImmatriculation().ToString());
		return false;
	}
}
void UFlareSpacecraftNavigationSystem::AbortAllCommands()
{
	FFlareShipCommandData Command;

	while (CommandData.Dequeue(Command))
	{
		FLOGV("UFlareSpacecraftNavigationSystem::AbortAllCommands : '%s' has aborted command '%s'",
			*Spacecraft->GetParent()->GetImmatriculation().ToString(),
			*EFlareCommandDataType::ToString(Command.Type));

		if (Command.Type == EFlareCommandDataType::CDT_Dock)
		{
			// Release dock grant
			AFlareSpacecraft* Station = Command.ActionTarget;
			Station->GetDockingSystem()->ReleaseDock(Spacecraft, Command.ActionTargetParam);
		}
	}
	SetStatus(EFlareShipStatus::SS_Manual);
}
AFlareSpacecraft* UFlareSpacecraftNavigationSystem::GetNearestShip(AFlareSpacecraft* DockingStation) const
{
	// For now an host ship is a the nearest host ship with the following critera:
	// - Alive or not
	// - From any company
	// - Is the nearest
	// - Is not me

	FVector PilotLocation = Spacecraft->GetActorLocation();
	float MinDistanceSquared = -1;
	AFlareSpacecraft* NearestShip = NULL;

	for (int32 SpacecraftIndex = 0; SpacecraftIndex < Spacecraft->GetGame()->GetActiveSector()->GetSpacecrafts().Num(); SpacecraftIndex++)
	{
		AFlareSpacecraft* ShipCandidate = Spacecraft->GetGame()->GetActiveSector()->GetSpacecrafts()[SpacecraftIndex];

		if (ShipCandidate != Spacecraft && ShipCandidate != DockingStation)
		{

			if (DockingStation && (DockingStation->GetDockingSystem()->IsGrantedShip(ShipCandidate) || DockingStation->GetDockingSystem()->IsDockedShip(ShipCandidate)))
			{
				// Ignore ship docked or docking at the same station
				continue;
			}

			float DistanceSquared = (PilotLocation - ShipCandidate->GetActorLocation()).SizeSquared();

			if (NearestShip == NULL || DistanceSquared < MinDistanceSquared)
			{
				MinDistanceSquared = DistanceSquared;
				NearestShip = ShipCandidate;
			}
		}
	}
	return NearestShip;
}
void UFlareAsteroidComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
	float CollisionSize = GetCollisionShape().GetExtent().Size();
	EffectsUpdateTimer += DeltaTime;

	// Get player ship
	AFlareGame* Game = Cast<AFlareGame>(GetWorld()->GetAuthGameMode());
	FCHECK(Game);
	AFlarePlayerController* PC = Game->GetPC();
	FCHECK(PC);
	AFlareSpacecraft* ShipPawn = PC->GetShipPawn();

	// Update if close to player and visible
	if (ShipPawn
	 && (ShipPawn->GetActorLocation() - GetComponentLocation()).Size() < 500000
	 && (GetWorld()->TimeSeconds - LastRenderTime) < 0.5)
	{
		if (EffectsUpdateTimer > EffectsUpdatePeriod)
		{
			// World data
			FVector AsteroidLocation = GetComponentLocation();
			FVector SunDirection = Game->GetPlanetarium()->GetSunDirection();
			SunDirection.Normalize();
	
			// Compute new FX locations
			for (int32 Index = 0; Index < Effects.Num(); Index++)
			{
				FVector RandomDirection = FVector::CrossProduct(SunDirection, EffectsKernels[Index]);
				RandomDirection.Normalize();
				FVector StartPoint = AsteroidLocation + RandomDirection * CollisionSize;

				// Trace params
				FHitResult HitResult(ForceInit);
				FCollisionQueryParams TraceParams(FName(TEXT("Asteroid Trace")), false, NULL);
				TraceParams.bTraceComplex = true;
				TraceParams.bReturnPhysicalMaterial = false;
				ECollisionChannel CollisionChannel = ECollisionChannel::ECC_WorldDynamic;

				// Trace
				bool FoundHit = GetWorld()->LineTraceSingleByChannel(HitResult, StartPoint, AsteroidLocation, CollisionChannel, TraceParams);
				if (FoundHit && HitResult.Component == this && Effects[Index])
				{
					FVector EffectLocation = HitResult.Location;

					if (!Effects[Index]->IsActive())
					{
						Effects[Index]->Activate();
					}
					Effects[Index]->SetWorldLocation(EffectLocation);
					Effects[Index]->SetWorldRotation(SunDirection.Rotation());
				}
				else
				{
					Effects[Index]->Deactivate();
				}
			}

			EffectsUpdateTimer = 0;
		}
	}

	// Disable all
	else
	{
		for (int32 Index = 0; Index < Effects.Num(); Index++)
		{
			Effects[Index]->Deactivate();
		}
	}
}
Example #6
0
AFlareSpacecraft* UFlareSector::LoadSpacecraft(UFlareSimulatedSpacecraft* ParentSpacecraft)
{
	AFlareSpacecraft* Spacecraft = NULL;
	FLOGV("UFlareSector::LoadSpacecraft : Start loading ('%s')", *ParentSpacecraft->GetImmatriculation().ToString());


	// Spawn parameters
	FActorSpawnParameters Params;
	Params.bNoFail = true;
	Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;



	// Create and configure the ship
	Spacecraft = GetGame()->GetWorld()->SpawnActor<AFlareSpacecraft>(ParentSpacecraft->GetDescription()->Template->GeneratedClass, ParentSpacecraft->GetData().Location, ParentSpacecraft->GetData().Rotation, Params);
	if (Spacecraft && !Spacecraft->IsPendingKillPending())
	{
		Spacecraft->Load(ParentSpacecraft);
		UPrimitiveComponent* RootComponent = Cast<UPrimitiveComponent>(Spacecraft->GetRootComponent());

		if (Spacecraft->IsStation())
		{
			SectorStations.Add(Spacecraft);
		}
		else
		{
			SectorShips.Add(Spacecraft);
		}
		SectorSpacecrafts.Add(Spacecraft);

		FLOGV("%s spawn mode = %d", *Spacecraft->GetImmatriculation().ToString(), ParentSpacecraft->GetData().SpawnMode+0)


		switch (ParentSpacecraft->GetData().SpawnMode)
		{
			// Already known to be correct
			case EFlareSpawnMode::Safe:

				FLOGV("UFlareSector::LoadSpacecraft : Safe spawn '%s' at (%f,%f,%f)",
					*ParentSpacecraft->GetImmatriculation().ToString(),
					ParentSpacecraft->GetData().Location.X, ParentSpacecraft->GetData().Location.Y, ParentSpacecraft->GetData().Location.Z);

				RootComponent->SetPhysicsLinearVelocity(ParentSpacecraft->GetData().LinearVelocity, false);
				RootComponent->SetPhysicsAngularVelocity(ParentSpacecraft->GetData().AngularVelocity, false);
				break;

			// First spawn
			case EFlareSpawnMode::Spawn:

				PlaceSpacecraft(Spacecraft, ParentSpacecraft->GetData().Location);
				{
					FVector NewLocation = Spacecraft->GetActorLocation();
					FLOGV("UFlareSector::LoadSpacecraft : Placing '%s' at (%f,%f,%f)",
						*ParentSpacecraft->GetImmatriculation().ToString(),
						NewLocation.X, NewLocation.Y, NewLocation.Z);
				}

				RootComponent->SetPhysicsLinearVelocity(FVector::ZeroVector, false);
				RootComponent->SetPhysicsAngularVelocity(FVector::ZeroVector, false);
				break;

			// Incoming in sector
			case EFlareSpawnMode::Travel:
			{

				FLOGV("UFlareSector::LoadSpacecraft : Travel '%s' at (%f, %f, %f)",
					*ParentSpacecraft->GetImmatriculation().ToString(),
					ParentSpacecraft->GetData().Location.X, ParentSpacecraft->GetData().Location.Y, ParentSpacecraft->GetData().Location.Z);

				FVector SpawnDirection;
				TArray<AFlareSpacecraft*> FriendlySpacecrafts = GetCompanySpacecrafts(Spacecraft->GetCompany());
				FVector FriendlyShipLocationSum = FVector::ZeroVector;
				int FriendlyShipCount = 0;

				for (int SpacecraftIndex = 0 ; SpacecraftIndex < FriendlySpacecrafts.Num(); SpacecraftIndex++)
				{
					AFlareSpacecraft *SpacecraftCandidate = FriendlySpacecrafts[SpacecraftIndex];
					if (!SpacecraftCandidate->IsStation() && SpacecraftCandidate != Spacecraft)
					{
						FriendlyShipLocationSum += SpacecraftCandidate->GetActorLocation();
						FriendlyShipCount++;
					}
				}

				if (FriendlyShipCount == 0)
				{
					FVector NotFriendlyShipLocationSum = FVector::ZeroVector;
					int NotFriendlyShipCount = 0;
					for (int SpacecraftIndex = 0 ; SpacecraftIndex < SectorShips.Num(); SpacecraftIndex++)
					{
						AFlareSpacecraft *SpacecraftCandidate = SectorShips[SpacecraftIndex];
						if (SpacecraftCandidate != Spacecraft && SpacecraftCandidate->GetCompany() != Spacecraft->GetCompany())
						{
							NotFriendlyShipLocationSum += SpacecraftCandidate->GetActorLocation();
							NotFriendlyShipCount++;
						}
					}

					if (NotFriendlyShipCount == 0)
					{
						SpawnDirection = FMath::VRand();
					}
					else
					{
						FVector	NotFriendlyShipLocationMean = NotFriendlyShipLocationSum / NotFriendlyShipCount;
						SpawnDirection = (GetSectorCenter() - NotFriendlyShipLocationMean).GetUnsafeNormal();
					}
				}
				else
				{
					FVector	FriendlyShipLocationMean = FriendlyShipLocationSum / FriendlyShipCount;
					SpawnDirection = (FriendlyShipLocationMean - GetSectorCenter()).GetUnsafeNormal() ;
				}

				float SpawnDistance = GetSectorRadius() + 1;

				if (GetSimulatedSector()->GetSectorBattleState(Spacecraft->GetCompany()) != EFlareSectorBattleState::NoBattle)
				{
					SpawnDistance += 500000; // 5 km
				}

				SpawnDistance = FMath::Min(SpawnDistance, GetSectorLimits());

				FVector Location = GetSectorCenter() + SpawnDirection * SpawnDistance;

				FVector CenterDirection = (GetSectorCenter() - Location).GetUnsafeNormal();
				Spacecraft->SetActorRotation(CenterDirection.Rotation());

				PlaceSpacecraft(Spacecraft, Location);

				float SpawnVelocity = 0;

				if (GetSimulatedSector()->GetSectorBattleState(Spacecraft->GetCompany()) != EFlareSectorBattleState::NoBattle)
				{
						SpawnVelocity = 10000;
				}

				RootComponent->SetPhysicsLinearVelocity(CenterDirection * SpawnVelocity, false);
				RootComponent->SetPhysicsAngularVelocity(FVector::ZeroVector, false);
			}
			break;
			case EFlareSpawnMode::Exit:
			{
				float SpawnDistance = GetSectorLimits() * 0.9;
				float SpawnVelocity = ParentSpacecraft->GetData().LinearVelocity.Size() * 0.6;
				FVector SpawnDirection = ParentSpacecraft->GetData().Location.GetUnsafeNormal();
				FVector Location = SpawnDirection * SpawnDistance;
				FVector CenterDirection = (GetSectorCenter() - Location).GetUnsafeNormal();

				FLOGV("UFlareSector::LoadSpacecraft : Exit '%s' at (%f, %f, %f)",
					*ParentSpacecraft->GetImmatriculation().ToString(),
					Location.X, Location.Y, Location.Z);

				PlaceSpacecraft(Spacecraft, Location);
				Spacecraft->SetActorRotation(CenterDirection.Rotation());

				RootComponent->SetPhysicsLinearVelocity(CenterDirection * SpawnVelocity, false);
				RootComponent->SetPhysicsAngularVelocity(FVector::ZeroVector, false);

			}
			break;
		}

		ParentSpacecraft->SetSpawnMode(EFlareSpawnMode::Safe);
	}
void UFlareSpacecraftDamageSystem::OnCollision(class AActor* Other, FVector HitLocation, FVector NormalImpulse)
{
	// If receive hit from over actor, like a ship we must apply collision damages.
	// The applied damage energy is 0.2% of the kinetic energy of the other actor. The kinetic
	// energy is calculated from the relative speed between the 2 actors, and only with the relative
	// speed projected in the axis of the collision normal: if 2 very fast ship only slightly touch,
	// only few energy will be decipated by the impact.
	//
	// The damages are applied only to the current actor, the ReceiveHit method of the other actor
	// will also call an it will apply its collision damages itself.

	// If the other actor is a projectile, specific weapon damage code is done in the projectile hit
	// handler: in this case we ignore the collision
	AFlareShell* OtherProjectile = Cast<AFlareShell>(Other);
	if (OtherProjectile)
	{
		return;
	}

	// No primitive component, ignore
	UPrimitiveComponent* OtherRoot = Cast<UPrimitiveComponent>(Other->GetRootComponent());
	if (!OtherRoot)
	{
		return;
	}

	// Ignore debris
	AStaticMeshActor* OtherActor = Cast<AStaticMeshActor>(Other);
	if (OtherActor)
	{
		if (OtherActor->GetName().StartsWith("Debris"))
		{
			return;
		}
	}

	// Relative velocity
	FVector DeltaVelocity = ((OtherRoot->GetPhysicsLinearVelocity() - Spacecraft->Airframe->GetPhysicsLinearVelocity()) / 100);

	// Compute the relative velocity in the impact axis then compute kinetic energy
	/*float ImpactSpeed = DeltaVelocity.Size();
	float ImpactMass = FMath::Min(Spacecraft->GetSpacecraftMass(), OtherRoot->GetMass());
	*/

	//200 m /s -> 6301.873047 * 20000 -> 300 / 2 damage

	float ImpactSpeed = 0;
	float ImpactEnergy = 0;
	float ImpactMass = Spacecraft->GetSpacecraftMass();

	// Check if the mass was set and is valid
	if (ImpactMass > KINDA_SMALL_NUMBER)
	{
		ImpactSpeed = NormalImpulse.Size() / (ImpactMass * 100.f);
		ImpactEnergy = ImpactMass * ImpactSpeed / 8402.f;
	}

	float  Radius = 0.2 + FMath::Sqrt(ImpactEnergy) * 0.11;
	//FLOGV("OnCollision %s", *Spacecraft->GetImmatriculation().ToString());
	//FLOGV("  OtherRoot->GetPhysicsLinearVelocity()=%s", *OtherRoot->GetPhysicsLinearVelocity().ToString());
	//FLOGV("  OtherRoot->GetPhysicsLinearVelocity().Size()=%f", OtherRoot->GetPhysicsLinearVelocity().Size());
	//FLOGV("  Spacecraft->Airframe->GetPhysicsLinearVelocity()=%s", *Spacecraft->Airframe->GetPhysicsLinearVelocity().ToString());
	//FLOGV("  Spacecraft->Airframe->GetPhysicsLinearVelocity().Size()=%f", Spacecraft->Airframe->GetPhysicsLinearVelocity().Size());
	//FLOGV("  dot=%f", FVector::DotProduct(DeltaVelocity.GetUnsafeNormal(), HitNormal.GetUnsafeNormal()));
	/*FLOGV("  DeltaVelocity=%s", *DeltaVelocity.ToString());
	FLOGV("  ImpactSpeed=%f", ImpactSpeed);
	FLOGV("  ImpactMass=%f", ImpactMass);
	FLOGV("  ImpactEnergy=%f", ImpactEnergy);
	FLOGV("  Radius=%f", Radius);*/



	bool HasHit = false;
	FHitResult BestHitResult;
	float BestHitDistance = 0;

	for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
	{
		UFlareSpacecraftComponent* Component = Cast<UFlareSpacecraftComponent>(Components[ComponentIndex]);
		if (Component)
		{
			FHitResult HitResult(ForceInit);
			FCollisionQueryParams TraceParams(FName(TEXT("Fragment Trace")), true);
			TraceParams.bTraceComplex = true;
			TraceParams.bReturnPhysicalMaterial = false;
			Component->LineTraceComponent(HitResult, HitLocation, HitLocation + Spacecraft->GetLinearVelocity().GetUnsafeNormal() * 10000, TraceParams);

			if (HitResult.Actor.IsValid()){
				float HitDistance = (HitResult.Location - HitLocation).Size();
				if (!HasHit || HitDistance < BestHitDistance)
				{
					BestHitDistance = HitDistance;
					BestHitResult = HitResult;
				}

				//FLOGV("Collide hit %s at a distance=%f", *Component->GetReadableName(), HitDistance);
				HasHit = true;
			}
		}

	}

	if (HasHit)
	{
		//DrawDebugLine(Spacecraft->GetWorld(), HitLocation, BestHitResult.Location, FColor::Magenta, true);
	}
	else
	{
		int32 BestComponentIndex = -1;
		BestHitDistance = 0;

		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UFlareSpacecraftComponent* Component = Cast<UFlareSpacecraftComponent>(Components[ComponentIndex]);
			if (Component)
			{
				float ComponentDistance = (Component->GetComponentLocation() - HitLocation).Size();
				if (BestComponentIndex == -1 || BestHitDistance > ComponentDistance)
				{
					BestComponentIndex = ComponentIndex;
					BestHitDistance = ComponentDistance;
				}
			}
		}
		UFlareSpacecraftComponent* Component = Cast<UFlareSpacecraftComponent>(Components[BestComponentIndex]);


		FCollisionQueryParams TraceParams(FName(TEXT("Fragment Trace")), true);
		TraceParams.bTraceComplex = true;
		TraceParams.bReturnPhysicalMaterial = false;
		Component->LineTraceComponent(BestHitResult, HitLocation, Component->GetComponentLocation(), TraceParams);
		//DrawDebugLine(Spacecraft->GetWorld(), HitLocation, BestHitResult.Location, FColor::Yellow, true);


	}

	AFlareSpacecraft* OtherSpacecraft = Cast<AFlareSpacecraft>(Other);
	UFlareCompany* DamageSource = NULL;
	if (OtherSpacecraft)
	{
		DamageSource = OtherSpacecraft->GetParent()->GetCompany();
		LastDamageCauser = OtherSpacecraft;
	}
	else
	{
		LastDamageCauser = NULL;
	}
	ApplyDamage(ImpactEnergy, Radius, BestHitResult.Location, EFlareDamage::DAM_Collision, DamageSource);
}
void UFlareSpacecraftNavigationSystem::CheckCollisionDocking(AFlareSpacecraft* DockingCandidate)
{
	if (IsAutoPilot())
	{
		FFlareShipCommandData CurrentCommand;
		if (CommandData.Peek(CurrentCommand))
		{
			if (CurrentCommand.Type == EFlareCommandDataType::CDT_Dock)
			{
				// We are in a automatic docking process
				AFlareSpacecraft* DockStation = CurrentCommand.ActionTarget;
				if (DockStation != DockingCandidate)
				{
					// The hit spacecraft is not the docking target station
					return;
				}

				// Check dock alignement

				// TODO Put to external constants
				float DockingAngleLimit = 2; // 1° of angle error to dock
				float DockingVelocityLimit = 200; // 1 m/s
				float DockingLateralVelocityLimit = 20; // 10 cm/s
				float DockingAngularVelocityLimit = 10; // 5 °/s

				int32 DockId = CurrentCommand.ActionTargetParam;

				FVector ShipAngularVelocity = Spacecraft->Airframe->GetPhysicsAngularVelocity();
				FVector ShipDockLocation = GetDockLocation();

				FFlareDockingInfo StationDockInfo = DockStation->GetDockingSystem()->GetDockInfo(DockId);
				FVector StationCOM = DockStation->Airframe->GetBodyInstance()->GetCOMPosition();

				FVector StationAngularVelocity = DockStation->Airframe->GetPhysicsAngularVelocity();
				FVector StationDockLocation =  DockStation->Airframe->GetComponentTransform().TransformPosition(StationDockInfo.LocalLocation);
				FVector StationDockSelfRotationInductedLinearVelocity = (PI /  180.f) * FVector::CrossProduct(StationAngularVelocity, StationDockLocation- StationCOM);

				FVector ShipDockSelfRotationInductedLinearVelocity = (PI /  180.f) * FVector::CrossProduct(ShipAngularVelocity, ShipDockLocation-COM);

				FVector StationDockLinearVelocity = StationDockSelfRotationInductedLinearVelocity + DockStation->GetLinearVelocity() * 100;
				FVector ShipDockLinearVelocity = ShipDockSelfRotationInductedLinearVelocity + Spacecraft->GetLinearVelocity() * 100;



				FVector ShipDockAxis = Spacecraft->Airframe->GetComponentToWorld().GetRotation().RotateVector(FVector(1, 0, 0)); // Ship docking port are always at front
				FVector StationDockAxis = DockStation->Airframe->GetComponentToWorld().GetRotation().RotateVector(StationDockInfo.LocalAxis);
				float DockToDockAngle = FMath::RadiansToDegrees(FMath::Acos(FVector::DotProduct(-ShipDockAxis, StationDockAxis)));
				FVector RelativeDockToDockLinearVelocity = StationDockLinearVelocity - ShipDockLinearVelocity;


				// Angular velocity must be the same
				FVector RelativeDockAngularVelocity = ShipAngularVelocity - StationAngularVelocity;


				// Check if dockable
				bool OkForDocking = true;
				if (DockToDockAngle > DockingAngleLimit)
				{
					//FLOG("OkForDocking ? Not aligned");
					// Not aligned
					OkForDocking = false;
				}
				else if (RelativeDockToDockLinearVelocity.Size() > DockingVelocityLimit)
				{
					//FLOG("OkForDocking ? Too fast");
					// Too fast
					OkForDocking = false;
				}
				else if (FVector::VectorPlaneProject(RelativeDockToDockLinearVelocity, StationDockAxis).Size()  > DockingLateralVelocityLimit)
				{
					//FLOG("OkForDocking ? Too much lateral velocity");
					// Too much lateral velocity
					OkForDocking = false;
				}
				else if (RelativeDockAngularVelocity.Size() > DockingAngularVelocityLimit)
				{
					//FLOG("OkForDocking ? Too much angular velocity");
					// Too much angular velocity
					OkForDocking = false;
				}

				if (OkForDocking)
				{
					// All is ok for docking, perform dock
					//FLOG("  Ok for docking after hit");
					ConfirmDock(DockStation, DockId);
					return;
				}

			}
		}
	}
}