NPC Creation(How should I make the NPC's attack/block)

Right now I am working on an NPC script and it is going well so far. I would like to know how everyone else makes the combat side of their NPC. Ex. How do you make the NPC block attacks(I mean what makes the NPC start blocking/ what conditionals do you use) I’m also curious in how you make the NPC attack. Does it wait for the player to have a break in their attacks or does it block the players attacks and then attack.

My issue is I can’t think of a way to make a blocking system for the NPC I believe it’s because of lack of experience as I have not done NPC creation before.

I’ve looked on the devforum but can not find anything really in depth about what conditionals a person uses when making their NPC.

Also I am sorry because my script is definitely not neatly sorted

local pathFind = game:GetService("PathfindingService")
local Rs = game:GetService("RunService")
local Players = game:GetService("Players")
local Ts = game:GetService("TweenService")

local trackHum = script.Parent.Humanoid
local trackTorso = script.Parent.Torso

local isAtking = false
local atkDebounce = false
local canAtk = true
local shieldBroken = false
local m1Atk = false
local bBdebounce = false

local combo = 0
local blockHits = 0

local katana = script.Parent.npcKatana
local hum = katana.Parent:WaitForChild('Humanoid')
local trackHRP = katana.Parent:WaitForChild("HumanoidRootPart")
local root = hum.Parent.PrimaryPart

trackHum.WalkSpeed = 30
--Finds plr to track
local function findTarget2()
	local plrList = Players:GetPlayers()
	local nearestPlayer = nil
	local distance = nil
	local direction = nil
	local char = nil
	for i,v in pairs(plrList) do
		char = v.Character
		if char then
			local distVector = (v.Character.HumanoidRootPart.Position - root.Position)
			if not nearestPlayer then
				nearestPlayer = v
				distance = distVector.magnitude
				direction = distVector.Unit
			elseif distVector.magnitude <= distance then
				nearestPlayer = v
				distance = distVector.magnitude
				direction = distVector.Unit
			end
		end
	end
	return char,direction
end
--Checks for blocking
local function checkforBlock(target)
	local block = false
	local counterDebounce = false
	if blockHits == 5 then 
		blockHits = 0
	end

	if target ~= nil then
		if target.Parent:FindFirstChild("Blocker") ~= nil and counterDebounce == false then
			counterDebounce = true
			block = true
		elseif target.Parent:FindFirstChild("Blocker") == nil then
			block = false
		end
	end
	return block
end
--Dmgs player depending on what combo it is on
local function DmgPlayer(combo,target)
	if m1Atk == true and combo == 1 and canAtk == true then
		target:TakeDamage(10.5)
		canAtk = false
		local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
		local Tween = Ts:Create(target.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 15}):Play()
	end
	if m1Atk == true and combo == 2 and canAtk == true then
		target:TakeDamage(12.5)
		canAtk = false
		local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
		local Tween = Ts:Create(target.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 15}):Play()
	end
	if m1Atk == true and combo == 3 and canAtk == true then
		target:TakeDamage(13.5)
		canAtk = false
		local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
		local Tween = Ts:Create(target.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 15}):Play()
	end
	if m1Atk == true and combo == 4 and canAtk == true then
		target:TakeDamage(15)
		canAtk = false
		local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
		local Tween = Ts:Create(target.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 15}):Play()
	end
end
--Delays next atk depending on combo
local function Delays()
	if combo == 1 then
		spawn(function()
			wait(.75)
			isAtking = false
		end)--End Of Spawned Func
	end
	if combo == 2 then
		spawn(function()
			spawn(function()
				wait(.85)
				isAtking = false
			end)--End Of Spawned Func
		end)
	end
	if combo == 3 then
		spawn(function()
			wait(.95)
			isAtking = false
		end)--End Of Spawned Func
	end
	if combo == 4 then
		combo = 0 
		spawn(function()
			wait(1.25)
			isAtking = false
		end)--End Of Spawned Func
	end
