Remappable Binds V2
Key Required

Remappable Binds V2

Magic Trainingsquinchsquinch 389 views 16 executesUpdated Jan 27, 2026
Unrated
00
Lua Script•323 lines (10904 chars)
-- Services
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local UserInputService = game:GetService("UserInputService")
local TextChatService = game:GetService("TextChatService")

-- Script-wide variables
local Keybinds = {} 
local BindingTarget = nil 
local ScreenGui
local SpellButtons = {} 

-- Audio Feedback (Creates a sound in CoreGui for efficiency)
local SoundId = "rbxassetid://6895079853" -- A simple "blip" sound
local BindSound = Instance.new("Sound")
BindSound.SoundId = SoundId
BindSound.Volume = 0.5
BindSound.Parent = game:GetService("CoreGui")

local function PlayFeedback()
    if BindSound then
        BindSound:Play()
    end
end

-- SPELL DATA
local Spells = {
    ["Stunning"] = {
        "Duro", "Ebublio", "Glacius", "Impedimenta", "Incarcerous", 
        "Levicorpus", "Locomotor Wibbly", "Petrificus Totalus", 
        "Stupefy", "Tarantallegra"
    },
    ["Killing"] = {
        "Avada Kedavra", "Defodio", "Deletrius", "Sectumsempra"
    },
    ["Damaging"] = {
        "Alarte Ascendare", "Baubillious", "Bombarda", "Confringo", 
        "Crucio", "Depulso", "Diffindo", "Everte Statum", "Expulso", 
        "Flare", "Incendio", "Reducto", "Tonitro", "Verdimillious"
    },
    ["Utility"] = {
        "Carpe Retractum", "Confundo", "Expelliarmus", "Flipendo", 
        "Rictusempra", "Obliviate", "Obscuro", "Silencio", 
        "Protego", "Protego Totalum", "Appa", "Ascendio", 
        "Episkey", "Finite Incantatem", "Liberacorpus", "Relashio", 
        "Rennervate", "Vulnera Sanentur", "Aboleo", "Accio", "Calvorio", 
        "Diminuendo", "Engorgio Skullus", "Lumos", "Melofors", 
        "Morsmordre", "Nox"
    }
}

-- CHAT FUNCTION
local function CastSpell(spellName)
    if TextChatService.ChatVersion == Enum.ChatVersion.TextChatService then
        local TextChannels = TextChatService:FindFirstChild("TextChannels")
        if TextChannels then
            local RBXGeneral = TextChannels:FindFirstChild("RBXGeneral")
            if RBXGeneral then
                RBXGeneral:SendAsync(spellName)
                return
            end
        end
    end

    local Chat = game:GetService("ReplicatedStorage"):FindFirstChild("DefaultChatSystemChatEvents")
    if Chat then
        local SayMessage = Chat:FindFirstChild("SayMessageRequest")
        if SayMessage then
            SayMessage:FireServer(spellName, "All")
        end
    end
end

-- Helper to update button text/color
local function UpdateButtonVisuals(SpellName)
    if not ScreenGui then return end
    local Btn = SpellButtons[SpellName]
    
    if Btn then
        local bind = Keybinds[SpellName]
        if BindingTarget == SpellName then
            Btn.Text = "[KEY?] " .. SpellName
            Btn.BackgroundColor3 = Color3.fromRGB(200, 50, 50) -- Bright Red when waiting
            Btn.TextColor3 = Color3.new(1, 1, 1)
        elseif bind then
            Btn.Text = "[" .. tostring(bind.Name):sub(6) .. "] " .. SpellName -- Remove "KeyCode."
            Btn.BackgroundColor3 = Color3.fromRGB(30, 100, 30) -- Green when bound
            Btn.BackgroundTransparency = 0.2
            Btn.TextColor3 = Color3.new(1, 1, 1)
        else
            Btn.Text = SpellName
            Btn.BackgroundColor3 = Color3.fromRGB(20, 20, 20) -- Dark Grey default
            Btn.BackgroundTransparency = 0.5
            Btn.TextColor3 = Color3.new(0.8, 0.8, 0.8)
        end
    end
end

