//TODO: This is still an awful way to do this and we should scrap this task or do it right.
void UAbilityTask_MoveToLocation::TickTask(float DeltaTime)
{
	if (bIsFinished)
	{
		return;
	}

	Super::TickTask(DeltaTime);
	AActor* MyActor = GetAvatarActor();
	if (MyActor)
	{
		ACharacter* MyCharacter = Cast<ACharacter>(MyActor);
		if (MyCharacter)
		{
			UCharacterMovementComponent* CharMoveComp = Cast<UCharacterMovementComponent>(MyCharacter->GetMovementComponent());
			if (CharMoveComp)
			{
				CharMoveComp->SetMovementMode(MOVE_Custom, 0);
			}
		}


		float CurrentTime = GetWorld()->GetTimeSeconds();

		if (CurrentTime >= TimeMoveWillEnd)
		{
			bIsFinished = true;

			// Teleport in attempt to find a valid collision spot
			MyActor->TeleportTo(TargetLocation, MyActor->GetActorRotation());
			if (!bIsSimulating)
			{
				MyActor->ForceNetUpdate();
				OnTargetLocationReached.Broadcast();
				EndTask();
			}
		}
		else
		{
			float MoveFraction = (CurrentTime - TimeMoveStarted) / DurationOfMovement;
			if (LerpCurve)
			{
				MoveFraction = LerpCurve->GetFloatValue(MoveFraction);
			}

			MyActor->SetActorLocation(FMath::Lerp<FVector, float>(StartLocation, TargetLocation, MoveFraction));
		}
	}
	else
	{
		bIsFinished = true;
		EndTask();
	}
}
예제 #2
0
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	ACharacter* OwningPawn = Cast<ACharacter>(TryGetPawnOwner());
	//const auto MovementComp = OwningPawn->GetMovementComponent(); 
	if (OwningPawn) {
		Speed = OwningPawn->GetVelocity().Size();
		Jump = OwningPawn->GetVelocity().Z;
		isFlying = OwningPawn->CharacterMovement->IsFalling();
	}
}
void ABatteryCollectorGameMode::HandleCurrentState(EBatteryPlayState  NewState)
{
	switch (NewState)
	{
	case EBatteryPlayState::EPlaying:
		{
			// spawn volumes active
			for (ASpawnVolume* Volume : SpawnVolumeActors)
			{
				Volume->SetSpawningActive(true);
			}
		}
		break;
	case EBatteryPlayState::Ewon:
		{
			// spawn volumes inactive
			for (ASpawnVolume* Volume : SpawnVolumeActors)
			{
				Volume->SetSpawningActive(false);
			}
		}
		break;
	case EBatteryPlayState::EGameOver:
		{
			// spawn volumes inactive
			for (ASpawnVolume* Volume : SpawnVolumeActors)
			{
				Volume->SetSpawningActive(false);
			}
			// block player input
			APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
			if (PlayerController)
			{
				PlayerController->SetCinematicMode(true, false, false, true, true);
			}
			// ragdoll the character
			ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
			if (MyCharacter)
			{
				MyCharacter->GetMesh()->SetSimulatePhysics(true);
				MyCharacter->GetMovementComponent()->MovementState.bCanJump = false;
			}
		}
		break;
		default:
	case EBatteryPlayState::EUnknown:
		{
			// Do nothing
		}
		break;
	}
}
/**
 *	Canceling an non instanced ability is tricky. Right now this works for Jump since there is nothing that can go wrong by calling
 *	StopJumping() if you aren't already jumping. If we had a montage playing non instanced ability, it would need to make sure the
 *	Montage that *it* played was still playing, and if so, to cancel it. If this is something we need to support, we may need some
 *	light weight data structure to represent 'non intanced abilities in action' with a way to cancel/end them.
 */
