mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
Upload
This commit is contained in:
2282
lua/vj_base/npc_general.lua
Normal file
2282
lua/vj_base/npc_general.lua
Normal file
File diff suppressed because it is too large
Load Diff
375
lua/vj_base/npc_movetype_aa.lua
Normal file
375
lua/vj_base/npc_movetype_aa.lua
Normal 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
|
||||
321
lua/vj_base/npc_schedules.lua
Normal file
321
lua/vj_base/npc_schedules.lua
Normal 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
|
||||
Reference in New Issue
Block a user