-- SEARCH LOGIC
local function UpdateSearch(query)
    query = string.lower(query)
    
    for SpellName, Btn in pairs(SpellButtons) do
        if string.find(string.lower(SpellName), query) ~= nil then
            Btn.Visible = true
        else
            Btn.Visible = false
        end
    end

    -- Handle Headers
    for Category, SpellList in pairs(Spells) do
        local hasVisibleSpell = false
        for _, SpellName in pairs(SpellList) do
            local Btn = SpellButtons[SpellName]
            if Btn and Btn.Visible then
                hasVisibleSpell = true
                break
            end
        end
        local Header = ScreenGui.MainFrame.ScrollFrame:FindFirstChild("Header_" .. Category)
        if Header then Header.Visible = hasVisibleSpell end
    end
end

-- UI CREATION
local function CreateGUI()
    if ScreenGui then ScreenGui:Destroy() end

    ScreenGui = Instance.new("ScreenGui")
    ScreenGui.Name = "SpellBinderPro"
    ScreenGui.ResetOnSpawn = false
    ScreenGui.Parent = LocalPlayer:WaitForChild("PlayerGui")

    -- Main Window (Fixed Bottom-Left for Tactical Visibility)
    local MainFrame = Instance.new("Frame")
    MainFrame.Name = "MainFrame"
    MainFrame.Size = UDim2.new(0, 220, 0, 400)
    MainFrame.Position = UDim2.new(0, 10, 1, -410) -- Pinned bottom left
    MainFrame.BackgroundColor3 = Color3.fromRGB(15, 15, 15)
    MainFrame.BorderSizePixel = 0
    MainFrame.Active = false -- Locked position (can't drag to prevent accidental movement)
    MainFrame.Parent = ScreenGui

    -- Outline
    local Stroke = Instance.new("UIStroke")
    Stroke.Color = Color3.fromRGB(80, 80, 80)
    Stroke.Thickness = 1
    Stroke.Parent = MainFrame

    local Corner = Instance.new("UICorner")
    Corner.CornerRadius = UDim.new(0, 4)
    Corner.Parent = MainFrame

    -- Title Bar (Top)
    local Title = Instance.new("TextLabel")
    Title.Name = "Title"
    Title.Size = UDim2.new(1, 0, 0, 25)
    Title.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
    Title.TextColor3 = Color3.new(1, 1, 1)
    Title.Text = "SPELL BINDER [F5]"
    Title.Font = Enum.Font.GothamBold
    Title.TextSize = 12
    Title.Parent = MainFrame

    local TitleCorner = Instance.new("UICorner")
    TitleCorner.CornerRadius = UDim.new(0, 4)
    TitleCorner.Parent = Title

    -- SEARCH BAR (Moved to top for ergonomics)
    local SearchBox = Instance.new("TextBox")
    SearchBox.Name = "SearchBox"
    SearchBox.Size = UDim2.new(1, -10, 0, 20)
    SearchBox.Position = UDim2.new(0, 5, 0, 27)
    SearchBox.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
    SearchBox.TextColor3 = Color3.new(1, 1, 1)
    SearchBox.PlaceholderText = "Search..."
    SearchBox.PlaceholderColor3 = Color3.fromRGB(100, 100, 100)
    SearchBox.Font = Enum.Font.Gotham
    SearchBox.TextSize = 11
    SearchBox.ClearTextOnFocus = false
    SearchBox.Parent = MainFrame

    local SearchCorner = Instance.new("UICorner")
    SearchCorner.CornerRadius = UDim.new(0, 2)
    SearchCorner.Parent = SearchBox

    SearchBox:GetPropertyChangedSignal("Text"):Connect(function()
        UpdateSearch(SearchBox.Text)
    end)

    -- Content Frame (Scrolling)
    local ScrollFrame = Instance.new("ScrollingFrame")
    ScrollFrame.Name = "ScrollFrame"
    ScrollFrame.Size = UDim2.new(1, -5, 1, -55) -- Adjusted for top search
    ScrollFrame.Position = UDim2.new(0, 0, 0, 50) -- Pushed down below search
    ScrollFrame.BackgroundTransparency = 1
    ScrollFrame.ScrollBarThickness = 3
    ScrollFrame.ScrollBarImageColor3 = Color3.new(0.4, 0.4, 0.4)
    ScrollFrame.Parent = MainFrame

    local Layout = Instance.new("UIListLayout")
    Layout.Padding = UDim.new(0, 2)
    Layout.Parent = ScrollFrame

    -- Populate UI
    for Category, SpellList in pairs(Spells) do
        -- Category Header
        local CatLabel = Instance.new("TextLabel")
        CatLabel.Name = "Header_" .. Category
        CatLabel.Size = UDim2.new(1, 0, 0, 15)
        CatLabel.BackgroundTransparency = 1
        CatLabel.Text = Category
        CatLabel.TextColor3 = Color3.fromRGB(255, 200, 0) -- Gold headers for visibility
        CatLabel.TextXAlignment = Enum.TextXAlignment.Left
        CatLabel.Font = Enum.Font.GothamBold
        CatLabel.TextSize = 10
        CatLabel.Parent = ScrollFrame

        -- Spells
        for _, SpellName in pairs(SpellList) do
            local Btn = Instance.new("TextButton")
            Btn.Name = SpellName
            Btn.Size = UDim2.new(1, 0, 0, 18) -- Compact height
            Btn.BackgroundColor3 = Color3.fromRGB(20, 20, 20)
            Btn.BackgroundTransparency = 0.5
            Btn.TextColor3 = Color3.new(0.8, 0.8, 0.8)
            Btn.Font = Enum.Font.Gotham
            Btn.TextSize = 11
            Btn.Text = SpellName
            Btn.TextXAlignment = Enum.TextXAlignment.Left
            Btn.Parent = ScrollFrame

            local BtnCorner = Instance.new("UICorner")
            BtnCorner.CornerRadius = UDim.new(0, 2)
            BtnCorner.Parent = Btn

            local BtnPadding = Instance.new("UIPadding")
            BtnPadding.PaddingLeft = UDim.new(0, 5)
            BtnPadding.Parent = Btn

            SpellButtons[SpellName] = Btn

            -- Left Click: Cast
            Btn.MouseButton1Click:Connect(function()
                CastSpell(SpellName)
            end)

            -- Right Click: Start Binding
            Btn.MouseButton2Click:Connect(function()
                if BindingTarget == SpellName then
                    BindingTarget = nil
                else
                    BindingTarget = SpellName
                end
                -- Refresh all
                for s, _ in pairs(SpellButtons) do UpdateButtonVisuals(s) end
            end)
        end
    end
    
    ScrollFrame.CanvasSize = UDim2.new(0, 0, 0, Layout.AbsoluteContentSize.Y + 5)
end

-- INPUT HANDLING
UserInputService.InputBegan:Connect(function(Input, GameProcessed)
    if GameProcessed then return end

    -- Toggle GUI Visibility (F5)
    if Input.KeyCode == Enum.KeyCode.F5 then
        ScreenGui.Enabled = not ScreenGui.Enabled
        return
    end

    -- 1. Unbind (Left Control)
    if Input.KeyCode == Enum.KeyCode.LeftControl and BindingTarget then
        Keybinds[BindingTarget] = nil
        UpdateButtonVisuals(BindingTarget)
        BindingTarget = nil
        PlayFeedback()
        return
    end

    -- 2. Bind Key
    if BindingTarget then
        if Input.KeyCode ~= Enum.KeyCode.Unknown and Input.UserInputType == Enum.UserInputType.Keyboard then
            local NewKey = Input.KeyCode

            -- Check for existing bind (One Key = One Spell)
            local OldSpell = nil
            for SpellName, Key in pairs(Keybinds) do
                if Key == NewKey then
                    OldSpell = SpellName
                    break
                end
            end

            if OldSpell then
                Keybinds[OldSpell] = nil
                UpdateButtonVisuals(OldSpell)
            end

            Keybinds[BindingTarget] = NewKey
            local BoundSpell = BindingTarget
            BindingTarget = nil
            
            UpdateButtonVisuals(BoundSpell)
            PlayFeedback() -- Audio confirmation
        end
        return
    end

    -- 3. Cast via Keybind
    for SpellName, Key in pairs(Keybinds) do
        if Input.KeyCode == Key then
            CastSpell(SpellName)
            return
        end
    end
end)

-- Start
CreateGUI()

Features & Information

added gui! left ctrl to unbind, right click then key to bind

Community Comments (2)

hasuvenhasuvenJan 27, 2026

w

squinchsquinchJan 27, 2026

V3 POSTED NOW!

More Scripts for Magic Training