void UGameplayAbility_CharacterJump::CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility)
{
	if (ScopeLockCount > 0)
	{
		WaitingToExecute.Add(FPostLockDelegate::CreateUObject(this, &UGameplayAbility_CharacterJump::CancelAbility, Handle, ActorInfo, ActivationInfo, bReplicateCancelAbility));
		return;
	}

	Super::CancelAbility(Handle, ActorInfo, ActivationInfo, bReplicateCancelAbility);
	
	ACharacter * Character = CastChecked<ACharacter>(ActorInfo->AvatarActor.Get());
	Character->StopJumping();
}
void UGameplayAbility_CharacterJump::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
	if (ActivationInfo.ActivationMode == EGameplayAbilityActivationMode::Authority ||
		ActivationInfo.ActivationMode == EGameplayAbilityActivationMode::Predicting)
	{
		if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
		{
			return;
		}

		ACharacter * Character = CastChecked<ACharacter>(ActorInfo->AvatarActor.Get());
		Character->Jump();
	}
}
void UGameplayAbility_CharacterJump::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
	
	if (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo))
	{
		if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
		{
			return;
		}

		ACharacter * Character = CastChecked<ACharacter>(ActorInfo->AvatarActor.Get());
		Character->Jump();
	}
}
bool USkeletalMeshComponent::ShouldTickPose() const
{
	// Characters playing Root Motion will tick pose themselves before physics.
	ACharacter * CharacterOwner = Cast<ACharacter>(GetOwner());
	const bool bSkipBecauseOfRootMotion = CharacterOwner && CharacterOwner->IsPlayingRootMotion();

	// When we stop root motion we go back to ticking after CharacterMovement. Unfortunately that means that we could tick twice that frame.
	// So only enforce a single tick per frame.
	const bool bAlreadyTickedThisFrame = (LastTickTime == GetWorld()->TimeSeconds);

	// Remote Clients on the Server will always tick animations as updates from the client comes in. To use Client's delta time.
	const bool bRemoteClientOnServer = CharacterOwner && (CharacterOwner->Role == ROLE_Authority) && CharacterOwner->Controller && !CharacterOwner->Controller->IsLocalController();

	return (Super::ShouldTickPose() && IsRegistered() && AnimScriptInstance && !bPauseAnims && GetWorld()->HasBegunPlay() && !bNoSkeletonUpdate && !bSkipBecauseOfRootMotion && !bRemoteClientOnServer && !bAlreadyTickedThisFrame);
}
예제 #8
0
void UCheatManager::Walk()
{
	APawn* Pawn = GetOuterAPlayerController()->GetPawn();
	if (Pawn != NULL)
	{
		ACharacter* Character =  Cast<ACharacter>(Pawn);
		if (Character)
		{
			Character->ClientCheatWalk();
			if (!Character->IsLocallyControlled())
			{
				Character->ClientCheatWalk_Implementation();
			}
		}
	}
}
void UAbilityTask_ApplyRootMotionMoveToActorForce::OnDestroy(bool AbilityIsEnding)
{
	if (MovementComponent)
	{
		MovementComponent->RemoveRootMotionSourceByID(RootMotionSourceID);

		if (bSetNewMovementMode)
		{
			MovementComponent->SetMovementMode(NewMovementMode);
		}

		if (VelocityOnFinishMode == ERootMotionFinishVelocityMode::SetVelocity)
		{
			FVector EndVelocity;
			ACharacter* Character = MovementComponent->GetCharacterOwner();
			if (Character)
			{
				EndVelocity = Character->GetActorRotation().RotateVector(SetVelocityOnFinish);
			}
			else
			{
				EndVelocity = SetVelocityOnFinish;
			}

			// When we mean to SetVelocity when finishing a MoveTo, we apply a short-duration low-priority
			// root motion velocity override. This ensures that the velocity we set is replicated properly
			// and takes effect.
			{
				const FName OnFinishForceName = FName("AbilityTaskApplyRootMotionMoveToActorForce_EndForce");
				FRootMotionSource_ConstantForce* ConstantForce = new FRootMotionSource_ConstantForce();
				ConstantForce->InstanceName = OnFinishForceName;
				ConstantForce->AccumulateMode = ERootMotionAccumulateMode::Override;
				ConstantForce->Priority = 1; // Low priority so any other override root motion sources stomp it
				ConstantForce->Force = EndVelocity;
				ConstantForce->Duration = 0.001f;
				MovementComponent->ApplyRootMotionSource(ConstantForce);

				if (Ability)
				{
					Ability->SetMovementSyncPoint(OnFinishForceName);
				}
			}
		}
	}

	Super::OnDestroy(AbilityIsEnding);
}
예제 #10
0
void AShooterPlayerController::OnDeathMessage(class AShooterPlayerState* KillerPlayerState, class AShooterPlayerState* KilledPlayerState, const UDamageType* KillerDamageType) 
{
	AShooterHUD* ShooterHUD = GetShooterHUD();
	if (ShooterHUD)
	{
		ShooterHUD->ShowDeathMessage(KillerPlayerState, KilledPlayerState, KillerDamageType);		
	}

	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
	if (LocalPlayer && LocalPlayer->GetUniqueNetId().IsValid() && KilledPlayerState->UniqueId.IsValid())
	{
		// if this controller is the player who died, update the hero stat.
		if (*LocalPlayer->GetUniqueNetId() == *KilledPlayerState->UniqueId)
		{
			const auto Events = Online::GetEventsInterface();
			const auto Identity = Online::GetIdentityInterface();

			if (Events.IsValid() && Identity.IsValid())
			{							
				int32 UserIndex = LocalPlayer->ControllerId;
				TSharedPtr<FUniqueNetId> UniqueID = Identity->GetUniquePlayerId(UserIndex);
				if (UniqueID.IsValid())
				{				
					ACharacter* Pawn = GetCharacter();
					check(Pawn);
					FVector Location = Pawn->GetActorLocation();

					FOnlineEventParms Params;
					Params.Add( TEXT( "SectionId" ), FVariantData( (int32)1 ) );
					Params.Add( TEXT( "GameplayModeId" ), FVariantData( (int32)1 ) );
					Params.Add( TEXT( "DifficultyLevelId" ), FVariantData( (int32)0 ) );

					Params.Add( TEXT( "PlayerRoleId" ), FVariantData( (int32)0 ) );
					Params.Add( TEXT( "PlayerWeaponId" ), FVariantData( (int32)0 ) );
					Params.Add( TEXT( "EnemyRoleId" ), FVariantData( (int32)0 ) );
					Params.Add( TEXT( "EnemyWeaponId" ), FVariantData( (int32)0 ) );	
				
					Params.Add( TEXT( "LocationX" ), FVariantData( Location.X ) );
					Params.Add( TEXT( "LocationY" ), FVariantData( Location.Y ) );
					Params.Add( TEXT( "LocationZ" ), FVariantData( Location.Z ) );
										
					Events->TriggerEvent(*UniqueID, TEXT("PlayerDeath"), Params);
				}
			}
		}
	}	
}
void ABatteryCollectorGameMode::HandleNewState(EBatteryPlayState NewState)
{
	switch (NewState)
	{
	case EBatteryPlayState::EPlaying:
	{
		for (ASpawnVolume* Volume : SpawnVolumeActors)
		{
			Volume->SetSpawningActive(true);
		}
	}
	break;
	case EBatteryPlayState::EGameOver:
	{
		for (ASpawnVolume* Volume : SpawnVolumeActors)
		{
			Volume->SetSpawningActive(false);
		}
		APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
		if (PlayerController)
		{
			PlayerController->SetCinematicMode(true, false, false, true, true);
		}

		ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
		if (MyCharacter)
		{
			MyCharacter->GetMesh()->SetSimulatePhysics(true);
			MyCharacter->GetMovementComponent()->MovementState.bCanJump = false;
		}
	}
	break;
	case EBatteryPlayState::EWon:
	{
		for (ASpawnVolume* Volume : SpawnVolumeActors)
		{
			Volume->SetSpawningActive(false);
		}
	}
	break;
	case EBatteryPlayState::EUnknown:
		break;
	default:
		break;
	}
}
void UAbilityTask_MoveToLocation::OnDestroy(bool AbilityIsEnding)
{
	AActor* MyActor = GetAvatarActor();
	if (MyActor)
	{
		ACharacter* MyCharacter = Cast<ACharacter>(MyActor);
		if (MyCharacter)
		{
			UCharacterMovementComponent* CharMoveComp = Cast<UCharacterMovementComponent>(MyCharacter->GetMovementComponent());
			if (CharMoveComp && CharMoveComp->MovementMode == MOVE_Custom)
			{
				CharMoveComp->SetMovementMode(MOVE_Falling);
			}
		}
	}

	Super::OnDestroy(AbilityIsEnding);
}
예제 #13
0
void UCheatManager::Ghost()
{
	APawn* Pawn = GetOuterAPlayerController()->GetPawn();
	if (Pawn != NULL)
	{
		GetOuterAPlayerController()->ClientMessage(TEXT("You feel ethereal"));
		
		ACharacter* Character =  Cast<ACharacter>(Pawn);
		if (Character)
		{
			Character->ClientCheatGhost();
			if (!Character->IsLocallyControlled())
			{
				Character->ClientCheatGhost_Implementation();
			}
		}
	}	
}
예제 #14
0
void UCheatManager::ChangeSize( float F )
{
	APawn* Pawn = GetOuterAPlayerController()->GetPawn();
	
	// Note: only works on characters
	ACharacter *Character =  Cast<ACharacter>(Pawn);
	if (Character)
	{
		ACharacter* DefaultCharacter = Character->GetClass()->GetDefaultObject<ACharacter>();
		Character->GetCapsuleComponent()->SetCapsuleSize(DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleRadius() * F, DefaultCharacter->GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight() * F);

		if (Character->GetMesh())
		{
			Character->GetMesh()->SetRelativeScale3D(FVector(F));
		}
		Character->TeleportTo(Character->GetActorLocation(), Character->GetActorRotation());
	}
}
예제 #15
0
void AShooterPlayerController::OnKill()
{
	UpdateAchievementProgress(ACH_FRAG_SOMEONE, 100.0f);

	const auto Events = Online::GetEventsInterface();
	const auto Identity = Online::GetIdentityInterface();

	if (Events.IsValid() && Identity.IsValid())
	{
		ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);
		if (LocalPlayer)
		{
			int32 UserIndex = LocalPlayer->ControllerId;
			TSharedPtr<FUniqueNetId> UniqueID = Identity->GetUniquePlayerId(UserIndex);			
			if (UniqueID.IsValid())
			{			
				ACharacter* Pawn = GetCharacter();
				// If player is dead, use location stored during pawn cleanup.
				FVector Location = LastDeathLocation;
				if (Pawn)
				{
					Pawn->GetActorLocation();
				}

				FOnlineEventParms Params;		

				Params.Add( TEXT( "SectionId" ), FVariantData( (int32)1 ) );
				Params.Add( TEXT( "GameplayModeId" ), FVariantData( (int32)1 ) );
				Params.Add( TEXT( "DifficultyLevelId" ), FVariantData( (int32)0 ) );

				Params.Add( TEXT( "PlayerRoleId" ), FVariantData( (int32)0 ) );
				Params.Add( TEXT( "PlayerWeaponId" ), FVariantData( (int32)0 ) );
				Params.Add( TEXT( "EnemyRoleId" ), FVariantData( (int32)0 ) );
				Params.Add( TEXT( "KillTypeId" ), FVariantData( (int32)0 ) );			
				Params.Add( TEXT( "LocationX" ), FVariantData( Location.X ) );
				Params.Add( TEXT( "LocationY" ), FVariantData( Location.Y ) );
				Params.Add( TEXT( "LocationZ" ), FVariantData( Location.Z ) );
				Params.Add( TEXT( "EnemyWeaponId" ), FVariantData( (int32)0 ) );			
			
				Events->TriggerEvent(*UniqueID, TEXT("KillOponent"), Params);				
			}
		}
	}
}
예제 #16
0
AActor * AHunterProjectile::FindHitActor()
{
	const FVector &thisLocation = GetActorLocation();

	UFlockingDataCache *cache = UFlockingDataCache::GetCacheChecked(this);
	
	ACharacter *playerCharacter = nullptr;
	for (FConstControllerIterator It = GetWorld()->GetControllerIterator(); It; ++It)
	{
		AController *controller = *It;
		APawn *otherPawn = controller->GetPawn();
		if (otherPawn == nullptr)
		{
			continue;
		}

		if (controller->IsA(APlayerController::StaticClass()))
		{
			playerCharacter = Cast<ACharacter>(controller->GetPawn());
		}
	}
	
	const TArray<FVector> &calfLocations = cache->GetTeamData(TEAM_CALVES)->m_locations;
	const TArray<FVector> &playerLocations = cache->GetLocationsPlayer();

	int32 targetCalf = FindHitActor(calfLocations, cache->GetTeamData(TEAM_CALVES)->m_agentRadius * 0.5f);
	AActor *targetActor = nullptr;
	if (targetCalf == INDEX_NONE)
	{
		int32 targetPlayer = FindHitActor(playerLocations, 0.5f * playerCharacter->GetCapsuleComponent()->GetScaledCapsuleRadius());
		if (targetPlayer != INDEX_NONE)
		{
			targetActor = playerCharacter;
		}
	}
	else
	{
		targetActor = cache->GetOrCreateTeamData(TEAM_CALVES).m_agents[targetCalf];
	}
	
	return targetActor;
}
bool FMovieScene3DTransformSectionRecorderFactory::CanRecordObject(UObject* InObjectToRecord) const
{
	if(USceneComponent* SceneComponent = Cast<USceneComponent>(InObjectToRecord))
	{
		// Dont record the root component transforms as this will be taken into account by the actor transform track
		// Also dont record transforms of skeletal mesh components as they will be taken into account in the actor transform
		bool bIsCharacterSkelMesh = false;
		if (SceneComponent->IsA<USkeletalMeshComponent>() && SceneComponent->GetOwner()->IsA<ACharacter>())
		{
			ACharacter* Character = CastChecked<ACharacter>(SceneComponent->GetOwner());
			bIsCharacterSkelMesh = SceneComponent == Character->GetMesh();
		}

		return (SceneComponent != SceneComponent->GetOwner()->GetRootComponent() && !bIsCharacterSkelMesh);
	}
	else 
	{
		return InObjectToRecord->IsA<AActor>();
	}
}
예제 #18
0
void ANinjaGameModeBase::BeginRound()
{
	UWorld* World = GetWorld();
	if (World) {
		ClearPlayerStartTags();
		for (APlayerState* CurrState : GameState->PlayerArray) {
			ANinjaPlayerState* State = (ANinjaPlayerState*)CurrState;
			if (State) {
				APlayerController* Cont = (APlayerController*) State->GetOwner();
				GEngine->AddOnScreenDebugMessage(-1, 1.5, FColor::Blue, FString::Printf(TEXT("%s"), *Cont->GetName()));
				if (State->GetChosenCharacter()) {
					GEngine->AddOnScreenDebugMessage(-1, 1.5, FColor::Red, FString::Printf(TEXT("%s - %s"), *Cont->GetName(), *State->GetChosenCharacter()->GetName()));
				}
				
				if (Cont) {
					ACharacter* Character = Cont->GetCharacter();
					APlayerStart* PS = (APlayerStart*)ChoosePlayerStart(Cont);
					if (PS) {
						PS->PlayerStartTag = FName(TEXT("Taken"));
						if (Character) {
							Character->Destroy();
						}

						FActorSpawnParameters Params;
						Params.Owner = Cont;
						ANinjaCharacter* SpawnedChar = World->SpawnActor<ANinjaCharacter>(State->GetChosenCharacter(), PS->GetActorLocation(), PS->GetActorRotation(), Params);
						if (SpawnedChar) {
							Cont->Possess(SpawnedChar);
						}
					}

				}
				
			}
		}
	}
}
예제 #19
0
bool ALabyrinthGameMode::IsSpawnpointPreferred(APlayerStart* SpawnPoint, AController* Player) const
{
	ACharacter* MyPawn = Cast<ACharacter>((*DefaultPawnClass)->GetDefaultObject<ACharacter>());

	// TO-DO: Add AI Controller
	//ALAIController* AIController = Cast<ALAIController>(Player);
	/*if (AIController != nullptr)
	{
		MyPawn = Cast<ACharacter>(BotPawnClass->GetDefaultObject<ACharacter>());
	}*/

	if (MyPawn)
	{
		const FVector SpawnLocation = SpawnPoint->GetActorLocation();
		for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; It++)
		{
			ACharacter* OtherPawn = Cast<ACharacter>(*It);
			if (OtherPawn && OtherPawn != MyPawn)
			{
				const float CombinedHeight = (MyPawn->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() + OtherPawn->GetCapsuleComponent()->GetScaledCapsuleHalfHeight()) * 2.0f;
				const float CombinedRadius = (MyPawn->GetCapsuleComponent()->GetScaledCapsuleRadius() + OtherPawn->GetCapsuleComponent()->GetScaledCapsuleRadius());
				const FVector OtherLocation = OtherPawn->GetActorLocation();

				// Check if the player start overlaps this pawn
				if (FMath::Abs(SpawnLocation.Z - OtherLocation.Z) < CombinedHeight && (SpawnLocation - OtherLocation).Size2D() < CombinedRadius)
				{
					return false;
				}
			}
		}
	}
	else
	{
		return false;
	}
	return true;
}
예제 #20
0
void ABatteryPickup::UpdateBeamTargetPoint()
{
	ACharacter* Character = GetWorld()->GetFirstPlayerController()->GetCharacter();
	FVector SocketLocation = Character->GetMesh()->GetSocketLocation("spine_02");
	ParticleSystem->SetBeamTargetPoint(0, SocketLocation, 0);
}
void ABatteryCollectorGameMode::HandleNewState(EBatteryPlayState NewState)
{

    
    switch (NewState) {
        case EBatteryPlayState::EPlaying :
            
            // If the game is playing
            //
            // spawn volume active
            for (ASpawnVolume* Volume : SpawnVolumeActors) {
                Volume->SetSpawningActive(true);
            }
            
            break;
        case EBatteryPlayState::EWon :
            
            // if we won the game
            //
            // spawn volume inactive
            for (ASpawnVolume* Volume : SpawnVolumeActors) {
                Volume->SetSpawningActive(false);
            }
            
            
            break;
        case EBatteryPlayState::EGameOver :
        {
            // If we lost
            //
            // spawn volume inactive
            // block player input
            // ragdoll the character
            for (ASpawnVolume* Volume : SpawnVolumeActors) {
                Volume->SetSpawningActive(false);
            }
            
            APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
            if(PlayerController)
            {
                PlayerController->SetCinematicMode(true, false, false, true, true);
                
                UE_LOG(LogClass, Log, TEXT("You have set Cinematic Mode"));

            }
            else
            {
                UE_LOG(LogClass, Log, TEXT("Player Controller was invalid!!"));
            }

            // now ragdoll the character
            ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
            if(MyCharacter)
            {
                MyCharacter->GetMesh()->SetSimulatePhysics(true);
                MyCharacter->GetMovementComponent()->MovementState.bCanJump=false;
                
                UE_LOG(LogClass, Log, TEXT("ACharacter jump turned off and Set Simulate Physics on"));
            }else
            {
                UE_LOG(LogClass, Log, TEXT("ACharacter was invalid!! (EGameOver State in HandleNewState"));

            }
        }
            
            break;
            
        default :

            // unknown state - incase some code forgets to call
            //
            // use to help debug
            
            break;
    }
}
void FGameplayDebuggerCategory_AI::CollectData(APlayerController* OwnerPC, AActor* DebugActor)
{
	APawn* MyPawn = Cast<APawn>(DebugActor);
	ACharacter* MyChar = Cast<ACharacter>(MyPawn);
	DataPack.PawnName = MyPawn ? MyPawn->GetHumanReadableName() : FString(TEXT("{red}No selected pawn."));
	DataPack.bIsUsingCharacter = (MyChar != nullptr);

	AAIController* MyController = MyPawn ? Cast<AAIController>(MyPawn->Controller) : nullptr;
	DataPack.bHasController = (MyController != nullptr);
	if (MyController)
	{
		if (MyController->IsPendingKill() == false)
		{
			DataPack.ControllerName = MyController->GetName();
		}
		else
		{
			DataPack.ControllerName = TEXT("Controller PENDING KILL");
		}
	}
	else
	{
		DataPack.ControllerName = TEXT("No Controller");
	}

	if (MyPawn && !MyPawn->IsPendingKill())
	{
		UCharacterMovementComponent* CharMovementComp = MyChar ? MyChar->GetCharacterMovement() : nullptr;
		if (CharMovementComp)
		{
			UPrimitiveComponent* FloorComponent = MyPawn->GetMovementBase();
			AActor* FloorActor = FloorComponent ? FloorComponent->GetOwner() : nullptr;
			DataPack.MovementBaseInfo = FloorComponent ? FString::Printf(TEXT("%s.%s"), *GetNameSafe(FloorActor), *FloorComponent->GetName()) : FString(TEXT("None"));
			DataPack.MovementModeInfo = CharMovementComp->GetMovementName();
		}

		UBehaviorTreeComponent* BehaviorComp = MyController ? Cast<UBehaviorTreeComponent>(MyController->BrainComponent) : nullptr;
		DataPack.bIsUsingBehaviorTree = (BehaviorComp != nullptr);
		if (BehaviorComp)
		{
			DataPack.CurrentAITask = BehaviorComp->DescribeActiveTasks();
			DataPack.CurrentAIState = BehaviorComp->IsRunning() ? TEXT("Running") : BehaviorComp->IsPaused() ? TEXT("Paused") : TEXT("Inactive");
			DataPack.CurrentAIAssets = BehaviorComp->DescribeActiveTrees();
		}

		UGameplayTasksComponent* TasksComponent = MyController ? MyController->GetGameplayTasksComponent() : nullptr;
		DataPack.bIsUsingGameplayTasks = (TasksComponent != nullptr);
		if (TasksComponent)
		{
			for (FConstGameplayTaskIterator It = TasksComponent->GetTickingTaskIterator(); It; ++It)
			{
				const UGameplayTask* TaskOb = *It;
				if (TaskOb)
				{
					DataPack.TickingTaskInfo += DescribeTaskHelper(*TaskOb);
					DataPack.NumTickingTasks++;
				}
			}

			for (FConstGameplayTaskIterator It = TasksComponent->GetPriorityQueueIterator(); It; ++It)
			{
				const UGameplayTask* TaskOb = *It;
				if (TaskOb)
				{
					DataPack.TaskQueueInfo += DescribeTaskHelper(*TaskOb);
					DataPack.NumTasksInQueue++;
				}
			}
		}

		DataPack.MontageInfo = MyChar ? GetNameSafe(MyChar->GetCurrentMontage()) : FString();

		UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(MyPawn->GetWorld());
		const ANavigationData* NavData = MyController && NavSys ? NavSys->GetNavDataForProps(MyController->GetNavAgentPropertiesRef()) : nullptr;
		DataPack.NavDataInfo = NavData ? NavData->GetConfig().Name.ToString() : FString();

		CollectPathData(MyController);
	}
	else
	{
		PathDataPack.PathCorridor.Reset();
		PathDataPack.PathPoints.Reset();
	}
}
void UHUDBlueprintLibrary::FindScreenLocationForWorldLocation(UObject* WorldContextObject, const FVector& InLocation, const float EdgePercent,  FVector2D& OutScreenPosition, float& OutRotationAngleDegrees, bool &bIsOnScreen)
{
	bIsOnScreen = false;
	OutRotationAngleDegrees = 0.f;
	FVector2D *ScreenPosition = new FVector2D();
	
	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	if (!World->IsValidLowLevel()) return;
	if (GEngine->GameViewport == NULL) return;
	if (GEngine->GameViewport->Viewport == NULL) return;
	
	const FVector2D ViewportSize = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY());
	const FVector2D  ViewportCenter =  FVector2D(ViewportSize.X/2, ViewportSize.Y/2);
	


	APlayerController* PlayerController = (WorldContextObject ? UGameplayStatics::GetPlayerController(WorldContextObject, 0) : NULL);
	ACharacter *PlayerCharacter = static_cast<ACharacter *> (PlayerController->GetPawn());
	
	if (!PlayerCharacter) return;
	
	
	FVector Forward = PlayerCharacter->GetActorForwardVector();
	FVector Offset = (InLocation - PlayerCharacter->GetActorLocation()).GetSafeNormal();
	
	float DotProduct = FVector::DotProduct(Forward, Offset);
	bool bLocationIsBehindCamera = (DotProduct < 0);
	
	if (bLocationIsBehindCamera)
	{
		// For behind the camera situation, we cheat a little to put the
		// marker at the bottom of the screen so that it moves smoothly
		// as you turn around. Could stand some refinement, but results
		// are decent enough for most purposes.
		
		FVector DiffVector = InLocation - PlayerCharacter->GetActorLocation();
		FVector Inverted = DiffVector * -1.f;
		FVector NewInLocation = PlayerCharacter->GetActorLocation() * Inverted;
		
		NewInLocation.Z -= 5000;
		
		PlayerController->ProjectWorldLocationToScreen(NewInLocation, *ScreenPosition);
		ScreenPosition->Y = (EdgePercent * ViewportCenter.X) * 2.f;
		ScreenPosition->X = -ViewportCenter.X - ScreenPosition->X;
	}
	 
	PlayerController->ProjectWorldLocationToScreen(InLocation, *ScreenPosition);
	
	// Check to see if it's on screen. If it is, ProjectWorldLocationToScreen is all we need, return it.
	if (ScreenPosition->X >= 0.f && ScreenPosition->X <= ViewportSize.X
		&& ScreenPosition->Y >= 0.f && ScreenPosition->Y <= ViewportSize.Y)
	{
		OutScreenPosition = *ScreenPosition;
		bIsOnScreen = true;
		return;
	}
	
	*ScreenPosition -= ViewportCenter;

	float AngleRadians = FMath::Atan2(ScreenPosition->Y, ScreenPosition->X);
	AngleRadians -= FMath::DegreesToRadians(90.f);
	
	OutRotationAngleDegrees = FMath::RadiansToDegrees(AngleRadians) + 180.f;
	
	float Cos = cosf(AngleRadians);
	float Sin = -sinf(AngleRadians);
	
	ScreenPosition = new FVector2D(ViewportCenter.X + (Sin * 150.f), ViewportCenter.Y + Cos * 150.f);
	
	float m = Cos / Sin;
	
	FVector2D ScreenBounds = ViewportCenter * EdgePercent;
	
	if (Cos > 0)
	{
		ScreenPosition = new FVector2D(ScreenBounds.Y/m, ScreenBounds.Y);
	}
	else
	{
		ScreenPosition = new FVector2D(-ScreenBounds.Y/m, -ScreenBounds.Y);
	}
	
	if (ScreenPosition->X > ScreenBounds.X)
	{
		ScreenPosition = new FVector2D(ScreenBounds.X, ScreenBounds.X*m);
	}
	else if (ScreenPosition->X < -ScreenBounds.X)
	{
		ScreenPosition = new FVector2D(-ScreenBounds.X, -ScreenBounds.X*m);
	}
	
	*ScreenPosition += ViewportCenter;
	
	OutScreenPosition = *ScreenPosition;
	
}
void ABaseController::SearchForTarget()
{
	if (GetPawn() == NULL || StopSearching)
	{
		return;
	}

	bool canSeePlayer = false;
	FHitResult hit(ForceInit);
	FCollisionQueryParams traceParams = FCollisionQueryParams(FName(TEXT("RV_Trace")), true, Self);
	traceParams.bTraceComplex = true;
	traceParams.bTraceAsyncScene = true;

	FVector EnemyLocation = Self->GetActorLocation();
	for (FConstPawnIterator i = World->GetPawnIterator(); i; ++i)
	{
		ACharacter* poesibleTarget = Cast<ACharacter>(*i);
		if (poesibleTarget != Cast<ACharacter>(Self) && poesibleTarget != NULL)
		{

			FVector possibleTargetLocation = poesibleTarget->GetActorLocation();
			bool bHit = World->LineTraceSingleByChannel(hit, Self->EyeLocation, possibleTargetLocation, ECC_Visibility, traceParams);

			bool bPersistent = true;
			float LifeTime = 5.f;

			// @fixme, draw line with thickneES = 2.f?
			if (bHit && hit.bBlockingHit)
			{
				// Red up to the blocking hit, green thereafter
				//DrawDebugLine(World, Self->EyeLocation, hit.ImpactPoint, FColor::Red, bPersistent, LifeTime);
				//DrawDebugLine(World, hit.ImpactPoint, possibleTargetLocation, FColor::Green, bPersistent, LifeTime);
				//DrawDebugPoint(World, hit.ImpactPoint, 16.f, FColor::Red, bPersistent, LifeTime);
			}
			else
			{
				// no hit means all red
				//DrawDebugLine(World, Self->EyeLocation, possibleTargetLocation, FLinearColor::Red, bPersistent, LifeTime);
			}

			if (hit.GetActor() && hit.GetActor()->GetName() == poesibleTarget->GetName() && hit.bBlockingHit)
			{
				if (Self->EState != EnemyState::ES_Searching)
					TargetsLastKnownPosition = hit.GetActor()->GetActorLocation();

				BBComp->SetValue<UBlackboardKeyType_Vector>(TargetsLastKnownPositionID, TargetsLastKnownPosition);
				float distanceFromPoESibleTarget = FVector::Dist(EnemyLocation, possibleTargetLocation);
				if (distanceFromPoESibleTarget <= Self->SightRange && distanceFromPoESibleTarget > Self->AttackRange && Self->AttackCompleted)
				{
					SetTarget(poesibleTarget, distanceFromPoESibleTarget);

					ResetFocusActor();
					SetState(EnemyState::ES_Chasing, "Chasing");

					BBComp->SetValue<UBlackboardKeyType_Bool>(MovedToLastKnownPositionID, false);
				}
				else if (distanceFromPoESibleTarget <= Self->AttackRange && Self->AttackCompleted)
				{
					Self->AttackStarted = true;
					Self->AttackCompleted = false;
					SetTarget(poesibleTarget, distanceFromPoESibleTarget);
					SetFocusActor(Cast<AActor>(Target));

					AttackLocation = poesibleTarget->GetActorLocation();

					SetState(EnemyState::ES_Attacking, "Attacking");

					BBComp->SetValue<UBlackboardKeyType_Bool>(MovedToLastKnownPositionID, false);
				}
				else if (Self->AttackCompleted)
				{
					ResetFocusActor();
					SetState(EnemyState::ES_Searching, "Searching");

					SearchForTargetAtLastKnownPosition();
				}
			}
			else if (hit.GetActor() && hit.GetActor()->GetName() != poesibleTarget->GetName() && hit.bBlockingHit)
			{
				if (Self->EState != EnemyState::ES_Searching)
					SearchForTargetAtLastKnownPosition();

				Self->AttackStarted = false;
				Self->AttackCompleted = true;

				ResetFocusActor();
				SetState(EnemyState::ES_Searching, "Searching");
			}
		}
	}
}