I’m back at it again with another error for my Harry Potter Wand! I finished Avada Kedavra, and I am working on the second spell, Crucio. For some reason, Crucio (which only has a different effect, everything else is the same) has a weird error. Avada Kedavra does not have this error. The error is 20:29:31.090 - ServerScriptService.Crucio:43: attempt to index field 'Parent' (a nil value).
Client:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage:WaitForChild("Crucio")
local mouse = game.Players.LocalPlayer:GetMouse()
local player = game.Players.LocalPlayer
local orientation = script.Parent.Handle.Orientation
local SpellChatted = false
local VALID_DURATION = 4
local debounce = true
mouse.Button1Down:Connect(function()
if debounce == true then
debounce = false
event:FireServer(mouse.Hit, orientation,SpellChatted)
wait(4)
debounce = true
end
end)
player.Chatted:Connect(function(msg)
local msg = msg:lower()
if msg:match("crucio") then
SpellChatted = true
print(player.Name.. "has typed in Crucio.")
wait(VALID_DURATION)
SpellChatted = false
end
end)
Server:
local RepStorage = game:GetService("ReplicatedStorage")
local Event = RepStorage:WaitForChild("Crucio")
local wand = game.StarterPack.Wand
local function IsWandEquipped(character)
for _, child in pairs(character:GetChildren()) do
if child.Name == wand.Name then
return true
end
end
return false
end
local function avadakedavra(plr,hit, orientation,spellChatted)
local character= plr.Character or plr.CharacterAdded:wait()
if spellChatted and IsWandEquipped(character) then
local ray = Ray.new(
plr.Character.Head.CFrame.p,
(hit.p - plr.Character.Head.CFrame.p).unit * 200)
local ignore = plr.Character
local part, position = workspace:FindPartOnRay(ray, plr.Character, false, true)
local hit, position, normal = workspace:FindPartOnRay(ray, ignore)
local beam = Instance.new("Part", workspace)
beam.BrickColor = BrickColor.new("Really red")
beam.FormFactor = "Custom"
beam.Material = "Neon"
beam.Transparency = 0.5
beam.Anchored = true
beam.Locked = true
beam.CanCollide = false
beam.Orientation = orientation
beam.Shape = Enum.PartType.Block
beam.Size = Vector3.new(1, 1, 1)
local distance = (plr.Character.Head.CFrame.p - position).magnitude
print(distance)
beam.CFrame = CFrame.new(plr.Character.Head.CFrame.p - position)
local start = plr.Character.Head.CFrame
for i = 1, 500 do
beam.CFrame = start:lerp(CFrame.new(position), i/10)
wait()
if part then
local humanoid = part.Parent:FindFirstChild("Humanoid")
if not humanoid then
humanoid = part.Parent.Parent:FindFirstChild("Humanoid")
end
if humanoid then
for i = 1, 10 do
humanoid.Health = humanoid.Health - 9.5
end
beam:Destroy()
end
end
wait()
end
wait(7)
beam:Destroy()
end
end
Event.OnServerEvent:Connect(avadakedavra)
It would have helped to have commented your code and pointed out where specifically your error was. It was fairly painful to count out your lines to find the source of error.
I feel that it’d be more worth your time to address all the potential or actual code problems that you’re having or that can be improved upon rather than going at the error specifically, since there’s a lot to be looked at in your code.
Client:
Try keeping your variables and constants together for better readability. You should also aim to use consistent conventions. Unless, well, you don’t care. Here’s what I typically use:
This in reference to all your variables being lowercase except for ReplicatedStorage, SpellChatted and VALID_DURATION.
Might be more helpful to send variables through remotes in the order that you check them in.
SpellChatted, orientation, mouse.Hit
First, you check if a spell was chatted. If it was, then you use the orientation of the Handle to determine a start point. Finally, you construct a Ray to mouse.Hit.
You may also want to consider not adding a debounce if a spell wasn’t chatted for the sake of UX design. Might hurt the experience to chant a spell but not be able to use it.
Server:
You broke convention using RepStorage over ReplicatedStorage! What happened!?
Everything from indexing the StarterPack’s Wand to the IsWandEquipped function is pointless overhead. Get rid of it. Keep the function but change how it works to something less intensive.1
For a receiving remote, don’t use CharacterAdded.Wait. Check if a character exists; if it doesn’t reject the request. Don’t stall the thread until the character exists.
MAIN SOURCE OF YOUR ERROR: Your code assumes that FindPartOnRay returns a non-nil part. When you use that method, it can return a nil value. Thus, when your code proceeds and doesn’t check if part is non-nil, it attempts to index Parent. Parent is not a valid member of nil.3
Even if the part does exist, Parent can be nil too. Parts with nil parents are typically not going to be in the Workspace or detectable, but just keep that in mind.
For some reason, you’re casting two rays? Get rid of the bottom one, you don’t use its arguments anyway and one them variable shadows a parameter sent to the function avadakedavra.2
A note that I’m just addressing your code work, but typically what I’d recommend here is that you pass this beam creation work to the client to render.
You can also get rid of unnecessary property setting.
[1]:
local function isWandEquipped(character)
local tool = character:FindFirstChildWhichIsA("Tool")
if tool and tool.Name == "Wand" then
return true
end
return false
end
-- The function below is also acceptable:
local function isWandEquipped(character)
local tool = character:FindFirstChildWhichIsA("Tool")
return tool and tool.Name == "Wand"
end
[2]:
local part, position = workspace:FindPartOnRay(ray, plr.Character, false, true)
[3]:
if part and part.Parent then
local humanoid = part.Parent:FindFirstChildWhichIsA("Humanoid")
if not humanoid and part.Parent.Parent then
humanoid = part.Parent.Parent:FindFirstChildWhichIsA("Humanoid")
end
end
[4]:
-- It'd be better to create a function that makes and returns the beam.
local beam = Instance.new("Part")
beam.BrickColor = BrickColor.new("Really red")
beam.Material = Enum.Material.Neon
beam.Transparency = 0.5
beam.Anchored = true
beam.CanCollide = false
beam.Orientation = orientation
beam.Size = Vector3.new(1, 1, 1)
-- Got rid of distance calculation, you don't ever use distance
-- @ below, CFrame.p is deprecated in favour of CFrame.Position
beam.CFrame = CFrame.new(plr.Character.Head.CFrame.Position - position)
beam.Parent = workspace
Wow! Thanks for all of the information! There is one tiny issue. It still kills you when you cast crucio. It’s only supposed to take 95 damage, not 100.
If the damage is meant to be instantaneous (seeing as you do not include a wait in your loop), you can get rid of the loop and just subtract humanoid health, then remove the beam.
if humanoid then
humanoid.Health = humanoid.Health - 95
end
Actually, in fact, your whole loop should be redone entirely. What’s happening here is that you have your loop, for i = 1, 500 right? The code in that loop runs 500 times. Your damage function is in that loop, so it runs 500 times on the detected humanoid.
Something you can do is create a variable in your code that determines if the humanoid was hit before. If they weren’t, damage them and set the variable to the humanoid. Next time the function checks to damage a humanoid, see if the humanoid is equal to that variable. If it is, do nothing, otherwise damage and set the variable.
In the long term though, restrict your for loop only to lerping the beam and keep the damage function outside of the loop.