This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 0e770b2b49
commit 94063e4369
7342 changed files with 1718932 additions and 14 deletions

2282
lua/vj_base/npc_general.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,375 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
/*-----------------------------------------------
*** Copyright (c) 2012-2023 by DrVrej, All rights reserved. ***
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
-----------------------------------------------*/
---------------------------------------------------------------------------------------------------------------------------------------------
-- AERIAL & AQUATIC BASE --
// MOVETYPE_FLY | MOVETYPE_FLYGRAVITY
ENT.CurrentAnim_AAMovement = nil
ENT.AA_NextMovementAnimTime = 0
ENT.AA_CurrentMoveAnimationType = "Calm" -- "Calm" | "Alert"
ENT.AA_CurrentMoveMaxSpeed = 0
ENT.AA_CurrentMoveTime = 0
ENT.AA_CurrentMoveType = 0 -- 0 = Undefined | 1 = Wander | 2 = Regular Move-to | 3 = Chase Enemy Move-to
ENT.AA_CurrentMovePos = nil
ENT.AA_CurrentMovePosDir = nil
ENT.AA_CurrentMoveDist = -1 -- Used to make sure we are making progress, in case something blocks its path
ENT.AA_LastChasePos = nil
ENT.AA_DoingLastChasePos = false
local defPos = Vector(0, 0, 0)
local defAng = Angle(0, 0, 0)
---------------------------------------------------------------------------------------------------------------------------------------------
--[[---------------------------------------------------------
Stops the current NPC, similar to ground NPCs calling self:StopMoving()
-----------------------------------------------------------]]
function ENT:AA_StopMoving()
if self:GetVelocity():Length() > 0 then
self.AA_CurrentMoveMaxSpeed = 0
self.AA_CurrentMoveTime = 0
self.AA_CurrentMoveType = 0
self.AA_CurrentMovePos = nil
self.AA_CurrentMovePosDir = nil
self.AA_CurrentMoveDist = -1
self:SetLocalVelocity(defPos)
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
--[[---------------------------------------------------------
Moves to the provided destination (If it can)
- dest = The destination to move to, it can be an entity or a vector
- playAnim = Should it play movement animation? | DEFAULT: true
- moveType = Type of movement animation it should do | DEFAULT: "Calm"
- extraOptions = Table that holds extra options to modify parts of the code
- AddPos = Position that will be added to the given destination | DEFAULT: Vector(0, 0, 0)
- FaceDest = Should it face the destination? | DEFAULT: true
- FaceDestTarget = If the destination is an entity, it will face the entity instead of the move position | DEFAULT: false
- IgnoreGround = If true, it will not do any ground checks | DEFAULT: false
-----------------------------------------------------------]]
local vecStart = Vector(0, 0, 30)
local vecEnd = Vector(0, 0, 40)
--
function ENT:AA_MoveTo(dest, playAnim, moveType, extraOptions)
local destVec = isvector(dest) and dest
if self.Dead or (!destVec && !IsValid(dest)) then return end
moveType = moveType or "Calm" -- "Calm" | "Alert"
extraOptions = extraOptions or {}
local addPos = extraOptions.AddPos or defPos -- This will be added to the given entity's position
local chaseEnemy = extraOptions.ChaseEnemy or false -- Used internally by ChaseEnemy, enables code that's used only for that
local moveSpeed = (moveType == "Calm" and self.Aerial_FlyingSpeed_Calm) or self.Aerial_FlyingSpeed_Alerted
local debug = self.VJ_DEBUG
local myPos = self:GetPos()
-- Initial checks for aquatic NPCs
if self.MovementType == VJ_MOVETYPE_AQUATIC then
moveSpeed = (moveType == "Calm" and self.Aquatic_SwimmingSpeed_Calm) or self.Aquatic_SwimmingSpeed_Alerted
if debug == true then
print("----------------")
print("My WaterLevel: "..self:WaterLevel())
if !destVec then print("dest WaterLevel: "..dest:WaterLevel()) end
end
-- NPC not fully in water, so forget the destination, instead wander OR go deeper into the war
if self:WaterLevel() <= 2 then self:DoIdleAnimation(1) return end
-- If the destination is a vector then make sure it's in the water
if destVec then
local tr_aquatic = util.TraceLine({
start = myPos,
endpos = destVec,
filter = self,
mask = MASK_WATER
})
if !tr_aquatic.Hit then self:DoIdleAnimation(1) return end
//print(tr_aquatic.Hit)
//VJ_CreateTestObject(tr_aquatic.HitPos, self:GetAngles(), Color(255,255,0), 5)
-- If the destination is not a vector, then make sure it's reachable
else
if dest:WaterLevel() <= 1 then
-- Destination not in water, so forget the destination, instead wander OR go deeper into the war
if dest:WaterLevel() == 0 then self:DoIdleAnimation(1) return end
local trene = util.TraceLine({
start = dest:GetPos() + self:OBBCenter(),
endpos = (dest:GetPos() + self:OBBCenter()) + dest:GetUp()*-20,
filter = self
})
//PrintTable(trene)
//print(trene.Hit)
//VJ_CreateTestObject(trene.HitPos, self:GetAngles(), Color(0,255,0), 5)
if trene.Hit == true then return end
//if IsValid(trene.Entity) && trene.Entity == dest then return end
end
end
end
-- Movement Calculations
// local nearpos = self:VJ_GetNearestPointToEntity(dest)
local startPos = myPos + self:OBBCenter() + vecStart // nearpos.MyPosition
local endPos = destVec or dest:GetPos() + dest:OBBCenter() + vecEnd // nearpos.EnemyPosition
local tr = util.TraceHull({
start = startPos,
endpos = endPos,
filter = {self, dest},
mins = self:OBBMins(),
maxs = self:OBBMaxs()
})
local trHitPos = tr.HitPos
//local groundLimited = false -- If true, it limited the ground because it was too close
-- Preform ground check if:
-- It's an aerial NPC AND it is not ignoring ground
-- It's NOT a chase enemy OR it is but the NPC doesn't have a melee attack
if self.MovementType == VJ_MOVETYPE_AERIAL && extraOptions.IgnoreGround != true && ((!chaseEnemy) or (chaseEnemy && !self.HasMeleeAttack)) then
local tr_check1 = util.TraceLine({start = startPos, endpos = startPos + Vector(0, 0, -self.AA_GroundLimit), filter = {self, dest}})
local tr_check2 = util.TraceLine({start = trHitPos, endpos = trHitPos + Vector(0, 0, -self.AA_GroundLimit), filter = {self, dest}})
if debug == true then
print("checking...")
VJ_CreateTestObject(startPos, self:GetAngles(), Color(145,255,0), 5)
VJ_CreateTestObject(tr_check1.HitPos, self:GetAngles(), Color(0,183,255), 5)
end
-- If it hit the world, then we are too close to the ground, replace "tr" with a new position!
if tr_check1.Hit == true or (tr_check2.Hit == true && !tr_check2.Entity:IsNPC()) then
if debug == true then print("Ground Hit!", tr_check1.HitPos:Distance(startPos)) end
//groundLimited = true
endPos.z = (tr_check1.Hit and myPos.z or endPos.z) + self.AA_GroundLimit
tr = util.TraceHull({
start = startPos,
endpos = endPos,
filter = {self, dest},
mins = self:OBBMins(),
maxs = self:OBBMaxs()
})
trHitPos = tr.HitPos
end
end
if !destVec then
-- If world is hit then our hitbox can't fully fit through the path to the destination
if tr.HitWorld then
if debug == true then print("hitworld") end
-- If we are already going to the last destination...
if self.AA_DoingLastChasePos then
-- Its movement is finished, therefore it's not moving there anymore!
if self.AA_CurrentMoveTime < CurTime() then
self.AA_DoingLastChasePos = false
self.AA_LastChasePos = nil
-- It's moving there, don't interrupt!
else
return
end
-- If we have a last destination then move there!
elseif self.AA_LastChasePos != nil then
if debug == true then VJ_CreateTestObject(self.AA_LastChasePos, self:GetAngles(), Color(0,68,255), 5) end
self.AA_DoingLastChasePos = true
tr = util.TraceHull({
start = startPos,
endpos = self.AA_LastChasePos,
filter = {self, dest},
mins = self:OBBMins(),
maxs = self:OBBMaxs()
})
end
else
self.AA_DoingLastChasePos = false
self.AA_LastChasePos = trHitPos
end
end
trHitPos = tr.HitPos
local trDistStart = startPos:Distance(trHitPos)
if debug == true then
util.ParticleTracerEx("Weapon_Combine_Ion_Cannon_Beam", tr.StartPos, trHitPos, false, self:EntIndex(), 0)//vortigaunt_beam
VJ_CreateTestObject(trHitPos, self:GetAngles(), Color(212,0,255), 5)
end
local finalPos = trHitPos
if trDistStart <= 16 && tr.HitWorld == true then
if debug == true then print("AA: Forward Blocked! [MOVE-TO]") end
finalPos = endPos
-- Make sure the trace actually went somewhere...
if tr.Fraction > 0 then
self.AA_LastChasePos = endPos
end
end
if destVec then
finalPos = finalPos + addPos
-- If the enemy is a bit above water, try to go for its GetPos, which is usually at its feet
elseif self.MovementType == VJ_MOVETYPE_AQUATIC && dest:WaterLevel() < 3 then
finalPos = dest:GetPos() + dest:GetForward()*addPos.x + dest:GetRight()*addPos.y + dest:GetUp()*addPos.z
else
finalPos = finalPos + dest:GetForward()*addPos.x + dest:GetRight()*addPos.y + dest:GetUp()*addPos.z
end
if debug == true then ParticleEffect("vj_impact1_centaurspit", finalPos, defAng, self) end
-- Z Calculations
-- BUG: Causes the NPC to go up / down VERY quickly!
/*local velUp = 0
local distZFinal = finalPos.z - startPos.z -- Distance between the hit position and the start position
if !groundLimited then
if distZFinal > 5 then -- Up
if debug == true then print("AA: GOING UP [MOVE-TO]") end
velUp = math.Clamp(distZFinal, 20, moveSpeed)
elseif distZFinal < 5 then -- Down
if debug == true then print("AA: GOING DOWN [MOVE-TO]") end
velUp = -math.Clamp(math.abs(distZFinal), 20, moveSpeed)
end
end*/
self.AA_CurrentMoveMaxSpeed = moveSpeed
if self.AA_MoveAccelerate > 0 then moveSpeed = Lerp(FrameTime()*2, self:GetVelocity():Length(), moveSpeed) end
-- Set the velocity
local velPos = (finalPos - startPos):GetNormal()*moveSpeed //+ self:GetUp()*velUp + self:GetForward()
local velTime = finalPos:Distance(startPos) / velPos:Length()
local velTimeCur = CurTime() + velTime
if velTimeCur == velTimeCur then -- Check for NaN
self.AA_CurrentMoveTime = velTimeCur
//self.NextIdleTime = velTimeCur
end
if extraOptions.FaceDest != false then
if extraOptions.FaceDestTarget == true && ((chaseEnemy && self.CombatFaceEnemy) or (!chaseEnemy)) then
self:FaceCertainEntity(dest, chaseEnemy, velTime)
else
self:FaceCertainPosition(finalPos, velTime)
end
//self.AA_CurrentTurnAng = chaseEnemy and false or self:GetFaceAngle(self:GetFaceAngle((velPos):Angle()))
end
self.AA_CurrentMoveType = chaseEnemy and 3 or 2
self.AA_CurrentMovePos = finalPos
self.AA_CurrentMovePosDir = finalPos - startPos
self.AA_CurrentMoveDist = -1
self:SetLocalVelocity(velPos)
-- Animations
if playAnim != false then
self.CurrentAnim_AAMovement = self.CurrentAnim_AAMovement
self.AA_CurrentMoveAnimationType = moveType
else
self.CurrentAnim_AAMovement = false
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
--[[---------------------------------------------------------
Makes the NPC wander, if it's aquatic then it will move deeper into water if it finds it necessary
- playAnim = Should it play movement animation? | DEFAULT: true
- moveType = Type of movement animation it should do | DEFAULT: "Calm"
- extraOptions = Table that holds extra options to modify parts of the code
- FaceDest = Should it face the destination? | DEFAULT: true
- IgnoreGround = If true, it will not do any ground checks | DEFAULT: false
-----------------------------------------------------------]]
function ENT:AA_IdleWander(playAnim, moveType, extraOptions)
moveType = moveType or "Calm" -- "Calm" | "Alert"
local moveSpeed = (moveType == "Calm" and self.Aerial_FlyingSpeed_Calm) or self.Aerial_FlyingSpeed_Alerted
local moveDown = false -- Used by aquatic NPCs only, forces them to move down
if self.MovementType == VJ_MOVETYPE_AQUATIC then
-- If NOT Completely submerged
if self:WaterLevel() < 3 then
self:AA_StopMoving()
moveDown = true
if self:WaterLevel() == 0 then
return
end
end
moveSpeed = (moveType == "Calm" and self.Aquatic_SwimmingSpeed_Calm) or self.Aquatic_SwimmingSpeed_Alerted
end
local debug = self.VJ_DEBUG
extraOptions = extraOptions or {}
-- Movement Calculations
local myPos = self:GetPos()
local myMaxs = self:OBBMaxs():Length()
local minDist = math.random(self.AA_MinWanderDist, self.AA_MinWanderDist + 150)
local tr_endpos = myPos + self:GetForward()*((myMaxs + minDist)*(math.random(1, 2) == 1 and -1 or 1)) + self:GetRight()*((myMaxs + minDist)*(math.random(1, 2) == 1 and -1 or 1)) + self:GetUp()*((myMaxs + minDist)*(math.random(1, 2) == 1 and -1 or 1))
if moveDown == true then
tr_endpos = myPos + self:GetUp()*((myMaxs + math.random(100, 150))*-1)
end
local tr = util.TraceLine({start = myPos, endpos = tr_endpos, filter = self})
local finalPos = tr.HitPos
//PrintTable(tr)
-- If we aren't being forced to move down, then make sure we limit how close we get to the ground!
if extraOptions.IgnoreGround != true && !moveDown && self.MovementType == VJ_MOVETYPE_AERIAL then
local tr_check = util.TraceLine({start = finalPos, endpos = finalPos + Vector(0, 0, -self.AA_GroundLimit), filter = self})
if debug == true then
print("checking...")
VJ_CreateTestObject(finalPos, self:GetAngles(), Color(255,255,255), 5)
VJ_CreateTestObject(tr_check.HitPos, self:GetAngles(), Color(255,0,255), 5)
end
-- If it hit the world, then we are too close to the ground, replace "tr" with a new position!
if tr_check.HitWorld == true then
if debug == true then print("Ground Hit!", tr_check.HitPos:Distance(finalPos)) end
tr_endpos.z = myPos.z + self.AA_GroundLimit
tr = util.TraceLine({start = myPos, endpos = tr_endpos, filter = self})
finalPos = tr.HitPos
end
end
if debug == true then
VJ_CreateTestObject(finalPos, self:GetAngles(), Color(0,255,255), 5)
util.ParticleTracerEx("Weapon_Combine_Ion_Cannon_Beam", tr.StartPos, finalPos, false, self:EntIndex(), 0)
ParticleEffect("vj_impact1_centaurspit", finalPos, defAng, self)
end
self.AA_CurrentMoveMaxSpeed = moveSpeed
if self.AA_MoveAccelerate > 0 then moveSpeed = Lerp(FrameTime()*2, self:GetVelocity():Length(), moveSpeed) end
-- Set the velocity
local velPos = (finalPos - myPos):GetNormal()*moveSpeed
local velTime = finalPos:Distance(myPos) / velPos:Length()
local velTimeCur = CurTime() + velTime
if velTimeCur == velTimeCur then -- Check for NaN
self.AA_CurrentMoveTime = velTimeCur
//self.NextIdleTime = velTimeCur
end
if extraOptions.FaceDest != false then
self:FaceCertainPosition(finalPos, velTime)
//self.AA_CurrentTurnAng = self:GetFaceAngle((finalPos - tr.StartPos):Angle())
//self:SetLocalAngularVelocity(self:GetFaceAngle((finalPos-tr.StartPos):Angle()))
end
self.AA_CurrentMoveType = 1
self.AA_CurrentMovePos = finalPos
self.AA_CurrentMovePosDir = finalPos - myPos
self.AA_CurrentMoveDist = -1
self:SetLocalVelocity(velPos)
-- Animations
if playAnim != false then
self.CurrentAnim_AAMovement = self.CurrentAnim_AAMovement
self.AA_CurrentMoveAnimationType = moveType
else
self.CurrentAnim_AAMovement = false
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
--[[---------------------------------------------------------
Makes the NPC chase its current enemy (If it has one)
- playAnim = Should it play movement animation? | DEFAULT: true
- moveType = Type of movement animation it should do | DEFAULT: "Alert"
-----------------------------------------------------------]]
function ENT:AA_ChaseEnemy(playAnim, moveType)
if self.Dead or (self.NextChaseTime > CurTime()) or !IsValid(self:GetEnemy()) then return end
self:AA_MoveTo(self:GetEnemy(), playAnim != false, moveType or "Alert", {FaceDestTarget=true, ChaseEnemy=true})
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:AA_MoveAnimation()
if self:GetSequence() != self.CurrentAnim_AAMovement && self:BusyWithActivity() == false && CurTime() > self.AA_NextMovementAnimTime then
local animTbl = {}
if self.AA_CurrentMoveAnimationType == "Calm" then
animTbl = (self.MovementType == VJ_MOVETYPE_AQUATIC and self.Aquatic_AnimTbl_Calm) or self.Aerial_AnimTbl_Calm
elseif self.AA_CurrentMoveAnimationType == "Alert" then
animTbl = (self.MovementType == VJ_MOVETYPE_AQUATIC and self.Aquatic_AnimTbl_Alerted) or self.Aerial_AnimTbl_Alerted
end
local pickedAnim = VJ_PICK(animTbl)
if type(pickedAnim) == "number" then pickedAnim = self:GetSequenceName(self:SelectWeightedSequence(pickedAnim)) end
self.CurrentAnim_AAMovement = VJ_GetSequenceName(self, pickedAnim)
self:VJ_ACT_PLAYACTIVITY(pickedAnim, false, 0, false, 0, {AlwaysUseSequence=true, SequenceDuration=false, SequenceInterruptible=true})
self.AA_NextMovementAnimTime = CurTime() + self:DecideAnimationLength(self.CurrentAnim_AAMovement, false)
end
end

View File

@@ -0,0 +1,321 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
require("ai_vj_schedule")
/*-----------------------------------------------
*** Copyright (c) 2012-2023 by DrVrej, All rights reserved. ***
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
-----------------------------------------------*/
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_FACE_X(faceType, customFunc)
-- Types: TASK_FACE_TARGET | TASK_FACE_ENEMY | TASK_FACE_PLAYER | TASK_FACE_LASTPOSITION | TASK_FACE_SAVEPOSITION | TASK_FACE_PATH | TASK_FACE_HINTNODE | TASK_FACE_IDEAL | TASK_FACE_REASONABLE
if (self.MovementType == VJ_MOVETYPE_STATIONARY && self.CanTurnWhileStationary == false) or (self.IsVJBaseSNPC_Tank == true) then return end
//self.NextIdleStandTime = CurTime() + 1.2
local vschedFaceX = ai_vj_schedule.New("vj_face_x")
vschedFaceX:EngTask(faceType or "TASK_FACE_TARGET", 0)
if (customFunc) then customFunc(vschedFaceX) end
self:StartSchedule(vschedFaceX)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_GOTO_LASTPOS(moveType, customFunc)
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then
self:AA_MoveTo(self:GetLastPosition(), true, (moveType == "TASK_RUN_PATH" and "Alert") or "Calm")
return
end
local vsched = ai_vj_schedule.New("vj_goto_lastpos")
vsched:EngTask("TASK_GET_PATH_TO_LASTPOSITION", 0)
//vsched:EngTask(moveType, 0)
vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vsched.IsMovingTask = true
if (moveType or "TASK_RUN_PATH") == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vsched.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vsched.MoveType = 0 end
//self.CanDoSelectScheduleAgain = false
//vsched.RunCode_OnFinish = function()
//self.CanDoSelectScheduleAgain = true
//end
if (customFunc) then customFunc(vsched) end
self:StartSchedule(vsched)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_GOTO_TARGET(moveType, customFunc)
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then
self:AA_MoveTo(self:GetTarget(), true, (moveType == "TASK_RUN_PATH" and "Alert") or "Calm")
return
end
local vsched = ai_vj_schedule.New("vj_goto_target")
vsched:EngTask("TASK_GET_PATH_TO_TARGET", 0)
//vsched:EngTask(moveType, 0)
vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vsched:EngTask("TASK_FACE_TARGET", 1)
vsched.IsMovingTask = true
if (moveType or "TASK_RUN_PATH") == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vsched.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vsched.MoveType = 0 end
if (customFunc) then customFunc(vsched) end
self:StartSchedule(vsched)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_GOTO_PLAYER(moveType, customFunc)
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then
self:AA_MoveTo(self:GetTarget(), true, (moveType == "TASK_RUN_PATH" and "Alert") or "Calm")
return
end
local vsched = ai_vj_schedule.New("vj_goto_player")
vsched:EngTask("TASK_GET_PATH_TO_PLAYER", 0)
//vsched:EngTask(moveType, 0)
vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vsched.IsMovingTask = true
if (moveType or "TASK_RUN_PATH") == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vsched.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vsched.MoveType = 0 end
if (customFunc) then customFunc(vsched) end
self:StartSchedule(vsched)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_COVER_FROM_ENEMY(moveType, customFunc)
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:AA_IdleWander() return end
moveType = moveType or "TASK_RUN_PATH"
local vsched = ai_vj_schedule.New("vj_cover_from_enemy")
vsched:EngTask("TASK_FIND_COVER_FROM_ORIGIN", 0)
//vsched:EngTask(moveType, 0)
vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vsched.IsMovingTask = true
if moveType == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vsched.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vsched.MoveType = 0 end
vsched.RunCode_OnFail = function()
//print("Cover from enemy failed!")
local vschedFail = ai_vj_schedule.New("vj_cover_from_enemy_fail")
vschedFail:EngTask("TASK_SET_ROUTE_SEARCH_TIME", 2)
vschedFail:EngTask("TASK_GET_PATH_TO_RANDOM_NODE", 500)
//vschedFail:EngTask(moveType, 0)
vschedFail:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vschedFail.IsMovingTask = true
if moveType == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vschedFail.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vschedFail.MoveType = 0 end
if (customFunc) then customFunc(vschedFail) end
self:StartSchedule(vschedFail)
end
if (customFunc) then customFunc(vsched) end
self:StartSchedule(vsched)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:VJ_TASK_COVER_FROM_ORIGIN(moveType, customFunc)
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:AA_IdleWander() return end
moveType = moveType or "TASK_RUN_PATH"
local vsched = ai_vj_schedule.New("vj_cover_from_origin")
vsched:EngTask("TASK_FIND_COVER_FROM_ORIGIN", 0)
//vsched:EngTask(moveType, 0)
vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vsched.IsMovingTask = true
if moveType == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vsched.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vsched.MoveType = 0 end
vsched.RunCode_OnFail = function()
local vschedFail = ai_vj_schedule.New("vj_cover_from_origin_fail")
vschedFail:EngTask("TASK_SET_ROUTE_SEARCH_TIME", 2)
vschedFail:EngTask("TASK_GET_PATH_TO_RANDOM_NODE", 500)
//vschedFail:EngTask(moveType, 0)
vschedFail:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
vschedFail.IsMovingTask = true
if moveType == "TASK_RUN_PATH" then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) vschedFail.MoveType = 1 else self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) vschedFail.MoveType = 0 end
if (customFunc) then customFunc(vschedFail) end
self:StartSchedule(vschedFail)
end
if (customFunc) then customFunc(vsched) end
self:StartSchedule(vsched)
end
---------------------------------------------------------------------------------------------------------------------------------------------
local task_idleWander = ai_vj_schedule.New("vj_idle_wander")
//task_idleWander:EngTask("TASK_SET_ROUTE_SEARCH_TIME", 0)
//task_idleWander:EngTask("TASK_GET_PATH_TO_LASTPOSITION", 0)
task_idleWander:EngTask("TASK_GET_PATH_TO_RANDOM_NODE", 350)
//task_idleWander:EngTask("TASK_WALK_PATH", 0)
task_idleWander:EngTask("TASK_WAIT_FOR_MOVEMENT", 0)
task_idleWander.ResetOnFail = true
task_idleWander.CanBeInterrupted = true
task_idleWander.IsMovingTask = true
task_idleWander.MoveType = 0
function ENT:VJ_TASK_IDLE_WANDER()
if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:AA_IdleWander() return end
self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk))
//self:SetLastPosition(self:GetPos() + self:GetForward() * 300)
self:StartSchedule(task_idleWander)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:RunAI(strExp) -- Called from the engine every 0.1 seconds
if self:GetState() == VJ_STATE_FREEZE or self:IsEFlagSet(EFL_IS_BEING_LIFTED_BY_BARNACLE) then self:MaintainActivity() return end
//print("Running the RunAI")
//self:SetArrivalActivity(ACT_COWER)
//self:SetArrivalSpeed(1000)
if self:IsRunningBehavior() or self:DoingEngineSchedule() then return true end
-- Apply walk frames to sequences
//print(self:GetSequenceMoveDist(self:GetSequence()))
if self.VJ_PlayingSequence && self:GetSequenceMoveDist(self:GetSequence()) > 0 && !self:IsMoving() && !self:IsSequenceFinished() && self.MovementType != VJ_MOVETYPE_AERIAL && self.MovementType != VJ_MOVETYPE_AQUATIC then
self:AutoMovement(self:GetAnimTimeInterval())
end
self:RunAIMoveJump()
if (!self.CurrentSchedule or (self.CurrentSchedule != nil && ((self:IsMoving() && self.CurrentSchedule.CanBeInterrupted == true) or (!self:IsMoving())))) && ((self.VJ_PlayingSequence == false) or (self.VJ_PlayingSequence == true && self.VJ_PlayingInterruptSequence == true)) then self:SelectSchedule() end
if (self.CurrentSchedule) then self:DoSchedule(self.CurrentSchedule) end
if self.VJ_PlayingSequence == false && self.VJ_PlayingInterruptSequence == false then self:MaintainActivity() end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:RunAIMoveJump()
if self:GetNavType() != NAV_JUMP then return end
if self:OnGround() then
self:MoveJumpStop()
if VJ_AnimationExists(self, ACT_LAND) then
self.NextIdleStandTime = CurTime() + self:SequenceDuration(self:GetSequence()) - 0.1
end
self:SetNavType(NAV_GROUND)
self:ClearGoal()
else
self:MoveJumpExec()
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:DoRunCode_OnFail(schedule)
if schedule == nil or schedule.AlreadyRanCode_OnFail == true then return false end
if schedule.RunCode_OnFail != nil && IsValid(self) then schedule.AlreadyRanCode_OnFail = true schedule.RunCode_OnFail() return true end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:DoRunCode_OnFinish(schedule)
if schedule == nil or schedule.AlreadyRanCode_OnFinish == true then return false end
if schedule.RunCode_OnFinish != nil && IsValid(self) then schedule.AlreadyRanCode_OnFinish = true schedule.RunCode_OnFinish() return true end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:OnMovementFailed()
//print("VJ Base: Movement Failed! "..self:GetName())
local curSchedule = self.CurrentSchedule
if curSchedule != nil then
if self:DoRunCode_OnFail(curSchedule) == true then
self:ClearCondition(35)
end
if curSchedule.ResetOnFail == true then
self:ClearCondition(35)
self:StopMoving()
//self:SelectSchedule()
end
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:OnMovementComplete()
//print("Movement completed!")
end
---------------------------------------------------------------------------------------------------------------------------------------------
local tr_addvec = Vector(0, 0, 2)
local tasksRun = {TASK_RUN_PATH=true, TASK_RUN_PATH_FLEE=true, TASK_RUN_PATH_TIMED=true, TASK_RUN_PATH_FOR_UNITS=true, TASK_RUN_PATH_WITHIN_DIST=true}
local tasksWalk = {TASK_WALK_PATH=true, TASK_WALK_PATH_TIMED=true, TASK_WALK_PATH_FOR_UNITS=true, TASK_WALK_PATH_WITHIN_DIST=true}
--
function ENT:StartSchedule(schedule)
if self.MovementType == VJ_MOVETYPE_STATIONARY && schedule.IsMovingTask == true then return end -- It's stationary therefore should not move!
if (self:GetState() == VJ_STATE_ONLY_ANIMATION or self:GetState() == VJ_STATE_ONLY_ANIMATION_CONSTANT or self:GetState() == VJ_STATE_ONLY_ANIMATION_NOATTACK) && schedule.IsPlayActivity != true then return end
if (IsValid(self:GetInternalVariable("m_hOpeningDoor")) or self:GetInternalVariable("m_flMoveWaitFinished") > 0) && self.CurrentSchedule != nil && schedule.Name == self.CurrentSchedule.Name then return end -- If it's the same task and it's opening a door, then DO NOT continue
self:ClearCondition(35)
if (!schedule.RunCode_OnFail) then schedule.RunCode_OnFail = nil end -- Code that will run ONLY when it fails!
if (!schedule.RunCode_OnFinish) then schedule.RunCode_OnFinish = nil end -- Code that will run once the task finished (Will run even if failed)
if (!schedule.ResetOnFail) then schedule.ResetOnFail = false end -- Makes the NPC stop moving if it fails
if (!schedule.StopScheduleIfNotMoving) then schedule.StopScheduleIfNotMoving = false end -- Will stop from certain entities, such as other NPCs
if (!schedule.StopScheduleIfNotMoving_Any) then schedule.StopScheduleIfNotMoving_Any = false end -- Will stop from any blocking entity!
if (!schedule.CanBeInterrupted) then schedule.CanBeInterrupted = false end
if (!schedule.ConstantlyFaceEnemy) then schedule.ConstantlyFaceEnemy = false end -- Constantly face the enemy while doing this task
if (!schedule.ConstantlyFaceEnemyVisible) then schedule.ConstantlyFaceEnemyVisible = false end
if (!schedule.CanShootWhenMoving) then schedule.CanShootWhenMoving = false end -- Is it able to fire when moving?
if !schedule.IsMovingTask then
for _,v in ipairs(schedule.Tasks) do
if tasksRun[v.TaskName] then
schedule.IsMovingTask = true
schedule.MoveType = 1
break
elseif tasksWalk[v.TaskName] then
schedule.IsMovingTask = true
schedule.MoveType = 0
break
else
schedule.IsMovingTask = false
schedule.MoveType = false
end
end
end
if schedule.IsMovingTask == nil then schedule.IsMovingTask = false end
if schedule.MoveType == nil then schedule.MoveType = false end
if schedule.IsMovingTask == true then
local tr = util.TraceHull({
start = self:GetPos(),
endpos = self:GetPos(),
mins = self:OBBMins() + tr_addvec,
maxs = self:OBBMaxs() + tr_addvec,
filter = self
})
if IsValid(tr.Entity) && tr.Entity:IsNPC() && !VJ_HasValue(self.EntitiesToNoCollide, tr.Entity:GetClass()) then
self:DoRunCode_OnFail(schedule)
return
end
self.LastHiddenZoneT = 0
self.CurAnimationSeed = 0
end
if schedule.CanShootWhenMoving == true && self.CurrentWeaponAnimation != nil && IsValid(self:GetEnemy()) then
self:DoWeaponAttackMovementCode(true, (schedule.MoveType == 0 and 1) or 0) -- Send 1 if the current task is walking!
self:SetArrivalActivity(self.CurrentWeaponAnimation)
end
schedule.AlreadyRanCode_OnFail = false
schedule.AlreadyRanCode_OnFinish = false
// lua_run PrintTable(Entity(1):GetEyeTrace().Entity.CurrentSchedule)
//if self.VJ_DEBUG == true then PrintTable(schedule) end
//if schedule.Name != "vj_chase_enemy" then PrintTable(schedule) end
if !self.Dead then self:DoRunCode_OnFinish(self.CurrentSchedule) end -- Yete arten schedule garne, verchatsoor
self.CurrentSchedule = schedule
self.CurrentTaskID = 1
self.GetNumberOfTasks = tonumber(schedule:NumTasks()) -- Or else nil
self:SetTask(schedule:GetTask(1))
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:DoSchedule(schedule)
if self:TaskFinished() then self:NextTask(schedule) end
if self.CurrentTask then self:RunTask(self.CurrentTask) end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:ScheduleFinished(schedule)
schedule = schedule or self.CurrentSchedule
self:DoRunCode_OnFinish(schedule)
self.CurrentSchedule = nil
self.CurrentTask = nil
self.CurrentTaskID = nil
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:SetTask(task)
self.CurrentTask = task
self.bTaskComplete = false
self.TaskStartTime = CurTime()
self:StartTask(self.CurrentTask)
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:NextTask(schedule)
//print(self.GetNumberOfTasks)
//print(self.CurrentTaskID)
if !schedule or !self then return end
if self.GetNumberOfTasks == nil then //1
print("VJ Base Schedules: Number of tasks is nil!")
end
//print("Running NextTask")
self.CurrentTaskID = self.CurrentTaskID + 1
if (self.CurrentTaskID > self.GetNumberOfTasks) then
self:ScheduleFinished(schedule)
return
end
self:SetTask(schedule:GetTask(self.CurrentTaskID))
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:OnTaskComplete()
//self:DoRunCode_OnFinish(self.CurrentSchedule) -- Will break many movement tasks (Ex: Humans Taking cover to reload)
self.bTaskComplete = true
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:StartTask(task) if task == nil or !task or !self then return end task:Start(self) end
function ENT:RunTask(task) if !task or !self then return end task:Run(self) end
function ENT:TaskTime() return CurTime() - self.TaskStartTime end
function ENT:TaskFinished() return self.bTaskComplete end
function ENT:StartEngineTask(iTaskID,TaskData) end
function ENT:RunEngineTask(iTaskID,TaskData) end
function ENT:StartEngineSchedule(scheduleID) self:ScheduleFinished() self.bDoingEngineSchedule = true end
function ENT:EngineScheduleFinish() self.bDoingEngineSchedule = nil end
function ENT:DoingEngineSchedule() return self.bDoingEngineSchedule end