Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local RS = game.ReplicatedStorage
- local CAS = game:GetService("ContextActionService")
- local players = game:GetService("Players")
- local plr = players.LocalPlayer
- 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.
- 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.
- -- Moves
- 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.
- 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.
- for i, move in keybinds.Moves[className] do
- MoveList[move.Name] = move -- puts all the moves into the MoveList folder so I can simply do MoveList["Jab"] and such
- end
- --Animations
- 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)
- AnimHandler.initialize() -- initializes/loads all animations
- 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.
- --Remotes
- local Remotes = RS.Remotes
- -- ActionNames
- local ACTION_JAB = "Jab"
- local ACTION_UPPERCUT = "Uppercut"
- local ACTION_BLOCK = "Block"
- --Combo Number
- local JabCombo = 0
- local UppercutCombo = 0
- -- 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
- -- Debounces
- local JabDebounce = os.clock()
- local UppercutDebounce = os.clock()
- local BlockDebounce = os.clock()
- --VFX Handling
- Remotes.VFX.OnClientEvent:Connect(function(character, VFXMove, combo, moveLength)
- if VFXMove == "Jab" then
- attackHandler.JabVFX(character, combo, moveLength)
- elseif VFXMove == "JabSmall" then
- attackHandler.JabVFX(character, combo, moveLength, true)
- elseif VFXMove == "BoxerBlock" then
- attackHandler.BoxerBlockFX(character)
- elseif VFXMove == "BoxerBlockBroken" then
- attackHandler.BoxerBlockBreakFX(character)
- end
- end)
- --Functions
- local function Jab(actionName, inputState)
- if plr.Character:GetAttribute("Blocking") then return end
- if actionName ~= "Jab" then return end
- if inputState ~= Enum.UserInputState.Begin then return end
- if JabDebounce > os.clock() then print("The JabDebounce is currently active")return end
- 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
- 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.
- local currentMove = MoveList[actionName] -- MoveList["Jab"] in this case since the actionName is "Jab"
- local currentCombo = JabCombo % #currentMove.SelfCooldown + 1 -- modulus
- 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
- --print(plr:GetAttribute("Cooldown"), "minus", os.clock(), "is", plr:GetAttribute("Cooldown") - os.clock())
- 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
- 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.
- JabCombo += 1 -- for example 100 ---> 101
- 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"
- Remotes:FindFirstChild(actionName):FireServer(currentCombo, currentMove.Length[currentCombo]) -- fires server so the damaging and stuff could happen
- currentAnim:Play()
- end
- 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
- if plr.Character:GetAttribute("Blocking") then return end
- if actionName ~= "Uppercut" then return end
- if inputState ~= Enum.UserInputState.Begin then return end
- if UppercutDebounce > os.clock() then print("There is currently an uppercut debounce")return end
- if plr.Character:GetAttribute("Stun") > os.clock() then print("Uppercut failed due to the player being in a stun") return end
- if plr.Character:GetAttribute("Cooldown") > os.clock() then print("Uppercut failed because the player is doing another move already") return end
- local currentMove = MoveList[actionName]
- local currentCombo = UppercutCombo % #currentMove.SelfCooldown + 1
- plr.Character:SetAttribute("Cooldown", os.clock() + currentMove.GeneralCooldown[currentCombo])
- --print(plr:GetAttribute("Cooldown"), "minus", os.clock(), "is", plr:GetAttribute("Cooldown") - os.clock())
- UppercutDebounce = os.clock() + currentMove.SelfCooldown[currentCombo]
- local NewCombo = UppercutCombo % AnimHandler:FindAnims(actionName) + 1
- UppercutCombo += 1
- local currentAnim = LoadedAnims[className][actionName]
- Remotes:FindFirstChild(actionName):FireServer(currentCombo, currentMove.Length[currentCombo])
- currentAnim:Play()
- end
- 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
- if actionName ~= "Block" then return end
- if inputState == Enum.UserInputState.Begin then
- if BlockDebounce > os.clock() then return end
- if plr.Character:GetAttribute("Stun") > os.clock() then return end
- if plr.Character:GetAttribute("Cooldown") > os.clock() then return end
- local currentMove = MoveList[actionName]
- local currentCombo = 1 % #currentMove.SelfCooldown + 1
- plr.Character:SetAttribute("Cooldown", os.clock() + currentMove.GeneralCooldown[currentCombo])
- BlockDebounce = os.clock() + currentMove.SelfCooldown[currentCombo]
- local Block = LoadedAnims[className].Block
- Block:Play()
- Remotes.Block:FireServer(true)
- elseif inputState == Enum.UserInputState.End then
- local Block = LoadedAnims[className].Block
- plr.Character:SetAttribute("Blocking", false)
- Remotes.Block:FireServer(false)
- Block:Stop()
- end
- end
- 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
- local Block = LoadedAnims[className].Block
- plr.Character:SetAttribute("Blocking", false)
- Remotes.Block:FireServer(false)
- Block:Stop()
- end)
- task.spawn(function()
- while task.wait(1) do -- since you can change keybinds every second i re initialize the keybinds in CAS
- CAS:UnbindAction(ACTION_JAB)
- CAS:BindAction(ACTION_JAB, Jab, true, unpack(MoveList.Jab.Keybind))
- CAS:UnbindAction(ACTION_UPPERCUT)
- CAS:BindAction(ACTION_UPPERCUT, Uppercut, true, unpack(MoveList.Uppercut.Keybind))
- CAS:UnbindAction(ACTION_BLOCK)
- CAS:BindAction(ACTION_BLOCK, Block, true, unpack(MoveList.Block.Keybind))
- end
- end)
- plr.CharacterAdded:Connect(function()
- AnimHandler.initialize()
- 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
- end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement