Advertisement
Ultimate_69

FightModule

May 21st, 2025 (edited)
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.01 KB | None | 0 0
  1. local FightModule = {}
  2.  
  3. -- SERVICES
  4. local RunService = game:GetService("RunService")
  5. local ReplicatedStorage = game:GetService("ReplicatedStorage").ReplicatedStoragePackage
  6. local ServerScriptService = game:GetService("ServerScriptService").ServerScriptServicePackage
  7. local TweenService = game:GetService("TweenService")
  8. local SoundService = game:GetService("SoundService")
  9. local PlayerService = game:GetService("Players")
  10. local ServerStorage = game:GetService("ServerStorage").ServerStoragePackage
  11.  
  12. -- MODULES
  13. local Types = require(ReplicatedStorage.Modules.Types)
  14. local FighterDetails = require(ServerScriptService.Parent.FighterDetails)
  15. local PlayerStats = require(ServerScriptService.Modules.PlayerStats)
  16. local AbilityModule = require(script.AbilityModule)
  17. local Utilities = require(ServerScriptService.Modules.Utilities)
  18. local CustomEnum = require(ReplicatedStorage.Modules.CustomEnum)
  19. local FighterMethods = require(ServerScriptService.Modules.FighterMethods)
  20.  
  21. local attackGuiUpdater = ReplicatedStorage.Remotes.AttackGuiUpdater
  22. local getTurnInfo = ServerStorage.Bindables.GetTurnInfo
  23. local highlightRemote = ReplicatedStorage.Remotes.HighlightRemote
  24.  
  25. local fightPart: Part = workspace.FightPart -- part where the center of the fight is
  26. local turn: number = 1
  27. local playedTurns: number = 1
  28. local players: {number} = {} -- includes singleplayer NPCs
  29. local globalFighters: {Types.Fighter} = {}
  30. local attackTweenInfo = TweenInfo.new(1)
  31.  
  32. getTurnInfo.OnInvoke = function()
  33.     return players, playedTurns
  34. end
  35.  
  36. local function GetPlayerFighters(fightersTable: {Types.Fighter}, userId: number)
  37.     local fighters = {}
  38.     for i,v in fightersTable do
  39.         if v.userId == userId then
  40.             table.insert(fighters, v)
  41.         end
  42.     end
  43.     return fighters
  44. end
  45.  
  46. local function IsFighterInTable(tableOfInstances: {Instance}, fighterName: string)
  47.     for i,v in tableOfInstances do
  48.         if v.Name == fighterName then
  49.             return true
  50.         end
  51.     end
  52.     return false
  53. end
  54.  
  55. -- Checks if a fighter is within the fighters folder
  56. local function CheckFighterValidity(fighter: Types.Fighter)
  57.     local normalFightersFolders = ReplicatedStorage.Fighters:GetChildren()
  58.    
  59.     for i,v in normalFightersFolders do
  60.         if not IsFighterInTable(v:GetChildren(), FighterDetails[fighter.id].Information.Name) then
  61.             continue
  62.         end
  63.         return true
  64.     end
  65.    
  66.     if RunService:IsStudio() then
  67.         local devFighters = ReplicatedStorage.Fighters.Dev:GetChildren()
  68.         if not IsFighterInTable(devFighters, FighterDetails[fighter.id].Information.Name) then
  69.             return false
  70.         end
  71.         return true
  72.     end
  73.    
  74.     return false   
  75. end
  76.  
  77. local function PlaceFighter(fighter: Types.Fighter, newPosition: CFrame, userId: number)
  78.     fighter.model.Parent = workspace
  79.     fighter.model:PivotTo(workspace.FightPart.CFrame * newPosition)
  80.    
  81.     local detector = ServerStorage.Misc.AssignFighterDetector:Clone()
  82.     detector.UserId.Value = userId
  83.     detector.Parent = fighter.model
  84. end
  85.  
  86. -- fighter must be in global fighters array. FilterId is optional,
  87. -- but prevents duplicate fighter for enemy being flagged instead
  88. local function GetFighterFromModel(fighterModel: Types.Character, filterId: number) : Types.Fighter
  89.     if not filterId then
  90.         for i,v: Types.Fighter in globalFighters do
  91.             if v.model == fighterModel then
  92.                 return v
  93.             end
  94.         end
  95.     else
  96.         for i,v: Types.Fighter in globalFighters do
  97.             local detector = fighterModel.AssignFighterDetector
  98.             local userId = detector.UserId.Value
  99.            
  100.             if v.model == fighterModel and v.model.AssignFighterDetector.UserId.Value == userId then
  101.                 return v
  102.             end
  103.         end
  104.     end
  105.     return nil
  106. end
  107.  
  108. local function ResetFighterAtTurnStart(fighter: Types.Fighter)
  109.     if fighter.model.Humanoid.Health <= 0 then
  110.         for i,v in fighter.model.Humanoid.Animator:GetPlayingAnimationTracks() do
  111.             v:Stop()
  112.         end
  113.         Utilities.LoadAnimationOfFighter(fighter.model, FighterDetails[fighter.id].Animations, "Dead"):Play()
  114.     end
  115.  
  116.     if fighter.abilityExpiry then
  117.         if fighter.abilityExpiry > 0 then
  118.             fighter.abilityExpiry -= 1
  119.         else
  120.             fighter.abilityExpiry = 0
  121.             AbilityModule.StopAbility(fighter.ability, fighter)
  122.         end
  123.     end
  124.  
  125.     if fighter.isBlocking then
  126.         fighter.isBlocking = false
  127.         for i,v in fighter.model.Humanoid.Animator:GetPlayingAnimationTracks() do
  128.             if v.Name == "Block" then
  129.                 v:Stop()
  130.             end
  131.         end
  132.         Utilities.LoadAnimationOfFighter(fighter.model, FighterDetails[fighter.id].Animations, "Idle"):Play()
  133.     end
  134. end
  135.  
  136. local function NextTurn()
  137.     turn += 1
  138.     for i,v: Types.Fighter in globalFighters do
  139.         if v.model.Humanoid.Health > 0 then
  140.             -- prevent dead people from coming back to life every turn
  141.             FighterMethods.GiveHealth(v, 5) -- regen every turn
  142.             if v.model.Humanoid.Health > FighterDetails[v.id].Information.MaxHealth then
  143.                 FighterMethods.SetHealth(v, FighterDetails[v.id].Information.MaxHealth)
  144.             end
  145.         end
  146.     end
  147.     if #players > playedTurns then
  148.         playedTurns += 1 -- current turn is players[2] if the previous turn was players[1]
  149.     elseif #players == playedTurns then
  150.         playedTurns = 1 -- reset turns back
  151.     end
  152.     attackGuiUpdater:FireAllClients(players, playedTurns, turn)
  153.    
  154.     if players[playedTurns] == 0 then
  155.         FightModule.EnemyAITurn()
  156.     else
  157.         for i,fighter: Types.Fighter in globalFighters do
  158.             if fighter.userId == players[playedTurns] then
  159.                 ResetFighterAtTurnStart(fighter)
  160.             end
  161.         end
  162.     end
  163. end
  164.  
  165. -- handles checks to see if fighter is alive too
  166. local function GetRandomFighter(aiFighters: {Types.Fighter}): Types.Fighter?
  167.     local randomNum = math.random(1, #aiFighters)
  168.     local opponentFighter = aiFighters[randomNum]
  169.  
  170.     if opponentFighter.model.Humanoid.Health <= 0 then
  171.         table.remove(aiFighters, randomNum)
  172.         if #aiFighters == 0 then
  173.             return nil -- all fighters are dead
  174.         end
  175.         return GetRandomFighter(aiFighters)
  176.     end
  177.  
  178.     return opponentFighter
  179. end
  180.  
  181. local function PlaceFighterGroup(fighterGroup: {Types.Fighter}, leftSide: boolean, userId: number)
  182.     local amount = #fighterGroup
  183.     local multiplier = 1
  184.    
  185.     if leftSide then
  186.         multiplier = -1
  187.     end
  188.    
  189.     if amount == 2 then
  190.         PlaceFighter(fighterGroup[1], CFrame.new(10 * multiplier, 2.5, -10), userId)
  191.         PlaceFighter(fighterGroup[2], CFrame.new(10 * multiplier, 2.5, -18), userId)
  192.     elseif amount == 3 then
  193.         PlaceFighter(fighterGroup[1], CFrame.new(7 * multiplier, 2.5, -14), userId)
  194.         PlaceFighter(fighterGroup[2], CFrame.new(10 * multiplier, 2.5, -18), userId)
  195.         PlaceFighter(fighterGroup[3], CFrame.new(10 * multiplier, 2.5, -10), userId)
  196.     elseif amount == 4 then
  197.         PlaceFighter(fighterGroup[1], CFrame.new(10 * multiplier, 2.5, -10), userId)
  198.         PlaceFighter(fighterGroup[2], CFrame.new(10 * multiplier, 2.5, -18), userId)
  199.         PlaceFighter(fighterGroup[3], CFrame.new(16 * multiplier, 2.5, -10), userId)       
  200.         PlaceFighter(fighterGroup[4], CFrame.new(16 * multiplier, 2.5, -18), userId)
  201.     end
  202. end
  203.  
  204. function FightModule.SkipTurn()
  205.     NextTurn()
  206. end
  207.  
  208. function FightModule.AssignFighter(player: Player, userId: number, fighterModel: Types.Character)
  209.     if userId == player.UserId then
  210.         -- switch player fighter
  211.         PlayerStats[player.UserId].fighter = GetFighterFromModel(fighterModel, userId)
  212.        
  213.         for i,v: Types.Fighter in globalFighters do
  214.             if v.userId == player.UserId then
  215.                 highlightRemote:FireClient(player, v.model, nil, false)
  216.                 highlightRemote:FireClient(player, v.model, nil, false, true)
  217.             end
  218.         end
  219.         highlightRemote:FireClient(player, fighterModel, Color3.new(0, 0.4, 1), true, true)
  220.     else
  221.         -- switch opponent fighter
  222.         PlayerStats[player.UserId].opponent = GetFighterFromModel(fighterModel, userId)
  223.        
  224.         for i,v: Types.Fighter in globalFighters do
  225.             if v.userId ~= player.UserId then
  226.                 highlightRemote:FireClient(player, v.model, nil, false)
  227.                 highlightRemote:FireClient(player, v.model, nil, false, true)
  228.             end
  229.         end
  230.         highlightRemote:FireClient(player, fighterModel, Color3.new(1, 0, 0.0156863), true, true)
  231.     end
  232. end
  233.  
  234. function FightModule.StartPartyFight(player1: Player, player2: Player, fighters: {Types.Fighter})
  235.     if #fighters <= 2 then return end -- literally just a normal 1v1
  236.  
  237.     -- make sure fighters are valid
  238.     local valid = true
  239.    
  240.     for i,v in fighters do
  241.         if not CheckFighterValidity(v) then valid = false end
  242.     end
  243.    
  244.     if not valid then return end
  245.    
  246.     if player2 == nil then
  247.         -- SINGLEPLAYER
  248.         local p1char: Types.Character = player1.Character
  249.         p1char.HumanoidRootPart.Anchored = true
  250.        
  251.         table.insert(players, 1, player1.UserId)
  252.         table.insert(players, 2, 0)
  253.        
  254.         for i,v in fighters do
  255.             table.insert(globalFighters, i, v)
  256.         end
  257.  
  258.         task.delay(1, function()
  259.             highlightRemote:FireClient(player1, fighters[1].model, Color3.new(0, 0.4, 1), true, true)
  260.             for i,v in fighters do
  261.                 if v.userId ~= player1.UserId then
  262.                     highlightRemote:FireClient(player1, v.model, Color3.new(1, 0, 0.0156863), true, true)
  263.                     break
  264.                 end
  265.             end
  266.             -- choose first opponent found as main opponent
  267.         end)
  268.  
  269.         player1.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  270.  
  271.         for i,v in fighters do
  272.             v.model.Humanoid.MaxHealth = FighterDetails[v.id].Information.MaxHealth
  273.             v.model.Humanoid.Health = FighterDetails[v.id].Information.MaxHealth
  274.         end
  275.  
  276.         for i,v in fighters do
  277.             local gui = ReplicatedStorage.Prefabs.CharacterGui:Clone()
  278.             gui.Holder.BarBackground.BarForeground.CharacterName.Text = FighterDetails[v.id].Information.Name
  279.             gui.Parent = v.model.Head
  280.         end
  281.        
  282.         local playerFighters = {}
  283.         local opponentFighters = {}
  284.  
  285.         for i,v in fighters do
  286.             if v.userId == player1.UserId then
  287.                 table.insert(playerFighters, v)
  288.             else
  289.                 table.insert(opponentFighters, v)
  290.             end
  291.         end
  292.        
  293.         PlaceFighterGroup(playerFighters, true, player1.UserId)
  294.         PlaceFighterGroup(opponentFighters, false, 0)
  295.        
  296.        
  297.         for i,v in fighters do
  298.             if v.userId == player1.UserId then
  299.                 v.model.PrimaryPart.CFrame *= CFrame.Angles(0, 80, 0)
  300.             else
  301.                 v.model.PrimaryPart.CFrame *= CFrame.Angles(0, -80, 0)
  302.             end
  303.         end
  304.        
  305.         for i,v in fighters do
  306.             Utilities.CreateAnimator(v.model)
  307.         end
  308.  
  309.         for i,v in fighters do
  310.             Utilities.LoadAnimationOfFighter(v.model, FighterDetails[v.id].Animations, "Idle"):Play()
  311.         end
  312.  
  313.         attackGuiUpdater:FireAllClients(players, playedTurns, turn)
  314.     else
  315.         -- Multiplayer
  316.         local p1char: Types.Character = player1.Character
  317.         p1char.HumanoidRootPart.Anchored = true
  318.        
  319.         local p2char: Types.Character = player2.Character
  320.         p2char.HumanoidRootPart.Anchored = true
  321.        
  322.         table.insert(players, 1, player1.UserId)
  323.         table.insert(players, 2, player2.UserId)
  324.  
  325.         for i,v in fighters do
  326.             table.insert(globalFighters, i, v)
  327.         end
  328.  
  329.         task.delay(1, function()
  330.             for i = 1, 2 do
  331.                 -- should probably make this a function
  332.                 if i == 1 then
  333.                     highlightRemote:FireClient(player1, GetPlayerFighters(globalFighters, players[i])[1].model, Color3.new(0, 0.4, 1), true, true)
  334.                     for i,v in fighters do
  335.                         if v.userId ~= player1.UserId then
  336.                             highlightRemote:FireClient(player1, v.model, Color3.new(1, 0, 0.0156863), true, true)
  337.                             break
  338.                         end
  339.                     end
  340.                 else
  341.                     highlightRemote:FireClient(player2, GetPlayerFighters(globalFighters, players[i])[1].model, Color3.new(0, 0.4, 1), true, true)
  342.                     for i,v in fighters do
  343.                         if v.userId ~= player2.UserId then
  344.                             highlightRemote:FireClient(player2, v.model, Color3.new(1, 0, 0.0156863), true, true)
  345.                             break
  346.                         end
  347.                     end
  348.                 end
  349.             end
  350.             -- chooses first opponent found as main opponent, and first fighter as main fighter.
  351.             -- well not really that's already done it just highlights them
  352.         end)
  353.  
  354.         player1.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  355.         player2.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  356.  
  357.         for i,v in fighters do
  358.             v.model.Humanoid.MaxHealth = FighterDetails[v.id].Information.MaxHealth
  359.             v.model.Humanoid.Health = FighterDetails[v.id].Information.MaxHealth
  360.         end
  361.  
  362.         for i,v in fighters do
  363.             local gui = ReplicatedStorage.Prefabs.CharacterGui:Clone()
  364.             gui.Holder.BarBackground.BarForeground.CharacterName.Text = FighterDetails[v.id].Information.Name
  365.             gui.Parent = v.model.Head
  366.         end
  367.  
  368.         local playerFighters = {}
  369.         local opponentFighters = {}
  370.  
  371.         for i,v in fighters do
  372.             if v.userId == player1.UserId then
  373.                 table.insert(playerFighters, v)
  374.             else
  375.                 table.insert(opponentFighters, v)
  376.             end
  377.         end
  378.  
  379.         PlaceFighterGroup(playerFighters, true, player1.UserId)
  380.         PlaceFighterGroup(opponentFighters, false, player2.UserId)
  381.  
  382.  
  383.         for i,v in fighters do
  384.             if v.userId == player1.UserId then
  385.                 v.model.PrimaryPart.CFrame *= CFrame.Angles(0, 80, 0)
  386.             else
  387.                 v.model.PrimaryPart.CFrame *= CFrame.Angles(0, -80, 0)
  388.             end
  389.         end
  390.  
  391.         for i,v in fighters do
  392.             Utilities.CreateAnimator(v.model)
  393.         end
  394.  
  395.         for i,v in fighters do
  396.             Utilities.LoadAnimationOfFighter(v.model, FighterDetails[v.id].Animations, "Idle"):Play()
  397.         end
  398.  
  399.         attackGuiUpdater:FireAllClients(players, playedTurns, turn)
  400.     end
  401. end
  402.  
  403. function FightModule.StartOneOnOne(player1: Player, player2: Player, fighters: {Types.Fighter})
  404.     if #fighters ~= 2 then return end -- only player 1 and player 2's fighters allowed
  405.    
  406.     -- make sure fighters are valid
  407.     if not CheckFighterValidity(fighters[1]) then return end
  408.     if not CheckFighterValidity(fighters[2]) then return end
  409.    
  410.     if player2 == nil then
  411.         -- SINGLEPLAYER
  412.         local p1char: Types.Character = player1.Character
  413.         p1char.HumanoidRootPart.Anchored = true
  414.        
  415.         table.insert(players, 1, player1.UserId)
  416.         table.insert(players, 2, 0)
  417.        
  418.         table.insert(globalFighters, 1, fighters[1])
  419.         table.insert(globalFighters, 2, fighters[2])
  420.        
  421.         task.delay(1, function()
  422.             highlightRemote:FireClient(player1, fighters[1].model, Color3.new(0, 0.4, 1), true, true)
  423.             highlightRemote:FireClient(player1, fighters[2].model, Color3.new(1, 0, 0.0156863), true, true)
  424.         end)
  425.        
  426.        
  427.         player1.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  428.        
  429.         for i = 1, 2 do
  430.             fighters[i].model.Humanoid.MaxHealth = FighterDetails[fighters[i].id].Information.MaxHealth
  431.             fighters[i].model.Humanoid.Health = FighterDetails[fighters[i].id].Information.MaxHealth
  432.         end
  433.        
  434.         for i = 1, 2 do
  435.             local gui = ReplicatedStorage.Prefabs.CharacterGui:Clone()
  436.             gui.Holder.BarBackground.BarForeground.CharacterName.Text = FighterDetails[fighters[i].id].Information.Name
  437.             gui.Parent = fighters[i].model.Head
  438.         end
  439.  
  440.         PlaceFighter(fighters[1], CFrame.new(-10, 2.5, -10), player1.UserId) -- left
  441.         PlaceFighter(fighters[2], CFrame.new(10, 2.5, -10), 0) -- right
  442.        
  443.  
  444.         fighters[1].model.PrimaryPart.CFrame = CFrame.lookAt(fighters[1].model.PrimaryPart.Position, fighters[2].model.PrimaryPart.Position)
  445.         fighters[2].model.PrimaryPart.CFrame = CFrame.lookAt(fighters[2].model.PrimaryPart.Position, fighters[1].model.PrimaryPart.Position)
  446.        
  447.         for i = 1, 2 do
  448.             Utilities.CreateAnimator(fighters[i].model)
  449.         end
  450.        
  451.                
  452.         Utilities.LoadAnimationOfFighter(fighters[1].model, FighterDetails[fighters[1].id].Animations, "Idle"):Play()
  453.         Utilities.LoadAnimationOfFighter(fighters[2].model, FighterDetails[fighters[2].id].Animations, "Idle"):Play()
  454.        
  455.         attackGuiUpdater:FireAllClients(players, playedTurns, turn)
  456.     else
  457.         -- 2 PLAYERS
  458.         local p1char: Types.Character = player1.Character
  459.         p1char.HumanoidRootPart.Anchored = true
  460.  
  461.         local p2char: Types.Character = player2.Character
  462.         p2char.HumanoidRootPart.Anchored = true
  463.        
  464.         table.insert(players, 1, player1.UserId)
  465.         table.insert(players, 2, player2.UserId)
  466.  
  467.         table.insert(globalFighters, 1, fighters[1])
  468.         table.insert(globalFighters, 2, fighters[2])
  469.        
  470.         task.delay(2, function()
  471.             highlightRemote:FireClient(player1, fighters[1].model, Color3.new(0, 0.4, 1), true, true)
  472.             highlightRemote:FireClient(player1, fighters[2].model, Color3.new(1, 0, 0.0156863), true, true)
  473.  
  474.             highlightRemote:FireClient(player2, fighters[2].model, Color3.new(0, 0.4, 1), true, true)
  475.             highlightRemote:FireClient(player2, fighters[1].model, Color3.new(1, 0, 0.0156863), true, true)
  476.         end)
  477.  
  478.         player1.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  479.         player2.PlayerGui.StarterGuiPackage.AttackGui.Enabled = true
  480.        
  481.         for i = 1, 2 do
  482.             fighters[i].model.Humanoid.MaxHealth = FighterDetails[fighters[i].id].Information.MaxHealth
  483.             fighters[i].model.Humanoid.Health = FighterDetails[fighters[i].id].Information.MaxHealth
  484.         end
  485.  
  486.         for i = 1, 2 do
  487.             local gui = ReplicatedStorage.Prefabs.CharacterGui:Clone()
  488.             gui.Holder.BarBackground.BarForeground.CharacterName.Text = FighterDetails[fighters[i].id].Information.Name
  489.             gui.Parent = fighters[i].model.Head
  490.         end
  491.  
  492.         PlaceFighter(fighters[1], CFrame.new(-10, 2.5, -10), player1.UserId) -- left
  493.         PlaceFighter(fighters[2], CFrame.new(10, 2.5, -10), player2.UserId) -- right
  494.  
  495.         fighters[1].model.PrimaryPart.CFrame = CFrame.lookAt(fighters[1].model.PrimaryPart.Position, fighters[2].model.PrimaryPart.Position)
  496.         fighters[2].model.PrimaryPart.CFrame = CFrame.lookAt(fighters[2].model.PrimaryPart.Position, fighters[1].model.PrimaryPart.Position)
  497.        
  498.        
  499.         for i = 1, 2 do
  500.             Utilities.CreateAnimator(fighters[i].model)
  501.         end
  502.  
  503.         Utilities.LoadAnimationOfFighter(fighters[1].model, FighterDetails[fighters[1].id].Animations, "Idle"):Play()
  504.         Utilities.LoadAnimationOfFighter(fighters[2].model, FighterDetails[fighters[2].id].Animations, "Idle"):Play()
  505.        
  506.         attackGuiUpdater:FireAllClients(players, playedTurns, turn)
  507.     end
  508. end
  509.  
  510. local function Attack(attacker: Types.Fighter, victim: Types.Fighter)
  511.     if attacker.ability and
  512.         (AbilityModule.IsAbilityType(attacker.ability, CustomEnum.AbilityType.Attack) or
  513.             AbilityModule.IsAbilityType(attacker.ability, CustomEnum.AbilityType.Cutscene)) then
  514.         for i,v in victim.model.Humanoid.Animator:GetPlayingAnimationTracks() do
  515.             if v.Name ~= "Block" then continue end
  516.             v:Stop()
  517.             local newAnim = Utilities.LoadAnimationOfFighter(victim.model, FighterDetails[victim.id].Animations, "Idle")
  518.             newAnim:Play()
  519.         end
  520.         AbilityModule.ActivateAbility(attacker.ability, attacker, victim)
  521.         return
  522.     end
  523.    
  524.     local damage = 30
  525.     local oldCFrame = attacker.model.PrimaryPart.CFrame
  526.    
  527.     if attacker.damageBoost and attacker.damageBoost > 0 then
  528.         damage *= attacker.damageBoost
  529.     end
  530.    
  531.     local offset = Vector3.new(-4, 0, 0)
  532.     local endPosition = {
  533.         Position = victim.model.PrimaryPart.Position + victim.model.PrimaryPart.CFrame.LookVector * 4
  534.     }
  535.  
  536.     -- preloading animations to avoid delay
  537.     local damageAnimation = Utilities.LoadAnimationOfFighter(victim.model, FighterDetails[victim.id].Animations, "Damage")
  538.     local moveAnimation = Utilities.LoadAnimationOfFighter(attacker.model, FighterDetails[attacker.id].Animations, "Move")
  539.     local attackAnimation = Utilities.LoadAnimationOfFighter(attacker.model, FighterDetails[attacker.id].Animations, "Attack")
  540.  
  541.     moveAnimation:Play()
  542.    
  543.     local tween = TweenService:Create(attacker.model.PrimaryPart, attackTweenInfo, endPosition)
  544.     tween:Play()
  545.     tween.Completed:Wait()
  546.     moveAnimation:Stop()
  547.  
  548.     Utilities.CreateAnimator(attacker.model)
  549.     Utilities.CreateAnimator(victim.model)
  550.  
  551.     attackAnimation:Play()
  552.    
  553.     repeat
  554.         task.wait()
  555.     until attackAnimation.Length > 0
  556.  
  557.     local connection = attackAnimation:GetMarkerReachedSignal("Hit"):Connect(function()
  558.         if not victim.isBlocking then
  559.             local sound = SoundService.HitSFX.Hit2:Clone()
  560.             sound.Parent = victim.model
  561.             sound:Destroy()
  562.             local vfx = ReplicatedStorage.VFX.Hit.HitVFX:Clone()
  563.             vfx.Parent = victim.model
  564.             vfx.smack.Anchored = true
  565.             vfx.smack.CFrame = victim.model.HumanoidRootPart.CFrame
  566.             game.Debris:AddItem(vfx, 0.4)
  567.             damageAnimation:Play()
  568.         else
  569.             if victim.model.Humanoid.Health > damage * 0.5 then
  570.                 local sound = SoundService.HitSFX.Block:Clone()
  571.                 sound.Parent = victim.model
  572.                 sound:Destroy()
  573.             else
  574.                 local sound = SoundService.HitSFX.Hit2:Clone()
  575.                 sound.Parent = victim.model
  576.                 sound:Destroy()
  577.             end
  578.         end
  579.     end)
  580.    
  581.     task.wait(attackAnimation.Length)
  582.    
  583.     connection:Disconnect()
  584.    
  585.     FighterMethods.TakeDamage(victim, damage, 0.5, attackGuiUpdater)
  586.  
  587.     task.wait(0.5)
  588.    
  589.     moveAnimation:Play()
  590.     local endPosition = {CFrame = oldCFrame}
  591.     local endTween = TweenService:Create(attacker.model.PrimaryPart, attackTweenInfo, endPosition)
  592.     endTween:Play()
  593.     endTween.Completed:Wait()
  594.     moveAnimation:Stop()
  595. end
  596.  
  597. function FightModule.Attack(player: Player, fighter: Types.Fighter)
  598.     if players[playedTurns] ~= player.UserId then return end -- not the player's turn
  599.     if fighter.isAttacking then return end -- player is doing attack
  600.     if fighter.isBlocking then return end -- player is blocking
  601.    
  602.    
  603.     fighter.isAttacking = true
  604.     Attack(fighter, PlayerStats[player.UserId].opponent)
  605.     NextTurn()
  606.     fighter.isAttacking = false
  607. end
  608.  
  609. function FightModule.Ability(player: Player, fighter: Types.Fighter, ability: number)
  610.     if players[playedTurns] ~= player.UserId then return end -- not the player's turn
  611.     if fighter.isAttacking then return end -- player is doing attack
  612.     if fighter.isBlocking then return end -- player is blocking
  613.    
  614.     local result
  615.    
  616.     if fighter.transformed then
  617.         result = AbilityModule.UseAbility(FighterDetails[fighter.id].AbilitiesTransformed[ability], fighter)
  618.     else
  619.         result = AbilityModule.UseAbility(FighterDetails[fighter.id].Abilities[ability], fighter)
  620.     end
  621.    
  622.     if result ~= false and player.UserId ~= 0 then
  623.         NextTurn()
  624.     end
  625.    
  626. end
  627.  
  628. local function Defend(fighter: Types.Fighter)
  629.     local anim: AnimationTrack = Utilities.LoadAnimationOfFighter(fighter.model, FighterDetails[fighter.id].Animations, "Block")
  630.  
  631.     for i,v: AnimationTrack in fighter.model.Humanoid.Animator:GetPlayingAnimationTracks() do
  632.         if v.Name == "Idle" then
  633.             v:Stop()
  634.         end
  635.     end
  636.  
  637.     anim:Play()
  638.  
  639.     fighter.isBlocking = true
  640. end
  641.  
  642. function FightModule.Defend(player: Player, fighter: Types.Fighter)
  643.     if players[playedTurns] ~= player.UserId then return end -- not the player's turn
  644.     if fighter.isAttacking then return end -- player is doing attack
  645.     if fighter.isBlocking then return end -- player is blocking
  646.  
  647.     Defend(fighter)
  648.    
  649.     NextTurn()
  650. end
  651.  
  652. function FightModule.EnemyAITurn()
  653.    
  654.     if #globalFighters == 2 then
  655.         -- 1v1
  656.         local playerFighter: Types.Fighter = globalFighters[1] -- player
  657.         local opponentFighter: Types.Fighter = globalFighters[2] -- ai
  658.        
  659.         ResetFighterAtTurnStart(opponentFighter)
  660.  
  661.         if opponentFighter.model.Humanoid.Health <= 0 then
  662.             NextTurn()
  663.             return
  664.         end
  665.        
  666.         task.wait(2) -- give the illusion of AI thinking
  667.  
  668.         local aiAction
  669.        
  670.         if opponentFighter.ability then
  671.             aiAction = math.random(1, 2)
  672.         else
  673.             aiAction = math.random(1, 5)
  674.         end
  675.  
  676.         if opponentFighter.ability then
  677.             if
  678.                 AbilityModule.
  679.                 IsAbilityType(opponentFighter.ability, CustomEnum.AbilityType.Attack)
  680.                 or
  681.                 AbilityModule.
  682.                 IsAbilityType(opponentFighter.ability, CustomEnum.AbilityType.Cutscene)
  683.             then
  684.                 aiAction = 1
  685.             end
  686.         end
  687.  
  688.         if aiAction == 1 then
  689.             -- attack
  690.             Attack(opponentFighter, playerFighter)
  691.         elseif aiAction == 2 then
  692.             Defend(opponentFighter)
  693.         elseif aiAction > 2 then
  694.             FightModule.Ability({UserId = 0}, opponentFighter, aiAction - 2)
  695.         end
  696.  
  697.         NextTurn()
  698.     elseif #globalFighters > 2 then
  699.         -- party
  700.         local playerFighters: {Types.Fighter} = GetPlayerFighters(globalFighters, players[1]) -- player
  701.         local opponentFighters: {Types.Fighter} = GetPlayerFighters(globalFighters, 0) -- ai
  702.  
  703.         local opponentFighter = GetRandomFighter(opponentFighters)
  704.         local playerFighter = GetRandomFighter(playerFighters)
  705.        
  706.         for i,v in opponentFighters do
  707.             ResetFighterAtTurnStart(v)
  708.         end
  709.        
  710.         if opponentFighter == nil or playerFighter == nil then
  711.             NextTurn()
  712.             return
  713.         end
  714.  
  715.         task.wait(2) -- give the illusion of AI thinking
  716.  
  717.         local aiAction
  718.         if opponentFighter.ability then
  719.             aiAction = math.random(1, 2)
  720.         else
  721.             aiAction = math.random(1, 5)
  722.         end
  723.  
  724.         if opponentFighter.ability then
  725.             if
  726.                 AbilityModule.
  727.                 IsAbilityType(opponentFighter.ability, CustomEnum.AbilityType.Attack)
  728.                 or
  729.                 AbilityModule.
  730.                 IsAbilityType(opponentFighter.ability, CustomEnum.AbilityType.Cutscene)
  731.             then
  732.                 aiAction = 1
  733.             end
  734.         end
  735.  
  736.         if aiAction == 1 then
  737.             -- attack
  738.             Attack(opponentFighter, playerFighter)
  739.         elseif aiAction == 2 then
  740.             Defend(opponentFighter)
  741.         elseif aiAction > 2 then
  742.             FightModule.Ability({UserId = 0}, opponentFighter, aiAction - 2)
  743.         end
  744.  
  745.         NextTurn()
  746.     end
  747. end
  748.  
  749. return FightModule
  750.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement