// Idling
void RPG_PlayerControllerState::Idling::OnTick(RPG_ControllerComponent *const controller, float const deltaTime)
{
  RPG_ControllerStateBase::OnTick(controller, deltaTime);

  RPG_PlayerControllerComponent *playerController = vstatic_cast<RPG_PlayerControllerComponent*>(controller);

  RPG_PlayerControllerInput const& input = playerController->GetInput();
  RPG_PlayerControllerInput const& prevInput = playerController->GetPrevInput();

  // Tick special attacks
  if(RPG_PlayerControllerState::OnTickSpecialAttacks(playerController, input, prevInput))
  {
    return;
  }

  // Move
  bool const primaryDown = input.IsDown(RPG_PlayerControllerInput::B_PRIMARY, prevInput);
  bool const primaryHeld = input.IsPressed(RPG_PlayerControllerInput::B_PRIMARY) && prevInput.IsPressed(RPG_PlayerControllerInput::B_PRIMARY);

  if(primaryDown || primaryHeld)
  {
    if(primaryDown && input.m_targetEntity)
    {
      // Move to target
      controller->SetTarget(input.m_targetEntity);
      controller->SetTargetPoint(input.m_targetEntity->GetPosition());
    }
    else
    {
      // Move to point
      controller->SetTarget(NULL);
      controller->SetTargetPoint(input.m_targetPoint);
    }

    hkvVec3 const targetPoint = controller->GetTargetPoint();
    hkvVec3 const targetPointToCharacter(controller->GetCharacter()->GetPosition() - targetPoint);
    float const targetPointToCharactedDistSqr = targetPointToCharacter.getLengthSquared();
    float const distTolerance = hkvMath::Max(60.0f, controller->GetPathGoalReachedTolerance());
    float const distToleranceSqr = distTolerance * distTolerance;

    if(targetPointToCharactedDistSqr > distToleranceSqr)
    {
      controller->SetState(RPG_ControllerStateId::kMoving);
      return;
    }
  }
}
// Moving
void RPG_PlayerControllerState::Moving::OnTick(RPG_ControllerComponent *const controller, float const deltaTime)
{
  RPG_ControllerStateBase::OnTick(controller, deltaTime);

  RPG_PlayerControllerComponent *playerController = vstatic_cast<RPG_PlayerControllerComponent*>(controller);

  RPG_PlayerControllerInput const& input = playerController->GetInput();
  RPG_PlayerControllerInput const& prevInput = playerController->GetPrevInput();

  // Tick special attacks
  if(RPG_PlayerControllerState::OnTickSpecialAttacks(playerController, input, prevInput))
  {
    return;
  }

  // Move or melee
  bool const primaryDown = input.IsDown(RPG_PlayerControllerInput::B_PRIMARY, prevInput);
  bool const primaryHeld = input.IsPressed(RPG_PlayerControllerInput::B_PRIMARY) && prevInput.IsPressed(RPG_PlayerControllerInput::B_PRIMARY);

  // Update target on click
  if(primaryDown)
  {
    playerController->SetTarget(input.m_targetEntity);
  }

  RPG_Character *const character = playerController->GetCharacter();
  RPG_DamageableEntity *const target = playerController->GetTarget();

  if(target)
  {
    hkvVec3 targetToCharacterProjectedDir;
    float targetToCharacterProjectedDist;
    RPG_ControllerUtil::GetProjectedDirAndDistanceFromTarget(character, target, targetToCharacterProjectedDir, targetToCharacterProjectedDist);

    float const minDist = RPG_ControllerUtil::GetMinimumDistanceToAttack(character, target);

    if(targetToCharacterProjectedDist > minDist)
    {
      controller->SetTargetPoint(target->GetPosition() + (target->GetCollisionRadius() + character->GetCollisionRadius()) * targetToCharacterProjectedDir);
    }
    else
    {
      controller->GetCharacter()->RaiseAnimationEvent(RPG_CharacterAnimationEvent::kMeleeAttack);
      controller->SetState(RPG_ControllerStateId::kMeleeAttacking);
      return;
    }
  }
  else if(primaryDown || primaryHeld)
  {
    controller->SetTargetPoint(input.m_targetPoint);
  }

  // Handle target reached or target update
  hkvVec3 const targetPoint = controller->GetTargetPoint();
  hkvVec3 const targetPointToCharacter(character->GetPosition() - targetPoint);
  float const targetPointToCharactedDistSqr = targetPointToCharacter.getLengthSquared();
  float const pathGoaltoleranceSqr = controller->GetPathGoalReachedTolerance() * controller->GetPathGoalReachedTolerance();

  if(targetPointToCharactedDistSqr <= pathGoaltoleranceSqr)
  {
    controller->SetState(RPG_ControllerStateId::kIdling);
    return;
  }
  else if(primaryDown || primaryHeld)
  {
    controller->RequestPath(targetPoint);
  }

  // Reorient
  hkvVec3 dir;
  RPG_ControllerUtil::CalcDirection(dir, controller->GetCharacter()->GetDirection(), controller->GetDirection(), 0.25f);
  controller->GetCharacter()->SetDirection(dir);
}