end--End of func
--NPC plays animation and checks if touched
local function slashM1(m1,hitbox)
	m1:Play()
	canAtk = true
	combo = combo+1
	isAtking = true
	hitbox.Touched:Connect(function(hit)
		if hit.Parent:FindFirstChild("Humanoid") then
			local target = hit.Parent:WaitForChild("Humanoid")
			if checkforBlock(target) == false and canAtk == true then
				DmgPlayer(combo,target)
				m1Atk = true
			elseif checkforBlock(target) == true and canAtk == true then
				blockHits = blockHits +1
				print(blockHits)
				canAtk = false
			end
			m1.Stopped:Wait()
			canAtk = false
			Delays()
		end

	end) -- End of Touched Event

end
--If distance is less than 7 NPC atks
local function M1(HRP,m1)
	local hitbox = katana:WaitForChild("BladeHitbox")
	local distance = (trackHRP.Position - HRP.Position).Magnitude
	if distance <= 7 and isAtking == false then	
		slashM1(m1,hitbox)
	end
end --End of func

local function blockBreakStun(hum)
	if canAtk == true then
	local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
	local Tween = Ts:Create(hum.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 20}):Play()
	for i,v in pairs(hum:GetPlayingAnimationTracks()) do
		v:Stop()
	end
	hum.WalkSpeed = 0
	hum:TakeDamage(15)
	canAtk = false
	local stun = Instance.new("BoolValue")
	stun.Name = "stun"
	delay(2,function()
		hum.WalkSpeed = 16
		stun:Destroy()
		end)
	end
end
--Breaks player block
local rndmNum = math.random(1,4)
local function blockBreaker(m1,hitbox)
	if bBdebounce == false then

		m1:Play()
		canAtk = true
		if canAtk == true then
			hitbox.Touched:Connect(function(hit)
				if hit.Parent:FindFirstChild("Humanoid") then
					local target = hit.Parent:FindFirstChild("Humanoid")
					if checkforBlock(target) == true then
						if canAtk == true then
							blockBreakStun(target)
							blockHits = 0
							canAtk = false
							rndmNum = math.random(1,4)
							end
					elseif checkforBlock(target) == false then
						if canAtk == true then
							target:TakeDamage(15)
							local tweenInfo = TweenInfo.new(.5,Enum.EasingStyle.Back,Enum.EasingDirection.Out)
							local Tween = Ts:Create(hum.Parent.HumanoidRootPart,tweenInfo,{Velocity = trackHRP.CFrame.LookVector * 20}):Play()
							canAtk = false
							rndmNum = math.random(1,4)
							end
					end
				end
			end)
		end
		m1.Stopped:Wait()
		bBdebounce = true
		canAtk = false --cant atk after anim done
		delay(5,function()
			bBdebounce = false
		end) --end of delay func
	end --End of debounce
end --End of func


local function CombatSystem()
	local char,direction = findTarget2()
	local HRP = char.HumanoidRootPart
	local hitbox = katana:FindFirstChild("BladeHitbox")

	local anims = script:WaitForChild("Anims")
	local m1 = hum:LoadAnimation(anims:WaitForChild("Kendo"))
	local blockBreak = hum:LoadAnimation(anims:WaitForChild("BlocKBreak"))
	local dash = hum:LoadAnimation(anims:WaitForChild("Dash"))
	print(rndmNum)
	if blockHits == rndmNum then
		print("blockbreaker")
		blockBreaker(m1,hitbox)
	end
	M1(HRP,m1)
end --End of function



local targetDistance = 25
local stopDistance = 10


local function checkDist(distance,torso)
	if distance <= 6 then
		trackHum.WalkSpeed = hum.WalkSpeed
	else 
		trackHum.WalkSpeed = 30
		local path = pathFind:CreatePath()
		path:ComputeAsync(trackTorso.Position,torso.Position)
		local waypoints = path:GetWaypoints()
		for i,v in pairs(waypoints) do
			local block = Instance.new("Part",workspace)
			block.Anchored = true
			block.CanCollide = false
			block.Size = Vector3.new(1,1,1)
			block.Shape = Enum.PartType.Ball
			block.BrickColor = BrickColor.new("Yellow flip/flop")
			block.Position = v.Position

			trackHum:MoveTo(v.Position)
		end
	end
end

while wait(.1) do
	root:SetNetworkOwner(nil)
	local char,direction = findTarget2()
	--if char == nil then
	--	trackHum:MoveTo( Vector3.new(math.random(-25,5),0,math.random(0,25)))
	--	trackHum.MoveToFinished:Wait(false)
	--	end
	if char then
		local torso = char.HumanoidRootPart
		local distance = (torso.Position-root.Position).magnitude
		if distance <= 7 then
			CombatSystem()
		end
		if distance <= 50 then
			wait(.5)
			checkDist(distance,torso)
		end
	end
end

this is my code rn feel free to find mistakes or things I could do better. All criticism is welcome.

1 Like

where you said: “Does it wait for the player to have a break in their attacks or does it block the players attacks and then attack”

since i’m lazy to post script i will say what i think

For example,
when you script some npc, you will need to create some Attack function, walk , actions, and etc

then, when the npc is about to attack, if the variable “PlayerIsAttacking” == true then the npc would block instantly, or make some animation, then after a small amount of seconds, the npc will Block. or parry, depending on the timing,

(the PlayerIsAttacking variable will be TRUE when the user press Mouse buttons or some Skill,)
the reaction and timing of the npc must be really good, so they will be able to react instantly without delay

when you hit the npc, he will be stunned ( animation being hit) for 0.05 ~~ 0.5 (depends on how fast the user attacks cooldown is, dagger, sword, axe, etc.

But, sometimes the npc will have no chance against you, because you will attack too fast (Dagger)

this is where Blocking or parry will shine, since your "PlayerIsAttacking variable is True most of the time

THE npc will try to block or parry constantly

after parrying, your weapon will make some animation, delaying even more your attack, this is where the npc will be able to attack you, doens’t matter how fast you can attack, only if your attack is really fast, ( leading to infinite parry trade with the npc )

Again, if your npc is scripted to be fast, and act fast, he will parry alot, your only way is creating some sort of ( if you parry 10x you will be tired, or your attack will be slowed down)

i gave some ideas, but since the game i’m creating will use HyperArmor ( the npc will have few seconds to react)
the blocking will not be necessary most of the time

3 Likes

Ok thank you this helps me a lot. Yesterday when I was considering the ways for the NPC to atk and parry making a variable(When the player atked) crossed my mind but I didn’t know if that would be crazy OP so it is very reassuring that it isn’t and that other people have the same mindset.

Do you suggest that I insert a Boolean value for the variable similar to how i did the block variable in my script?

target.Parent:FindFirstChild("Blocker")

Also when it comes to parrying I was thinking of inserting a variable called PerfectBlock or smthn and when the plr blocks there’s a time frame for them to get a perfect block similar to deepwokens parry system. Would this be a good idea or is there a better way to do it?

1 Like

yea i would do that, but i would make something like this:

if target.Parent:FindFirstChild("PlayerIsAttacking") == true then
     --the npc noticed that the player is attacking, and the npc will react RIGHT NOW
    --Insert Some script that blocks or active some "Block" variable to true, 
    --so, the npc will start blocking 
   else if target.Parent:FindFirstChild("PlayerIsAttacking") == false then
    --Player is not trying to attack... time to attack.
    ---Insert Script functions here or functional variables

end

this will repeat and probaly will work very well, i can’t test it since my combat script is different and unfinished

1 Like

But let’s suppose that the npc is being stunned for a few seconds when you hit him, you need to give him a chance to counter attack
, ( if you already have some methods, then everything is fine)

because you can just all-win the npc attacking fast

(that’s why i use HyperArmor), and that makes more sense to me than creating some delay on attacks, it may mess with some mechanics later on)

1 Like

Are you giving the player HyperArmor as well or just NPC i think u mean only NPC but im just checking

1 Like

no no, the player has no HyperArmor, it would be unfair, i want the game to be hard, so the player must block or parry while the HyperArmor Npc is attacking

1 Like

Ok I thought so but just double checking. Ur game sounds fun lmk when it releases

1 Like

you can also add a debounce or some sort of cooldown to make the npc not look like it has auto parry