Advertisement
alexhernandezroblox

Untitled

Apr 22nd, 2025
18
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.02 KB | None | 0 0
  1. local RS = game.ReplicatedStorage
  2. local CAS = game:GetService("ContextActionService")
  3. local players = game:GetService("Players")
  4. local plr = players.LocalPlayer
  5. local keybinds = require(RS.Keybinds) -- Module has all moves' (e.g. Jab, Uppercut, etc) keybinds, damage, etc. This can be used both on the client and server, since I don't want exploiters changing their damage to 100000.
  6. local attackHandler = require(RS.AttackHandler) -- Basically does all the moves, this module can be used server sided and client sides as well. Since this is a local script, I use it locally and only for server client VFX replication.
  7.  
  8. -- Moves
  9. local MoveList = {} -- So there is a class named "Boxer" which is my only class (I plan to add more), but this is simply to find all the moves' settings in the keybinds module.
  10. local className = script.Parent.Name -- The script is currently in a folder named "Boxer." I did this to not hardcode my script and simply just copy and paste the script into another class like "Karate" and change the moves around so it is easier for me.
  11. for i, move in keybinds.Moves[className] do
  12.     MoveList[move.Name] = move -- puts all the moves into the MoveList folder so I can simply do MoveList["Jab"] and such
  13. end
  14.  
  15. --Animations
  16. local AnimHandler = require(RS.AnimationHandler) -- Since I don't want to do loadanimation every single time, I do it all once (do it again when the characters respawn, all I need to do is AnimHandler.initialize again)
  17. AnimHandler.initialize() -- initializes/loads all animations
  18.  
  19. local LoadedAnims = AnimHandler.loadedAnimations -- currently loaded animations (basically all of them) so I can just do LoadedAnims.Jab to get the jab itself's animation.
  20.  
  21. --Remotes
  22. local Remotes = RS.Remotes
  23.  
  24. -- ActionNames
  25. local ACTION_JAB = "Jab"
  26. local ACTION_UPPERCUT = "Uppercut"
  27. local ACTION_BLOCK = "Block"
  28.  
  29. --Combo Number
  30. local JabCombo = 0
  31. local UppercutCombo = 0
  32. -- so I use modulus for my jabs to prevent hardcoding. All I do is JabCombo % (current move combo like if it's on move #2) + 1 which I hope as the application reader you understand modulus. BTW I do the + 1 since it will give you 0 if the move is on move 1 soo yeah
  33.  
  34. -- Debounces
  35. local JabDebounce = os.clock()
  36. local UppercutDebounce = os.clock()
  37. local BlockDebounce = os.clock()
  38.  
  39. --VFX Handling
  40. Remotes.VFX.OnClientEvent:Connect(function(character, VFXMove, combo, moveLength)
  41.     if VFXMove == "Jab" then
  42.         attackHandler.JabVFX(character, combo, moveLength)
  43.     elseif VFXMove == "JabSmall" then
  44.         attackHandler.JabVFX(character, combo, moveLength, true)
  45.     elseif VFXMove == "BoxerBlock" then
  46.         attackHandler.BoxerBlockFX(character)
  47.     elseif VFXMove == "BoxerBlockBroken" then
  48.         attackHandler.BoxerBlockBreakFX(character)
  49.     end
  50. end)
  51.  
  52. --Functions
  53. local function Jab(actionName, inputState)
  54.     if plr.Character:GetAttribute("Blocking") then return end
  55.     if actionName ~= "Jab" then return end
  56.     if inputState ~= Enum.UserInputState.Begin then return end
  57.     if JabDebounce > os.clock() then print("The JabDebounce is currently active")return end
  58.     if plr.Character:GetAttribute("Stun") > os.clock() then print("The jab move has failed since the player is stunned due to being attacked by another character") return end
  59.     if plr.Character:GetAttribute("Cooldown") > os.clock() then print("The jab move has failed since the player is currently on cooldown for ANOTHER move") return end -- basically if you are mid-uppercut and lets say the uppercut takes 1 second for its animation, the cooldown will be set to os.clock + 1 and you'll be prevented from commencing a move until the uppercut is over.
  60.     local currentMove = MoveList[actionName] -- MoveList["Jab"] in this case since the actionName is "Jab"
  61.     local currentCombo = JabCombo % #currentMove.SelfCooldown + 1 -- modulus
  62.     plr.Character:SetAttribute("Cooldown", os.clock() + currentMove.GeneralCooldown[currentCombo]) -- sets the cooldown to the GeneralCooldown which is basically the animation length and maybe a little bit more if i decided to make it more. this was explained before, you don't want someone uppercutting for example and then jabbing at the same time while the uppercut animation is still happening because that is two moves as one
  63.     --print(plr:GetAttribute("Cooldown"), "minus", os.clock(), "is", plr:GetAttribute("Cooldown") - os.clock())
  64.     JabDebounce = os.clock() + currentMove.SelfCooldown[currentCombo] -- sets the jab debounce. for example if you uppercut you cant uppercut for another 5 seconds since its too heavy and OP of a move if you were able to do it every 1 second
  65.     local NewCombo = JabCombo % AnimHandler:FindAnims(actionName) + 1 -- finds the current combo and updates JabCombo. since jabcombo is probably like 1293 after like 10 mins of play time, I cant just do newcombo = jabcombo, I need to find the modulus.
  66.     JabCombo += 1 -- for example 100 ---> 101
  67.     local currentAnim = LoadedAnims[className][actionName..tostring(NewCombo)] -- finds the current animation. in this case it is LoadedAnims["Boxer"]["Jab1"] or it can be jab2 since you can jab with 2 arms. the "combo" here is more like a "which hand to punch with next in line"
  68.     Remotes:FindFirstChild(actionName):FireServer(currentCombo, currentMove.Length[currentCombo]) -- fires server so the damaging and stuff could happen
  69.     currentAnim:Play()
  70. end
  71.  
  72. local function Uppercut(actionName, inputState) -- this is all pretty much explained since i explained the Jab function. if you dont understand something go to the jab since i basically copy and pasted it
  73.     if plr.Character:GetAttribute("Blocking") then return end
  74.     if actionName ~= "Uppercut" then return end
  75.     if inputState ~= Enum.UserInputState.Begin then return end
  76.     if UppercutDebounce > os.clock() then print("There is currently an uppercut debounce")return end
  77.     if plr.Character:GetAttribute("Stun") > os.clock() then print("Uppercut failed due to the player being in a stun") return end
  78.     if plr.Character:GetAttribute("Cooldown") > os.clock() then print("Uppercut failed because the player is doing another move already") return end
  79.     local currentMove = MoveList[actionName]
  80.     local currentCombo = UppercutCombo % #currentMove.SelfCooldown + 1
  81.     plr.Character:SetAttribute("Cooldown", os.clock() + currentMove.GeneralCooldown[currentCombo])
  82.     --print(plr:GetAttribute("Cooldown"), "minus", os.clock(), "is", plr:GetAttribute("Cooldown") - os.clock())
  83.     UppercutDebounce = os.clock() + currentMove.SelfCooldown[currentCombo]
  84.     local NewCombo = UppercutCombo % AnimHandler:FindAnims(actionName) + 1
  85.     UppercutCombo += 1
  86.     local currentAnim = LoadedAnims[className][actionName]
  87.     Remotes:FindFirstChild(actionName):FireServer(currentCombo, currentMove.Length[currentCombo])
  88.     currentAnim:Play()
  89. end
  90.  
  91. local function Block(actionName, inputState) -- this is the block now. if its userInputState.begin you began holding down block so you start blocking, and if you let go of the keybind to block itll stop blocking
  92.     if actionName ~= "Block" then return end
  93.     if inputState == Enum.UserInputState.Begin then
  94.         if BlockDebounce > os.clock() then return end
  95.         if plr.Character:GetAttribute("Stun") > os.clock() then return end
  96.         if plr.Character:GetAttribute("Cooldown") > os.clock() then return end
  97.        
  98.         local currentMove = MoveList[actionName]
  99.         local currentCombo = 1 % #currentMove.SelfCooldown + 1
  100.         plr.Character:SetAttribute("Cooldown", os.clock() + currentMove.GeneralCooldown[currentCombo])
  101.         BlockDebounce = os.clock() + currentMove.SelfCooldown[currentCombo]
  102.         local Block = LoadedAnims[className].Block
  103.         Block:Play()
  104.         Remotes.Block:FireServer(true)
  105.     elseif inputState ==  Enum.UserInputState.End then
  106.         local Block = LoadedAnims[className].Block
  107.         plr.Character:SetAttribute("Blocking", false)
  108.         Remotes.Block:FireServer(false)
  109.         Block:Stop()
  110.     end
  111. end
  112.  
  113. Remotes.BlockBroken.OnClientEvent:Connect(function() -- cant spam block so i have to have a blockbroken event that ends your blocking and puts you in a stun
  114.     local Block = LoadedAnims[className].Block
  115.     plr.Character:SetAttribute("Blocking", false)
  116.     Remotes.Block:FireServer(false)
  117.     Block:Stop()
  118. end)
  119.  
  120. task.spawn(function()
  121.     while task.wait(1) do -- since you can change keybinds every second i re initialize the keybinds in CAS
  122.         CAS:UnbindAction(ACTION_JAB)
  123.         CAS:BindAction(ACTION_JAB, Jab, true, unpack(MoveList.Jab.Keybind))
  124.        
  125.         CAS:UnbindAction(ACTION_UPPERCUT)
  126.         CAS:BindAction(ACTION_UPPERCUT, Uppercut, true, unpack(MoveList.Uppercut.Keybind))
  127.        
  128.         CAS:UnbindAction(ACTION_BLOCK)
  129.         CAS:BindAction(ACTION_BLOCK, Block, true, unpack(MoveList.Block.Keybind))
  130.     end
  131. end)
  132.  
  133. plr.CharacterAdded:Connect(function()
  134.     AnimHandler.initialize()
  135.     LoadedAnims = AnimHandler.loadedAnimations -- you can see that I re initialize the animations that are currently loaded because the old character is dead and the animations are deleted for that one
  136. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement