✓ Selection States

Gamepad users select slots and perform actions through a state machine. Each state represents a step in the selection flow, from idle to completing actions like swap, drop, or quick move.

State Overview

The selection state machine

🖼

Step 0: Idle

Ready to select a slot

🎒 SELECTING
D-Pad selects slot
🔄

Step 1: Source Selected

First slot chosen, waiting for target

🎒 SWAP - SELECT TARGET
From Source State
Same slot pressedCancel
Y pressedPerform Swap
X pressedEnter Drop Mode

State Details

What happens in each state

State Step Description Enabled Actions
Idle 0 Waiting for user to select a slot with D-Pad D-Pad navigation, B to cancel
Source 1 Source slot selected, waiting for target or action Y: Swap, X: Drop, A: QuickMove, B: Cancel
Dropping 2 Adjusting drop amount with D-Pad Up/Down DPadUp/Down: Amount, A: Drop, B: Cancel

Actions

What each action does

Y
Swap

Swap the source item with the currently selected slot.

Select sourceYSelect targetItems swapped
X
Drop

Drop the selected item with configurable amount.

Select itemXAdjust amountA to confirm
A + R1
Quick Move

Move item to first empty slot in the other container.

Hotbar itemA+R1Moves to Storage
Storage itemA+R1Moves to Hotbar
B
Cancel

Cancel current selection and return to Idle state.

Any stateBClear selection

Code Structure

SelectionManager implementation

Selection State Luau
local SelectionState = {
    enabled = false,
    step = 0,           -- 0: idle, 1: source, 2: dropping
    sourceType = nil,     -- "Hotbar" | "Storage"
    sourceSlot = nil,      -- Slot index
    sourceFrame = nil,     -- Frame reference
}
Get Slot Info Luau
function SelectionManager.GetSelectedSlotInfo()
    local selected = GuiService.SelectedObject
    if not selected then return nil end
    
    local slotFrame = selected.Parent 
    local slotType
    
    if slotFrame.Parent.Name == "Hotbar" then
        slotType = "Hotbar"
    elseif slotFrame.Parent.Name == "ScrollingFrame" then
        slotType = "Storage"
    end
    
    local slotName = slotFrame.Name:gsub("_", "")
    local slotIndex = tonumber(slotName)
    
    return {
        Type = slotType,
        Index = slotIndex,
        Frame = slotFrame
    }
end

Swap Handler

Step-by-step swap logic

HandleSwap Logic Luau
function SelectionManager.HandleSwap()
    local selected = SelectionManager.GetSelectedSlotInfo()
    if not selected then return end
    
    -- Step 0: Select source
    if SelectionState.step == 0 then
        SelectionState.step = 1
        SelectionState.sourceType = selected.Type
        SelectionState.sourceSlot = selected.Index
        SelectionState.sourceFrame = selected.Frame
        
        SelectionManager.ApplySelectionHighlight(selected.Frame)
        SelectionManager.NotifyStateChanged()
    
    -- Step 1: Select target and swap
    elseif SelectionState.step == 1 then
        -- Same slot = cancel
        if SelectionState.sourceType == selected.Type 
           and SelectionState.sourceSlot == selected.Index then
            SelectionManager.CancelSelection()
            return
        end
        
        -- Perform swap
        InventoryController.Swap(
            SelectionState.sourceType,
            SelectionState.sourceSlot,
            selected.Type,
            selected.Index,
            true
        )
        
        SelectionManager.CancelSelection()
    end
end

Drop Handler

Drop with amount selection

HandleDrop Logic Luau
function SelectionManager.HandleDrop()
    local selected = SelectionManager.GetSelectedSlotInfo()
    if not selected then return end
    
    -- Get item data
    local store = require(script.Parent.Parent.CoreState.InventoryStore)
    local item = store:GetItemFromSlot(selected.Type, selected.Index)
    if not item then return end
    
    -- Enter dropping state
    SelectionState.step = 2
    SelectionManager.NotifyStateChanged()
    
    -- Disable inventory, enable drop context
    InputManager.SetInventoryEnabled(false)
    InputManager.SetDropEnabled(true)
    SelectionManager.LoadDropBinds()
    
    -- Show drop UI
    ConsoleDropUI.Show(item, 1)
    
    -- Set up callbacks
    ConsoleDropUI.OnDrop = function(amount)
        InventoryController.Drop(selected.Type, selected.Index, amount, true)
        SelectionManager.CloseDropUI()
    end
    
    ConsoleDropUI.OnDropAll = function()
        InventoryController.Drop(selected.Type, selected.Index, item.Amount, true)
        SelectionManager.CloseDropUI()
    end
    
    ConsoleDropUI.OnCancel = function()
        SelectionManager.CloseDropUI()
    end
end

Hooks Integration

Firing hooks on selection changes

SelectionManager fires hooks when slots are selected/deselected:

Selection Hooks Luau
-- Apply highlight when slot is selected
function SelectionManager.ApplySelectionHighlight(frame)
    if HookManager then
        HookManager:Fire("OnSelect", frame)
    end
end

-- Clear highlight when slot is deselected
function SelectionManager.ClearSelectionHighlight(frame)
    if HookManager then
        HookManager:Fire("OnDeselect", frame)
    end
end
Hook Arguments Fired When
OnSelect frame Slot is selected (step 0 → 1)
OnDeselect frame Selection is cleared

Related Documentation

See also