using Godot; using Godot.Collections; using System; using System.Data; using System.Linq; [GlobalClass] public partial class CardStateMachine : Node { private State currentState; private CardUI cardUI; private const float DRAG_MINIMUM_THRESHOLD = 0.05f; private bool minimumDragTimeElsapsed = false; private bool played; [Signal] public delegate void TransitionRequestedEventHandler(State from, State to); public void Init(CardUI cardUI) { // construct card states currentState = State.Base; this.cardUI = cardUI; this.Enter(); } public async void Enter(State state = State.None) { switch (state) { case State.None: this.Enter(currentState); break; case State.Base: if (!cardUI.IsNodeReady()) { await ToSignal(cardUI, Node.SignalName.Ready); } cardUI.EmitSignal(CardUI.SignalName.ReparentRequested, cardUI); cardUI.color.Color = Color.Color8(0, 128, 0); cardUI.state.Text = "BASE"; cardUI.PivotOffset = Vector2.Zero; if (cardUI.tapped) { cardUI.RotationDegrees = 90.0f; cardUI.Position = new Vector2(cardUI.Position.X + 200.0f, cardUI.Position.Y); } else { cardUI.RotationDegrees = 0.0f; } break; case State.Clicked: cardUI.color.Color = Color.Color8(255, 165, 0); cardUI.state.Text = "CLICKED"; cardUI.dropDetector.Monitoring = true; break; case State.Dragging: Node uiLayer = GetTree().GetFirstNodeInGroup("ui_layer"); if (IsInstanceIdValid(uiLayer.GetInstanceId())) { cardUI.Reparent(uiLayer); } cardUI.color.Color = Color.Color8(0, 0, 128); cardUI.state.Text = "DRAGGING"; minimumDragTimeElsapsed = false; SceneTreeTimer thresholdTimer = GetTree().CreateTimer(DRAG_MINIMUM_THRESHOLD, false); thresholdTimer.Connect(SceneTreeTimer.SignalName.Timeout, Callable.From(() => minimumDragTimeElsapsed = true)); break; case State.Released: cardUI.color.Color = Color.Color8(148, 0, 211); cardUI.state.Text = "RELEASED"; played = false; if (cardUI.targetedZone == CardZone.ZoneType.Battlefield) { played = true; cardUI.EmitSignal(CardUI.SignalName.ReparentRequested, cardUI); Node topLayer = GetTree().GetFirstNodeInGroup("top_layer"); if (topLayer is Main mainNode) { ManaGroveState gameState = mainNode.GetNode("ManaGroveState"); gameState.EmitSignal(ManaGroveState.SignalName.MoveCard, [cardUI, (int)cardUI.targetedZone]); } } else { this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Released, (int)State.Base]); } break; } } public void Exit(State state = State.None) { switch (state) { case State.None: this.Exit(currentState); break; } } public void OnInput(InputEvent @event) { switch (currentState) { case State.Clicked: if (cardUI.currentZone == CardZone.ZoneType.Battlefield) { if (cardUI.tapped) { cardUI.Position = new Vector2(cardUI.Position.X - 200.0f, cardUI.Position.Y); } cardUI.tapped = !cardUI.tapped; this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Clicked, (int)State.Base]); } else { if (@event.IsClass("InputEventMouseMotion")) { this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Clicked, (int)State.Dragging]); } } break; case State.Dragging: bool mouseMotion = @event.IsClass("InputEventMouseMotion"); bool confirm = @event.IsActionReleased("left_mouse"); bool canBePlayed = cardUI.CanBePlayed(cardUI.targetedZone); if (mouseMotion) { cardUI.GlobalPosition = cardUI.GetGlobalMousePosition() - cardUI.PivotOffset; } if (minimumDragTimeElsapsed && confirm && canBePlayed) { GetViewport().SetInputAsHandled(); this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Dragging, (int)State.Released]); } else if (minimumDragTimeElsapsed && confirm && !canBePlayed) { cardUI.targetedZone = CardZone.ZoneType.None; this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Dragging, (int)State.Base]); } break; case State.Released: this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Released, (int)State.Base]); break; } } public void OnGuiInput(InputEvent @event) { switch (currentState) { case State.Base: if (@event.IsActionPressed("left_mouse")) { cardUI.PivotOffset = cardUI.GetGlobalMousePosition() - cardUI.GlobalPosition; this.EmitSignal(CardStateMachine.SignalName.TransitionRequested, [(int)State.Base, (int)State.Clicked]); } break; } } public void OnMouseEntered() { } public void OnMouseExited() { } public void OnTransitionRequested(State from, State to) { if (from != currentState) { return; } Exit(from); Enter(to); currentState = to; } } public enum State { None = -1, Base = 0, Clicked, Dragging, Released }