I’m wanting to have multiple streak items, and here’s a quick example for grenades. I fear this is incredibly cluttered and poorly written.
Basically, I require all the modules on the server, and then the client requires and fires the .Use() function when they use the item.
This is currently flawed as well, as I create the grenade on the client (so theres a quick response between throwing the grenade/etc), and I also create the grenade on the server, and then delete the server grenade from our own client (so you don’t see 2 grenades.)
Is there better ways of handling this? What can I do different/better. Ideally, the main thing that needs to stay is Grenade.Use() as thats the function the client fires when they use said streak item. And then everything else in the code is run on start of server.
local Grenade = {}
local CollectionService = game:GetService("CollectionService")
local Debris = game:GetService("Debris")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local GrenadeItem = script:WaitForChild("Grenade")
local GameSettings = ReplicatedStorage:WaitForChild("GameSettings")
local Shared = ReplicatedStorage:WaitForChild("Shared")
local Maid = require(Shared.Maid)
local Camera = workspace.CurrentCamera
local SPEED = 3
local EXPLODE_TIME = 2
local DIAMETER = 30
local Explode = script:WaitForChild("Explode")
local Throw = script:WaitForChild("Throw")
--// Create the grenade
local function CreateGrenade(player, cFrame, client)
local GrenadeItem = GrenadeItem:Clone()
GrenadeItem.BrickColor = player.TeamColor
GrenadeItem:SetAttribute("Creator", player.Name)
GrenadeItem:SetAttribute("Client", client)
CollectionService:AddTag(GrenadeItem, "Grenade")
GrenadeItem.Parent = workspace
GrenadeItem.CFrame = cFrame * CFrame.new(0, -0.5, -2)
GrenadeItem:ApplyImpulse(GrenadeItem.CFrame.LookVector * SPEED)
return GrenadeItem
end
--// Use the grenade streak
function Grenade.Use()
if RunService:IsClient() then
local Player = Players.LocalPlayer
local GrenadeItem = CreateGrenade(Player, Camera.CFrame, true)
Throw:FireServer(Camera.CFrame) -- Throw on the server
delay(EXPLODE_TIME, function()
GrenadeItem.Anchored = true
GrenadeItem.Transparency = 1
local Explode = GrenadeItem:Clone()
Explode.Transparency = 0
Explode.Parent = GrenadeItem
local ExplodeTween = TweenService:Create(
Explode,
TweenInfo.new(0.5),
{
Size = Vector3.new(DIAMETER, DIAMETER, DIAMETER),
Transparency = 1
}
)
ExplodeTween:Play()
ExplodeTween.Completed:Wait()
GrenadeItem:Destroy()
end)
end
end
if RunService:IsServer() then
--// Character was hit
local function CharacterHit(player, hitPlayer, hitCharacter)
if not hitPlayer or not hitCharacter then return end
if hitPlayer.Character ~= hitCharacter then return end
if player == hitPlayer then return end -- Creator can't tag themselves
local Teams = GameSettings:GetAttribute("Teams")
if player.Team == hitPlayer.Team and Teams then return end -- Can't tag your own team
local Humanoid = hitCharacter:FindFirstChildWhichIsA("Humanoid")
if not Humanoid then return end
-- Create all values associated with Creator
local CreatorValue = Instance.new("ObjectValue")
CreatorValue.Name = "Creator"
CreatorValue.Value = player
-- Player's level
local LevelValue = Instance.new("NumberValue")
LevelValue.Name = "Level"
--LevelValue.Value = player.PlayerData.Level.Value
LevelValue.Parent = CreatorValue
-- Grenade used
local EquippedValue = Instance.new("StringValue")
EquippedValue.Name = "Equipped"
EquippedValue.Value = "Grenade"
EquippedValue.Parent = CreatorValue
CreatorValue.Parent = Humanoid
Humanoid:TakeDamage(100) -- Kill player
end
--// Grenade has been thrown
local function GrenadeThrown(throwingPlayer, cFrame)
local GrenadeItem = CreateGrenade(throwingPlayer, cFrame)
delay(EXPLODE_TIME, function()
GrenadeItem.Anchored = true
GrenadeItem.Transparency = 1
local Explode = GrenadeItem:Clone()
Explode.Transparency = 0
Explode.Parent = GrenadeItem
local ExplodeTween = TweenService:Create(
Explode,
TweenInfo.new(0.5),
{
Size = Vector3.new(DIAMETER, DIAMETER, DIAMETER),
Transparency = 1
}
)
ExplodeTween:Play()
coroutine.wrap(function()
ExplodeTween.Completed:Wait()
GrenadeItem:Destroy()
end)()
local Teams = GameSettings:GetAttribute("Teams")
-- Check radius of players
for _, player in pairs(Players:GetPlayers()) do
if player == throwingPlayer then continue end -- Don't affect ourselves
if player.Team == throwingPlayer.Team and Teams then continue end -- Don't affect team mates
local Character = player.Character
if not Character then continue end
if (Character.HumanoidRootPart.Position - GrenadeItem.Position).Magnitude <= DIAMETER / 2 then
CharacterHit(throwingPlayer, player, Character)
end
end
end)
end
Throw.OnServerEvent:Connect(GrenadeThrown)
elseif RunService:IsClient() then
local Player = Players.LocalPlayer
--// Remove the server grenade from our client (so no double grenade visual)
local function RemoveGrenade(grenade)
if grenade:GetAttribute("Client") then return end
if grenade:GetAttribute("Creator") ~= Player.Name then return end -- Not our grenade
RunService.RenderStepped:Wait()
grenade:Destroy()
end
CollectionService:GetInstanceAddedSignal("Grenade"):Connect(RemoveGrenade)
end
return Grenade
NOTE I don’t want to split this up into seperate modules. All streak items will have their own module, and each module would handle that specific streak items information (for example sentries, radars, landmines, etc.)