internal void UpdatePlayerRemainingMovement(ActorData actor, bool send = true)
        {
            ActorTurnSM     turnSm          = actor.gameObject.GetComponent <ActorTurnSM>();
            ActorController actorController = actor.gameObject.GetComponent <ActorController>();
            ActorMovement   actorMovement   = actor.GetActorMovement();

            float movementCost = GetActorMovementCost(actor, out float lastStepCost);

            bool cannotExceedMaxMovement = GameplayData.Get()?.m_movementMaximumType == GameplayData.MovementMaximumType.CannotExceedMax;

            List <ActorTargeting.AbilityRequestData> abilityRequest = actor.TeamSensitiveData_authority.GetAbilityRequestData();
            bool abilitySet = !abilityRequest.IsNullOrEmpty() && abilityRequest[0].m_actionType != AbilityData.ActionType.INVALID_ACTION;

            actor.RemainingHorizontalMovement        = actorMovement.CalculateMaxHorizontalMovement() - movementCost;
            actor.RemainingMovementWithQueuedAbility = abilitySet ? actor.RemainingHorizontalMovement : actorMovement.CalculateMaxHorizontalMovement(true) - movementCost;
            actor.QueuedMovementAllowsAbility        = abilitySet ||
                                                       (cannotExceedMaxMovement
                    ? actor.RemainingMovementWithQueuedAbility >= 0
                    : actor.RemainingMovementWithQueuedAbility + lastStepCost > 0);

            Log.Info($"UpdatePlayerMovement:  Basic: {actor.m_postAbilityHorizontalMovement}/{actor.m_maxHorizontalMovement}, +",
                     $"Remaining: {actor.RemainingMovementWithQueuedAbility}/{actor.RemainingHorizontalMovement}, " +
                     $"Movement cost: {movementCost}, Ability set: {abilitySet}, Ability allowed: {actor.QueuedMovementAllowsAbility}, " +
                     $"Movement max type: {GameplayData.Get()?.m_movementMaximumType}");

            actorMovement.UpdateSquaresCanMoveTo();
            if (send)
            {
                actorController.CallRpcUpdateRemainingMovement(actor.RemainingHorizontalMovement, actor.RemainingMovementWithQueuedAbility);
            }
        }
        public void CmdSetSquare(ActorTurnSM actorTurnSM, int x, int y, bool setWaypoint)
        {
            ActorData actor = actorTurnSM.gameObject.GetComponent <ActorData>();

            if (!GameFlowData.Get().IsInDecisionState())
            {
                Log.Info($"Recieved CmdSetSquare not in desicion state! {actor.DisplayName} [{x}, {y}] (setWaypoint = {setWaypoint})");
                actorTurnSM.CallRpcTurnMessage((int)TurnMessage.MOVEMENT_REJECTED, 0);
                return;
            }

            Log.Info($"CmdSetSquare {actor.DisplayName} [{x}, {y}] (setWaypoint = {setWaypoint})");

            BoardSquare   boardSquare   = Board.Get().GetSquare(x, y);
            ActorMovement actorMovement = actor.GetActorMovement();

            if (!setWaypoint)
            {
                ClearMovementRequest(actor, false);
            }

            actorMovement.UpdateSquaresCanMoveTo();

            if (!actor.CanMoveToBoardSquare(boardSquare))
            {
                boardSquare = actorMovement.GetClosestMoveableSquareTo(boardSquare, false);
            }
            if (actor.TeamSensitiveData_authority.MovementLine == null)
            {
                actor.TeamSensitiveData_authority.MovementLine = new LineData.LineInstance();
            }
            if (actor.TeamSensitiveData_authority.MovementLine.m_positions.Count == 0)
            {
                actor.TeamSensitiveData_authority.MovementLine.m_positions.Add(actor.InitialMoveStartSquare.GetGridPosition());
            }

            BoardSquarePathInfo path = actorMovement.BuildPathTo(actor.TeamSensitiveData_authority.MoveFromBoardSquare, boardSquare);

            if (path == null)  // TODO check cost
            {
                Log.Info($"CmdSetSquare: Movement rejected");
                UpdatePlayerRemainingMovement(actor); // TODO updating because we cancelled movement - perhaps we should not cancel in this case
                actorTurnSM.CallRpcTurnMessage((int)TurnMessage.MOVEMENT_REJECTED, 0);
                return;
            }

            //List<GridPos> posList = path.ToGridPosPath();
            List <GridPos> posList = new List <GridPos>();

            for (var pathNode = path; pathNode.next != null; pathNode = pathNode.next)
            {
                posList.Add(pathNode.next.square.GetGridPosition()); // TODO why doesnt path.ToGridPosPath() work?
            }

            actor.TeamSensitiveData_authority.MovementLine.m_positions.AddRange(posList);
            actor.TeamSensitiveData_authority.MoveFromBoardSquare = boardSquare;
            actor.MoveFromBoardSquare = boardSquare;

            UpdatePlayerRemainingMovement(actor);
            actorTurnSM.CallRpcTurnMessage((int)TurnMessage.MOVEMENT_ACCEPTED, 0);
        }