--[[ | 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/ --]] if (!file.Exists("autorun/vj_base_autorun.lua","LUA")) then return end AddCSLuaFile("shared.lua") include("vj_base/npc_general.lua") include("vj_base/npc_schedules.lua") include("vj_base/npc_movetype_aa.lua") include("shared.lua") /*-------------------------------------------------- *** 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. --------------------------------------------------*/ AccessorFunc(ENT, "m_iClass", "NPCClass", FORCE_NUMBER) AccessorFunc(ENT, "m_fMaxYawSpeed", "MaxYawSpeed", FORCE_NUMBER) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Core Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.Model = {} -- The game will pick a random model from the table when the SNPC is spawned | Add as many as you want ENT.VJ_IsHugeMonster = false -- This is mostly used for massive or boss SNPCs, it affects certain part of the SNPC, for example the SNPC won't receive any knock back -- ====== Health ====== -- ENT.StartHealth = 50 -- The starting health of the NPC ENT.HasHealthRegeneration = false -- Can the SNPC regenerate its health? ENT.HealthRegenerationAmount = 4 -- How much should the health increase after every delay? ENT.HealthRegenerationDelay = VJ_Set(2, 4) -- How much time until the health increases ENT.HealthRegenerationResetOnDmg = true -- Should the delay reset when it receives damage? -- ====== Collision / Hitbox Variables ====== -- ENT.HullType = HULL_HUMAN ENT.HasHull = true -- Set to false to disable HULL ENT.HullSizeNormal = true -- set to false to cancel out the self:SetHullSizeNormal() ENT.HasSetSolid = true -- set to false to disable SetSolid -- ====== Sight & Speed Variables ====== -- ENT.SightDistance = 10000 -- How far it can see | Remember to call "self:SetSightDistance(dist)" if you want to set a new value after initialize! ENT.SightAngle = 80 -- The sight angle | Example: 180 would make the it see all around it | Measured in degrees and then converted to radians ENT.TurningSpeed = 20 -- How fast it can turn ENT.TurningUseAllAxis = false -- If set to true, angles will not be restricted to y-axis, it will change all axes (plural axis) ENT.AnimationPlaybackRate = 1 -- Controls the playback rate of all the animations -- ====== Movement Variables ====== -- -- Types: VJ_MOVETYPE_GROUND | VJ_MOVETYPE_AERIAL | VJ_MOVETYPE_AQUATIC | VJ_MOVETYPE_STATIONARY | VJ_MOVETYPE_PHYSICS ENT.MovementType = VJ_MOVETYPE_GROUND -- How does the SNPC move? ENT.UsePlayerModelMovement = false -- If true, it will allow the NPC to use player models properly by calculating the direction it needs to go to and setting the appropriate values -- Jumping Variables: -- Requires "CAP_MOVE_JUMP" | Applied automatically by the base if "ACT_JUMP" is valid on the NPC's model ENT.AllowMovementJumping = true -- Should the NPC be allowed to jump from one node to another? ENT.MaxJumpLegalDistance = VJ_Set(150, 280) -- The max distance the NPC can jump (Usually from one node to another) | ( UP, DOWN ) -- Stationary Move Type Variables: ENT.CanTurnWhileStationary = true -- If true, the NPC will be able to turn while it's stationary ENT.Stationary_UseNoneMoveType = false -- Technical variable, used if there is any issues with the NPC's position (It has its downsides, use only when needed!) -- ====== NPC Controller Data ====== -- ENT.VJC_Data = { CameraMode = 1, -- Sets the default camera mode | 1 = Third Person, 2 = First Person ThirdP_Offset = Vector(0, 0, 0), -- The offset for the controller when the camera is in third person FirstP_Bone = "ValveBiped.Bip01_Head1", -- If left empty, the base will attempt to calculate a position for first person FirstP_Offset = Vector(0, 0, 5), -- The offset for the controller when the camera is in first person FirstP_ShrinkBone = true, -- Should the bone shrink? Useful if the bone is obscuring the player's view FirstP_CameraBoneAng = 0, -- Should the camera's angle be affected by the bone's angle? | 0 = No, 1 = Pitch, 2 = Yaw, 3 = Roll FirstP_CameraBoneAng_Offset = 0, -- How much should the camera's angle be rotated by? | Useful for weird bone angles } -- ====== Miscellaneous Variables ====== -- ENT.HasEntitiesToNoCollide = true -- If set to false, it won't run the EntitiesToNoCollide code ENT.EntitiesToNoCollide = {} -- Entities to not collide with when HasEntitiesToNoCollide is set to true ENT.AllowPrintingInChat = true -- Should this SNPC be allowed to post in player's chat? Example: "Blank no longer likes you." ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ AI / Relationship Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.CanOpenDoors = true -- Can it open doors? ENT.HasAllies = true -- Put to false if you want it not to have any allies ENT.VJ_NPC_Class = {} -- NPCs with the same class with be allied to each other -- Common Classes: Combine = CLASS_COMBINE || Zombie = CLASS_ZOMBIE || Antlions = CLASS_ANTLION || Xen = CLASS_XEN || Player Friendly = CLASS_PLAYER_ALLY ENT.FriendsWithAllPlayerAllies = false -- Should this SNPC be friends with all other player allies that are running on VJ Base? ENT.Behavior = VJ_BEHAVIOR_AGGRESSIVE -- The behavior of the SNPC -- VJ_BEHAVIOR_AGGRESSIVE = Default behavior, attacks enemies || VJ_BEHAVIOR_NEUTRAL = Neutral to everything, unless provoked -- VJ_BEHAVIOR_PASSIVE = Doesn't attack, but can be attacked by others || VJ_BEHAVIOR_PASSIVE_NATURE = Doesn't attack and is allied with everyone ENT.IsGuard = false -- If set to false, it will attempt to stick to its current position at all times ENT.AlertedToIdleTime = VJ_Set(4, 6) -- How much time until it calms down after the enemy has been killed/disappeared | Sets self.Alerted to false after the timer expires ENT.MoveOutOfFriendlyPlayersWay = true -- Should the SNPC move out of the way when a friendly player comes close to it? ENT.BecomeEnemyToPlayer = false -- Should the friendly SNPC become enemy towards the player if it's damaged by it or it witnesses another ally killed by it ENT.BecomeEnemyToPlayerLevel = 2 -- Any time the player does something bad, the NPC's anger level raises by 1, if it surpasses this, it will become enemy! -- ====== Old Variables (Can still be used, but it's recommended not to use them) ====== -- ENT.PlayerFriendly = false -- Makes the SNPC friendly to the player and HL2 Resistance -- ====== Passive Behavior Variables ====== -- ENT.Passive_RunOnTouch = true -- Should it run away and make a alert sound when something collides with it? ENT.Passive_NextRunOnTouchTime = VJ_Set(3, 4) -- How much until it can run away again when something collides with it? ENT.Passive_RunOnDamage = true -- Should it run when it's damaged? | This doesn't impact how self.Passive_AlliesRunOnDamage works ENT.Passive_AlliesRunOnDamage = true -- Should its allies (other passive SNPCs) also run when it's damaged? ENT.Passive_AlliesRunOnDamageDistance = 800 -- Any allies within this distance will run when it's damaged ENT.Passive_NextRunOnDamageTime = VJ_Set(6, 7) -- How much until it can run the code again? -- ====== On Player Sight Variables ====== -- ENT.HasOnPlayerSight = false -- Should do something when it sees the enemy? Example: Play a sound ENT.OnPlayerSightDistance = 200 -- How close should the player be until it runs the code? ENT.OnPlayerSightDispositionLevel = 1 -- 0 = Run it every time | 1 = Run it only when friendly to player | 2 = Run it only when enemy to player ENT.OnPlayerSightOnlyOnce = true -- If true, it will only run the code once | Sets self.HasOnPlayerSight to false once it runs! ENT.OnPlayerSightNextTime = VJ_Set(15, 20) -- How much time should it pass until it runs the code again? -- ====== Call For Help Variables ====== -- ENT.CallForHelp = true -- Does the SNPC call for help? ENT.CallForHelpDistance = 2000 -- -- How far away the SNPC's call for help goes | Counted in World Units ENT.NextCallForHelpTime = 4 -- Time until it calls for help again ENT.HasCallForHelpAnimation = true -- if true, it will play the call for help animation ENT.AnimTbl_CallForHelp = {ACT_SIGNAL_ADVANCE, ACT_SIGNAL_FORWARD} -- Call For Help Animations ENT.CallForHelpAnimationDelay = 0 -- It will wait certain amount of time before playing the animation ENT.CallForHelpAnimationPlayBackRate = 1 -- How fast should the animation play? | Currently only for gestures! ENT.CallForHelpStopAnimations = true -- Should it stop attacks for a certain amount of time? -- To let the base automatically detect the animation duration, set this to false: ENT.CallForHelpStopAnimationsTime = false -- How long should it stop attacks? ENT.CallForHelpAnimationFaceEnemy = true -- Should it face the enemy when playing the animation? ENT.NextCallForHelpAnimationTime = 30 -- How much time until it can play the animation again? -- ====== Medic Variables ====== -- ENT.IsMedicSNPC = false -- Is this SNPC a medic? Does it heal other friendly friendly SNPCs, and players(If friendly) ENT.AnimTbl_Medic_GiveHealth = {ACT_SPECIAL_ATTACK1} -- Animations is plays when giving health to an ally ENT.Medic_DisableAnimation = false -- if true, it will disable the animation code ENT.Medic_TimeUntilHeal = false -- Time until the ally receives health | Set to false to let the base decide the time ENT.Medic_CheckDistance = 600 -- How far does it check for allies that are hurt? | World units ENT.Medic_HealDistance = 100 -- How close does it have to be until it stops moving and heals its ally? ENT.Medic_HealthAmount = 25 -- How health does it give? ENT.Medic_NextHealTime = VJ_Set(10, 15) -- How much time until it can give health to an ally again ENT.Medic_SpawnPropOnHeal = true -- Should it spawn a prop, such as small health vial at a attachment when healing an ally? ENT.Medic_SpawnPropOnHealModel = "models/healthvial.mdl" -- The model that it spawns ENT.Medic_SpawnPropOnHealAttachment = "anim_attachment_LH" -- The attachment it spawns on ENT.Medic_CanBeHealed = true -- If set to false, this SNPC can't be healed! -- ====== Follow System Variables ====== -- -- Associated variables: self.FollowData, self.IsFollowing ENT.FollowMinDistance = 150 -- Minimum distance the NPC should come to the player | The base automatically adds the NPC's size to this variable to account for different sizes! ENT.NextFollowUpdateTime = 0.5 -- Time until it checks if it should move to the player again | Lower number = More performance loss ENT.FollowPlayer = true -- Should the NPC follow the player when the player presses a certain key? | Restrictions: Player has to be friendly and the NPC's move type cannot be stationary! -- ====== Movement & Idle Variables ====== -- ENT.AnimTbl_IdleStand = nil -- The idle animation table when AI is enabled | DEFAULT: {ACT_IDLE} ENT.AnimTbl_Walk = {ACT_WALK} -- Set the walking animations | Put multiple to let the base pick a random animation when it moves ENT.AnimTbl_Run = {ACT_RUN} -- Set the running animations | Put multiple to let the base pick a random animation when it moves ENT.IdleAlwaysWander = false -- If set to true, it will make the SNPC always wander when idling ENT.DisableWandering = false -- Disables wandering when the SNPC is idle ENT.DisableChasingEnemy = false -- Disables the SNPC chasing the enemy -- ====== Constantly Face Enemy Variables ====== -- ENT.ConstantlyFaceEnemy = false -- Should it face the enemy constantly? ENT.ConstantlyFaceEnemy_IfVisible = true -- Should it only face the enemy if it's visible? ENT.ConstantlyFaceEnemy_IfAttacking = false -- Should it face the enemy when attacking? ENT.ConstantlyFaceEnemy_Postures = "Both" -- "Both" = Moving or standing | "Moving" = Only when moving | "Standing" = Only when standing ENT.ConstantlyFaceEnemyDistance = 2500 -- How close does it have to be until it starts to face the enemy? -- ====== Combat Face Enemy Variables ====== -- -- Mostly used by base tasks ENT.CombatFaceEnemy = true -- If enemy exists and is visible -- ====== Pose Parameter Variables ====== -- ENT.HasPoseParameterLooking = true -- Does it look at its enemy using poseparameters? ENT.PoseParameterLooking_CanReset = true -- Should it reset its pose parameters if there is no enemies? ENT.PoseParameterLooking_InvertPitch = false -- Inverts the pitch poseparameters (X) ENT.PoseParameterLooking_InvertYaw = false -- Inverts the yaw poseparameters (Y) ENT.PoseParameterLooking_InvertRoll = false -- Inverts the roll poseparameters (Z) ENT.PoseParameterLooking_TurningSpeed = 10 -- How fast does the parameter turn? ENT.PoseParameterLooking_Names = {pitch={}, yaw={}, roll={}} -- Custom pose parameters to use, can put as many as needed -- ====== Investigation Variables ====== -- -- Showcase: https://www.youtube.com/watch?v=cCqoqSDFyC4 ENT.CanInvestigate = true -- Can it detect and investigate possible enemy disturbances? | EX: Sounds, movement and flashlight ENT.InvestigateSoundDistance = 9 -- How far can the NPC hear sounds? | This number is multiplied by the calculated volume of the detectable sound -- ====== Danger & Grenade Detection Variables ====== -- -- Showcase: https://www.youtube.com/watch?v=XuaMWPTe6rA -- EXAMPLES: Props that are one fire, especially objects like barrels that are about to explode, Combine mine that is triggered and about to explode, The location that the Antlion Worker's spit is going to hit, Combine Flechette that is about to explode, -- Antlion Guard that is charging towards the NPC, Player that is driving a vehicle at high speed towards the NPC, Manhack that has opened its blades, Rollermine that is about to self-destruct, Combine Helicopter that is about to drop bombs or is firing a turret near the NPC, -- Combine Gunship's is about to fire its belly cannon near the NPC, Turret impact locations fired by Combine Gunships, or Combine Dropships, or Striders, The location that a Combine Dropship is going to deploy soldiers, Strider is moving on top of the NPC, -- The location that the Combine or HECU mortar is going to hit, SMG1 grenades that are flying close by, A Combine soldier that is rappelling on top of the NPC, Stalker's laser impact location, Combine APC that is driving towards the NPC ENT.CanDetectDangers = true -- Should the NPC detect dangers? | This includes grenades! ENT.DangerDetectionDistance = 400 -- Max danger detection distance | WARNING: Most of the non-grenade dangers ignore this max value ENT.CanThrowBackDetectedGrenades = true -- Should it pick up the detected grenade and throw it away or to the enemy? -- NOTE: Can only throw grenades away if it has a grenade attack AND can detect dangers -- ====== Taking Cover Variables ====== -- ENT.AnimTbl_TakingCover = {ACT_COVER_LOW} -- The animation it plays when hiding in a covered position ENT.AnimTbl_MoveToCover = {ACT_RUN_CROUCH} -- The animation it plays when moving to a covered position -- ====== Control Variables ====== -- -- Use these variables very careful! One wrong change can mess up the whole SNPC! ENT.FindEnemy_UseSphere = false -- Should the SNPC be able to see all around him? (360) | Objects and walls can still block its sight! ENT.FindEnemy_CanSeeThroughWalls = false -- Should it be able to see through walls and objects? | Can be useful if you want to make it know where the enemy is at all times ENT.DisableFindEnemy = false -- Disables FindEnemy code, friendly code still works though ENT.DisableSelectSchedule = false -- Disables Schedule code, Custom Schedule can still work ENT.DisableTakeDamageFindEnemy = false -- Disable the SNPC finding the enemy when being damaged ENT.DisableTouchFindEnemy = false -- Disable the SNPC finding the enemy when being touched ENT.DisableMakingSelfEnemyToNPCs = false -- Disables the "AddEntityRelationship" that runs in think ENT.TimeUntilEnemyLost = 15 -- Time until it resets its enemy if the enemy is not visible ENT.NextProcessTime = 1 -- Time until it runs the essential part of the AI, which can be performance heavy! -- ====== Miscellaneous Variables ====== -- ENT.DisableInitializeCapabilities = false -- If enabled, all of the Capabilities will be disabled, allowing you to add your own ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Damaged / Injured Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ====== Blood-Related Variables ====== -- -- Leave custom blood tables empty to let the base decide depending on the blood type ENT.Bleeds = true -- Does the SNPC bleed? (Blood decal, particle, etc.) ENT.BloodColor = "" -- The blood type, this will determine what it should use (decal, particle, etc.) -- Types: "Red" || "Yellow" || "Green" || "Orange" || "Blue" || "Purple" || "White" || "Oil" ENT.HasBloodParticle = true -- Does it spawn a particle when damaged? ENT.CustomBlood_Particle = {} -- Particles to spawn when it's damaged ENT.HasBloodPool = true -- Does it have a blood pool? ENT.CustomBlood_Pool = {} -- Blood pool types after it dies ENT.BloodPoolSize = "Normal" -- What's the size of the blood pool? | Sizes: "Normal" || "Small" || "Tiny" ENT.HasBloodDecal = true -- Does it spawn a decal when damaged? ENT.CustomBlood_Decal = {} -- Decals to spawn when it's damaged ENT.BloodDecalUseGMod = false -- Should use the current default decals defined by Garry's Mod? (This only applies for certain blood types only!) ENT.BloodDecalDistance = 150 -- How far the decal can spawn in world units -- ====== Immunity Variables ====== -- ENT.GodMode = false -- Immune to everything ENT.Immune_AcidPoisonRadiation = false -- Immune to Acid, Poison and Radiation ENT.Immune_Bullet = false -- Immune to bullet type damages ENT.Immune_Blast = false -- Immune to explosive-type damages ENT.Immune_Dissolve = false -- Immune to dissolving | Example: Combine Ball ENT.Immune_Electricity = false -- Immune to electrical-type damages | Example: shock or laser ENT.Immune_Fire = false -- Immune to fire-type damages ENT.Immune_Melee = false -- Immune to melee-type damage | Example: Crowbar, slash damages ENT.Immune_Physics = false -- Immune to physics impacts, won't take damage from props ENT.Immune_Sonic = false -- Immune to sonic-type damages ENT.ImmuneDamagesTable = {} -- Makes the SNPC immune to specific type of damages | Takes DMG_ enumerations ENT.GetDamageFromIsHugeMonster = false -- Should it get damaged no matter what by SNPCs that are tagged as VJ_IsHugeMonster? ENT.AllowIgnition = true -- Can this SNPC be set on fire? -- ====== Flinching Variables ====== -- ENT.CanFlinch = 0 -- 0 = Don't flinch | 1 = Flinch at any damage | 2 = Flinch only from certain damages ENT.FlinchDamageTypes = {DMG_BLAST} -- If it uses damage-based flinching, which types of damages should it flinch from? ENT.FlinchChance = 16 -- Chance of it flinching from 1 to x | 1 will make it always flinch -- To let the base automatically detect the animation duration, set this to false: ENT.NextMoveAfterFlinchTime = false -- How much time until it can move, attack, etc. ENT.NextFlinchTime = 5 -- How much time until it can flinch again? ENT.AnimTbl_Flinch = {ACT_FLINCH_PHYSICS} -- If it uses normal based animation, use this ENT.FlinchAnimationDecreaseLengthAmount = 0 -- This will decrease the time it can move, attack, etc. | Use it to fix animation pauses after it finished the flinch animation ENT.HitGroupFlinching_DefaultWhenNotHit = true -- If it uses hitgroup flinching, should it do the regular flinch if it doesn't hit any of the specified hitgroups? ENT.HitGroupFlinching_Values = nil -- EXAMPLES: {{HitGroup = {HITGROUP_HEAD}, Animation = {ACT_FLINCH_HEAD}}, {HitGroup = {HITGROUP_LEFTARM}, Animation = {ACT_FLINCH_LEFTARM}}, {HitGroup = {HITGROUP_RIGHTARM}, Animation = {ACT_FLINCH_RIGHTARM}}, {HitGroup = {HITGROUP_LEFTLEG}, Animation = {ACT_FLINCH_LEFTLEG}}, {HitGroup = {HITGROUP_RIGHTLEG}, Animation = {ACT_FLINCH_RIGHTLEG}}} -- ====== Damage By Player Variables ====== -- ENT.HasDamageByPlayer = true -- Should the SNPC do something when it's hit by a player? Example: Play a sound or animation ENT.DamageByPlayerDispositionLevel = 1 -- 0 = Run it every time | 1 = Run it only when friendly to player | 2 = Run it only when enemy to player ENT.DamageByPlayerTime = VJ_Set(2, 2) -- How much time until it can run the Damage By Player code? -- ====== Call For Back On Damage Variables ====== -- -- NOTE: This AI component only runs when there is NO enemy detected! ENT.CallForBackUpOnDamage = true -- Should the NPC call for help when damaged? ENT.CallForBackUpOnDamageDistance = 800 -- How far away does the call for help go? ENT.CallForBackUpOnDamageLimit = 4 -- How many allies should it call? | 0 = Unlimited ENT.NextCallForBackUpOnDamageTime = VJ_Set(9, 11) -- How much time until it can run this AI component again ENT.CallForBackUpOnDamageAnimation = {ACT_SIGNAL_GROUP} -- Animations played when it calls for help on damage ENT.CallForBackUpOnDamageAnimationTime = false -- How much time until it can use activities | false = Base automatically decides the animation duration ENT.DisableCallForBackUpOnDamageAnimation = false -- Disables the animations from playing -- ====== Move Or Hide On Damage Variables ====== -- ENT.MoveOrHideOnDamageByEnemy = true -- Should the SNPC move or hide when being damaged by an enemy? ENT.MoveOrHideOnDamageByEnemy_OnlyMove = false -- Should it only move and not hide? ENT.MoveOrHideOnDamageByEnemy_HideTime = VJ_Set(3, 4) -- How long should it hide? ENT.NextMoveOrHideOnDamageByEnemy1 = 3 -- How much time until it moves or hides on damage by enemy? | The first # in math.random ENT.NextMoveOrHideOnDamageByEnemy2 = 3.5 -- How much time until it moves or hides on damage by enemy? | The second # in math.random -- ====== Miscellaneous Variables ====== -- ENT.HideOnUnknownDamage = 5 -- number = Hide on unknown damage, defines the time until it can hide again | false = Disable this AI component ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Death & Corpse Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ====== Ally Reaction On Death Variables ====== -- -- Default: Creature base uses BringFriends and Human base uses AlertFriends -- BringFriendsOnDeath takes priority over AlertFriendsOnDeath! ENT.BringFriendsOnDeath = false -- Should the SNPC's friends come to its position before it dies? ENT.BringFriendsOnDeathDistance = 800 -- How far away does the signal go? | Counted in World Units ENT.BringFriendsOnDeathLimit = 3 -- How many people should it call? | 0 = Unlimited ENT.AlertFriendsOnDeath = true -- Should the SNPCs allies get alerted when it dies? | Its allies will also need to have this variable set to true! ENT.AlertFriendsOnDeathDistance = 800 -- How far away does the signal go? | Counted in World Units ENT.AlertFriendsOnDeathLimit = 50 -- How many people should it alert? ENT.AnimTbl_AlertFriendsOnDeath = {ACT_RANGE_ATTACK1} -- Animations it plays when an ally dies that also has AlertFriendsOnDeath set to true -- ====== Death Animation Variables ====== -- ENT.HasDeathAnimation = false -- Does it play an animation when it dies? ENT.AnimTbl_Death = {} -- Death Animations -- To let the base automatically detect the animation duration, set this to false: ENT.DeathAnimationTime = false -- Time until the SNPC spawns its corpse and gets removed ENT.DeathAnimationChance = 1 -- Put 1 if you want it to play the animation all the time ENT.DeathAnimationDecreaseLengthAmount = 0 -- This will decrease the time until it turns into a corpse -- ====== Corpse Variables ====== -- ENT.HasDeathRagdoll = true -- If set to false, it will not spawn the regular ragdoll of the SNPC ENT.DeathCorpseEntityClass = "UseDefaultBehavior" -- The entity class it creates | "UseDefaultBehavior" = Let the base automatically detect the type ENT.DeathCorpseModel = {} -- The corpse model that it will spawn when it dies | Leave empty to use the NPC's model | Put as many models as desired, the base will pick a random one. ENT.DeathCorpseCollisionType = COLLISION_GROUP_DEBRIS -- Collision type for the corpse | SNPC Options Menu can only override this value if it's set to COLLISION_GROUP_DEBRIS! ENT.DeathCorpseSkin = -1 -- Used to override the death skin | -1 = Use the skin that the SNPC had before it died ENT.DeathCorpseSetBodyGroup = true -- Should it get the models bodygroups and set it to the corpse? When set to false, it uses the model's default bodygroups ENT.DeathCorpseBodyGroup = VJ_Set(-1, -1) -- #1 = the category of the first bodygroup | #2 = the value of the second bodygroup | Set -1 for #1 to let the base decide the corpse's bodygroup ENT.DeathCorpseSubMaterials = nil -- Apply a table of indexes that correspond to a sub material index, this will cause the base to copy the NPC's sub material to the corpse. ENT.DeathCorpseFade = false -- Fades the ragdoll on death ENT.DeathCorpseFadeTime = 10 -- How much time until the ragdoll fades | Unit = Seconds ENT.DeathCorpseSetBoneAngles = true -- This can be used to stop the corpse glitching or flying on death ENT.DeathCorpseApplyForce = true -- If false, force will not be applied to the corpse ENT.WaitBeforeDeathTime = 0 -- Time until the SNPC spawns its corpse and gets removed -- ====== Dismemberment/Gib Variables ====== -- ENT.AllowedToGib = true -- Is it allowed to gib in general? This can be on death or when shot in a certain place ENT.HasGibOnDeath = true -- Is it allowed to gib on death? ENT.GibOnDeathDamagesTable = {"UseDefault"} -- Damages that it gibs from | "UseDefault" = Uses default damage types | "All" = Gib from any damage ENT.HasGibOnDeathSounds = true -- Does it have gib sounds? | Mostly used for the settings menu ENT.HasGibDeathParticles = true -- Does it spawn particles on death or when it gibs? | Mostly used for the settings menu -- ====== Item Drops On Death Variables ====== -- ENT.HasItemDropsOnDeath = true -- Should it drop items on death? ENT.ItemDropsOnDeathChance = 14 -- If set to 1, it will always drop it ENT.ItemDropsOnDeath_EntityList = {"weapon_frag", "item_healthvial"} -- List of items it will randomly pick from | Leave it empty to drop nothing or to make your own dropping code (Using CustomOn...) ENT.DropWeaponOnDeath = true -- Should it drop its weapon on death? ENT.DropWeaponOnDeathAttachment = "anim_attachment_RH" -- Which attachment should it use for the weapon's position ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Melee Attack Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.HasMeleeAttack = true -- Should the SNPC have a melee attack? ENT.MeleeAttackDamage = 10 ENT.MeleeAttackDamageType = DMG_CLUB -- Type of Damage ENT.HasMeleeAttackKnockBack = true -- Should knockback be applied on melee hit? | Use self:MeleeAttackKnockbackVelocity() to edit the velocity -- ====== Animation Variables ====== -- ENT.AnimTbl_MeleeAttack = {ACT_MELEE_ATTACK1} -- Melee Attack Animations ENT.MeleeAttackAnimationDelay = 0 -- It will wait certain amount of time before playing the animation ENT.MeleeAttackAnimationFaceEnemy = true -- Should it face the enemy while playing the melee attack animation? ENT.MeleeAttackAnimationDecreaseLengthAmount = 0 -- This will decrease the time until starts chasing again. Use it to fix animation pauses until it chases the enemy. ENT.MeleeAttackAnimationAllowOtherTasks = false -- If set to true, the animation will not stop other tasks from playing, such as chasing | Useful for gesture attacks! -- ====== Distance Variables ====== -- ENT.MeleeAttackDistance = 30 -- How close does it have to be until it attacks? ENT.MeleeAttackAngleRadius = 100 -- What is the attack angle radius? | 100 = In front of the SNPC | 180 = All around the SNPC ENT.MeleeAttackDamageDistance = 70 -- How far does the damage go? ENT.MeleeAttackDamageAngleRadius = 100 -- What is the damage angle radius? | 100 = In front of the SNPC | 180 = All around the SNPC -- ====== Timer Variables ====== -- -- To use event-based attacks, set this to false: ENT.TimeUntilMeleeAttackDamage = 0.5 -- This counted in seconds | This calculates the time until it hits something ENT.NextMeleeAttackTime = 0 -- How much time until it can use a melee attack? ENT.NextMeleeAttackTime_DoRand = false -- False = Don't use random time | Number = Picks a random number between the regular timer and this timer -- To let the base automatically detect the attack duration, set this to false: ENT.NextAnyAttackTime_Melee = false -- How much time until it can use any attack again? | Counted in Seconds ENT.NextAnyAttackTime_Melee_DoRand = false -- False = Don't use random time | Number = Picks a random number between the regular timer and this timer ENT.MeleeAttackReps = 1 -- How many times does it run the melee attack code? ENT.MeleeAttackExtraTimers = nil -- Extra melee attack timers, EX: {1, 1.4} | it will run the damage code after the given amount of seconds ENT.StopMeleeAttackAfterFirstHit = false -- Should it stop the melee attack from running rest of timers when it hits an enemy? -- ====== Control Variables ====== -- ENT.DisableMeleeAttackAnimation = false -- if true, it will disable the animation code ENT.DisableDefaultMeleeAttackCode = false -- When set to true, it will completely disable the melee attack code ENT.DisableDefaultMeleeAttackDamageCode = false -- Disables the default melee attack damage code ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Weapon Attack Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.WeaponSpread = 1 -- What's the spread of the weapon? | Closer to 0 = better accuracy, Farther than 1 = worse accuracy ENT.DisableWeapons = false -- If set to true, it won't be able to use weapons ENT.Weapon_NoSpawnMenu = false -- If set to true, the NPC weapon setting in the spawn menu will not be applied for this SNPC -- ====== Distance Variables ====== -- ENT.Weapon_FiringDistanceFar = 3000 -- How far away it can shoot ENT.Weapon_FiringDistanceClose = 10 -- How close until it stops shooting ENT.HasWeaponBackAway = true -- Should the SNPC back away if the enemy is close? ENT.WeaponBackAway_Distance = 150 -- When the enemy is this close, the SNPC will back away | 0 = Never back away -- ====== Standing-Firing Variables ====== -- ENT.AnimTbl_WeaponAim = nil -- Animations played when the NPC is supposed to raise/aim its weapon | EX: Gun is out of ammo, combat idle, etc.| DEFAULT: {ACT_IDLE_ANGRY} ENT.AnimTbl_WeaponAttack = {ACT_RANGE_ATTACK1} -- Animation played when the SNPC does weapon attack ENT.CanCrouchOnWeaponAttack = true -- Can it crouch while shooting? ENT.AnimTbl_WeaponAttackCrouch = {ACT_RANGE_ATTACK1_LOW} -- Animation played when the SNPC does weapon attack while crouching | For VJ Weapons ENT.CanCrouchOnWeaponAttackChance = 2 -- How much chance of crouching? | 1 = Crouch every time ENT.AnimTbl_WeaponAttackFiringGesture = {ACT_GESTURE_RANGE_ATTACK1} -- Firing Gesture animations used when the SNPC is firing the weapon ENT.DisableWeaponFiringGesture = false -- If set to true, it will disable the weapon firing gestures -- ====== Secondary Fire Variables ====== -- ENT.CanUseSecondaryOnWeaponAttack = true -- Can the NPC use a secondary fire if it's available? ENT.AnimTbl_WeaponAttackSecondary = {"shootAR2alt"} -- Animations played when the SNPC fires a secondary weapon attack ENT.WeaponAttackSecondaryTimeUntilFire = 0.9 -- The weapon uses this integer to set the time until the firing code is ran -- ====== Moving-Firing Variables ====== -- ENT.HasShootWhileMoving = true -- Can it shoot while moving? ENT.AnimTbl_ShootWhileMovingRun = {ACT_RUN_AIM} -- Animations it will play when shooting while running ENT.AnimTbl_ShootWhileMovingWalk = {ACT_WALK_AIM} -- Animations it will play when shooting while walking -- ====== Reloading Variables ====== -- ENT.AllowWeaponReloading = true -- If false, the NPC will not reload ENT.DisableWeaponReloadAnimation = false -- if true, it will disable the animation code when reloading ENT.AnimTbl_WeaponReload = {ACT_RELOAD} -- Animations that play when the NPC reloads ENT.AnimTbl_WeaponReloadBehindCover = {ACT_RELOAD_LOW} -- Animations that play when the NPC reloads, but behind cover ENT.WeaponReload_FindCover = true -- Should it first find cover before reloading? ENT.WeaponReloadAnimationFaceEnemy = true -- Should it face the enemy while playing the weapon reload animation? ENT.WeaponReloadAnimationDecreaseLengthAmount = 0 -- This will decrease the time until it starts moving or attack again. Use it to fix animation pauses until it chases the enemy. ENT.WeaponReloadAnimationDelay = 0 -- It will wait certain amount of time before playing the animation -- ====== Weapon Inventory Variables ====== -- -- Weapons are given on spawn and the NPC will only switch to those if the requirements are met -- The items that are stored in self.WeaponInventory: -- Primary - Default weapon -- AntiArmor - Current enemy is an armored enemy tank/vehicle or a boss -- Melee - Current enemy is (very close and the NPC is out of ammo) OR (in regular melee attack distance) + NPC must have more than 25% health ENT.WeaponInventory_AntiArmor = false -- If true, the NPC will spawn with one of the given weapons (Will only be given the weapon if it already has another!) ENT.WeaponInventory_AntiArmorList = {} -- It will randomly be given one of these weapons ENT.WeaponInventory_Melee = false -- If true, the NPC will spawn with one of the given weapons (Will only be given the weapon if it already has another!) ENT.WeaponInventory_MeleeList = {} -- It will randomly be given one of these weapons -- ====== Move Randomly While Firing Variables ====== -- ENT.MoveRandomlyWhenShooting = true -- Should it move randomly when shooting? ENT.NextMoveRandomlyWhenShootingTime1 = 3 -- How much time until it can move randomly when shooting? | First number in math.random ENT.NextMoveRandomlyWhenShootingTime2 = 6 -- How much time until it can move randomly when shooting? | Second number in math.random -- ====== Wait For Enemy To Come Out Variables ====== -- ENT.WaitForEnemyToComeOut = true -- Should it wait for the enemy to come out from hiding? ENT.WaitForEnemyToComeOutTime = VJ_Set(3, 5) -- How much time should it wait until it starts chasing the enemy? ENT.WaitForEnemyToComeOutDistance = 100 -- If it's this close to the enemy, it won't do it ENT.HasLostWeaponSightAnimation = false -- Set to true if you would like the SNPC to play a different animation when it has lost sight of the enemy and can't fire at it -- ====== Scared Behavior Variables ====== -- ENT.NoWeapon_UseScaredBehavior = true -- Should it use the scared behavior when it sees an enemy and doesn't have a weapon? ENT.AnimTbl_ScaredBehaviorStand = nil -- Animations it will play while scared and standing | Replaces the idle stand animation | DEFAULT: {ACT_COWER} ENT.AnimTbl_ScaredBehaviorMovement = {} -- Animations it will play while scared and moving | Leave empty for the base to decide the animation ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Grenade Attack Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.HasGrenadeAttack = false -- Should the SNPC have a grenade attack? ENT.GrenadeAttackEntity = "obj_vj_grenade" -- The entity that the SNPC throws | Half Life 2 Grenade: "npc_grenade_frag" ENT.GrenadeAttackModel = {} -- Picks a random model from this table to override the model of the grenade ENT.GrenadeAttackAttachment = "anim_attachment_LH" -- The attachment that the grenade will spawn at | false = Custom position -- ====== Animation Variables ====== -- ENT.AnimTbl_GrenadeAttack = {"grenThrow"} -- Grenade Attack Animations ENT.GrenadeAttackAnimationDelay = 0 -- It will wait certain amount of time before playing the animation ENT.GrenadeAttackAnimationFaceEnemy = true -- Should it face the enemy while playing the grenade attack animation? -- ====== Distance & Chance Variables ====== -- ENT.NextThrowGrenadeTime = VJ_Set(10, 15) -- Time until it can throw a grenade again ENT.ThrowGrenadeChance = 4 -- Chance that it will throw the grenade | Set to 1 to throw all the time ENT.GrenadeAttackThrowDistance = 1500 -- How far it can throw grenades ENT.GrenadeAttackThrowDistanceClose = 400 -- How close until it stops throwing grenades -- ====== Timer Variables ====== -- ENT.TimeUntilGrenadeIsReleased = 0.72 -- Time until the grenade is released ENT.GrenadeAttackAnimationStopAttacks = true -- Should it stop attacks for a certain amount of time? -- To let the base automatically detect the attack duration, set this to false: ENT.GrenadeAttackAnimationStopAttacksTime = false -- How long should it stop attacks? ENT.GrenadeAttackFussTime = 3 -- Time until the grenade explodes -- ====== Control Variables ====== -- ENT.DisableGrenadeAttackAnimation = false -- if true, it will disable the animation code when doing grenade attack ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Sound Variables ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.HasSounds = true -- Put to false to disable ALL sounds! -- ====== Footstep Sound / World Shake On Move Variables ====== -- ENT.DisableFootStepSoundTimer = false -- If set to true, it will disable the time system for the footstep sound code, allowing you to use other ways like model events ENT.FootStepTimeRun = 0.5 -- Next foot step sound when it is running ENT.FootStepTimeWalk = 1 -- Next foot step sound when it is walking ENT.DisableFootStepOnRun = false -- It will not play the footstep sound when running ENT.DisableFootStepOnWalk = false -- It will not play the footstep sound when walking ENT.HasWorldShakeOnMove = false -- Should the world shake when it's moving? ENT.WorldShakeOnMoveAmplitude = 10 -- How much the screen will shake | From 1 to 16, 1 = really low 16 = really high ENT.WorldShakeOnMoveRadius = 1000 -- How far the screen shake goes, in world units ENT.WorldShakeOnMoveDuration = 0.4 -- How long the screen shake will last, in seconds ENT.WorldShakeOnMoveFrequency = 100 -- Just leave it to 100 -- ====== Idle Sound Variables ====== -- ENT.IdleSounds_PlayOnAttacks = false -- It will be able to continue and play idle sounds when it performs an attack ENT.IdleSounds_NoRegularIdleOnAlerted = false -- if set to true, it will not play the regular idle sound table if the combat idle sound table is empty -- ====== Idle dialogue Sound Variables ====== -- -- When an allied SNPC or a allied player is in range, the SNPC will play a different sound table. If the ally is a VJ SNPC and has dialogue answer sounds, it will respond to this SNPC ENT.HasIdleDialogueSounds = true -- If set to false, it won't play the idle dialogue sounds ENT.HasIdleDialogueAnswerSounds = true -- If set to false, it won't play the idle dialogue answer sounds ENT.IdleDialogueDistance = 400 -- How close should the ally be for the SNPC to talk to the ally? ENT.IdleDialogueCanTurn = true -- If set to false, it won't turn when a dialogue occurs -- ====== Miscellaneous Variables ====== -- ENT.AlertSounds_OnlyOnce = false -- After it plays it once, it will never play it again ENT.BeforeMeleeAttackSounds_WaitTime = 0 -- Time until it starts playing the Before Melee Attack sounds ENT.OnlyDoKillEnemyWhenClear = true -- If set to true, it will only play the OnKilledEnemy sound when there isn't any other enemies -- ====== Main Control Variables ====== -- ENT.HasFootStepSound = true -- Should the SNPC make a footstep sound when it's moving? ENT.HasBreathSound = true -- Should it make a breathing sound? ENT.HasIdleSounds = true -- If set to false, it won't play the idle sounds ENT.HasOnReceiveOrderSounds = true -- If set to false, it won't play any sound when it receives an order from an ally ENT.HasFollowPlayerSounds_Follow = true -- If set to false, it won't play the follow player sounds ENT.HasFollowPlayerSounds_UnFollow = true -- If set to false, it won't play the unfollow player sounds ENT.HasMoveOutOfPlayersWaySounds = true -- If set to false, it won't play any sounds when it moves out of the player's way ENT.HasMedicSounds_BeforeHeal = true -- If set to false, it won't play any sounds before it gives a med kit to an ally ENT.HasMedicSounds_AfterHeal = true -- If set to false, it won't play any sounds after it gives a med kit to an ally ENT.HasMedicSounds_ReceiveHeal = true -- If set to false, it won't play any sounds when it receives a medkit ENT.HasOnPlayerSightSounds = true -- If set to false, it won't play the saw player sounds ENT.HasInvestigateSounds = true -- If set to false, it won't play any sounds when it's investigating something ENT.HasLostEnemySounds = true -- If set to false, it won't play any sounds when it looses it enemy ENT.HasAlertSounds = true -- If set to false, it won't play the alert sounds ENT.HasCallForHelpSounds = true -- If set to false, it won't play any sounds when it calls for help ENT.HasBecomeEnemyToPlayerSounds = true -- If set to false, it won't play the become enemy to player sounds ENT.HasSuppressingSounds = true -- If set to false, it won't play any sounds when firing a weapon ENT.HasWeaponReloadSounds = true -- If set to false, it won't play any sound when reloading ENT.HasMeleeAttackSounds = true -- If set to false, it won't play the melee attack sound ENT.HasExtraMeleeAttackSounds = false -- Set to true to use the extra melee attack sounds ENT.HasMeleeAttackMissSounds = true -- If set to false, it won't play the melee attack miss sound ENT.HasGrenadeAttackSounds = true -- If set to false, it won't play any sound when doing grenade attack ENT.HasOnGrenadeSightSounds = true -- If set to false, it won't play any sounds when it sees a grenade ENT.HasOnDangerSightSounds = true -- If set to false, it won't play any sounds when it detects a danger ENT.HasOnKilledEnemySound = true -- Should it play a sound when it kills an enemy? ENT.HasAllyDeathSound = true -- Should it paly a sound when an ally dies? ENT.HasPainSounds = true -- If set to false, it won't play the pain sounds ENT.HasImpactSounds = true -- If set to false, it won't play the impact sounds ENT.HasDamageByPlayerSounds = true -- If set to false, it won't play the damage by player sounds ENT.HasDeathSounds = true -- If set to false, it won't play the death sounds ENT.HasSoundTrack = false -- Does the SNPC have a sound track? -- ====== File Path Variables ====== -- -- Leave blank if you don't want any sounds to play ENT.SoundTbl_FootStep = {} ENT.SoundTbl_Breath = {} ENT.SoundTbl_Idle = {} ENT.SoundTbl_IdleDialogue = {} ENT.SoundTbl_IdleDialogueAnswer = {} ENT.SoundTbl_CombatIdle = {} ENT.SoundTbl_OnReceiveOrder = {} ENT.SoundTbl_FollowPlayer = {} ENT.SoundTbl_UnFollowPlayer = {} ENT.SoundTbl_MoveOutOfPlayersWay = {} ENT.SoundTbl_MedicBeforeHeal = {} ENT.SoundTbl_MedicAfterHeal = {} ENT.SoundTbl_MedicReceiveHeal = {} ENT.SoundTbl_OnPlayerSight = {} ENT.SoundTbl_Investigate = {} ENT.SoundTbl_LostEnemy = {} ENT.SoundTbl_Alert = {} ENT.SoundTbl_CallForHelp = {} ENT.SoundTbl_BecomeEnemyToPlayer = {} ENT.SoundTbl_Suppressing = {} ENT.SoundTbl_WeaponReload = {} ENT.SoundTbl_BeforeMeleeAttack = {} ENT.SoundTbl_MeleeAttack = {} ENT.SoundTbl_MeleeAttackExtra = {} ENT.SoundTbl_MeleeAttackMiss = {} ENT.SoundTbl_GrenadeAttack = {} ENT.SoundTbl_OnGrenadeSight = {} ENT.SoundTbl_OnDangerSight = {} ENT.SoundTbl_OnKilledEnemy = {} ENT.SoundTbl_AllyDeath = {} ENT.SoundTbl_Pain = {} ENT.SoundTbl_Impact = {} ENT.SoundTbl_DamageByPlayer = {} ENT.SoundTbl_Death = {} ENT.SoundTbl_SoundTrack = {} ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ ///// WARNING: Don't change anything in this box! \\\\\ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- These are the default file paths in case the user doesn't put one (tables above). local DefaultSoundTbl_FootStep = {"npc/metropolice/gear1.wav","npc/metropolice/gear2.wav","npc/metropolice/gear3.wav","npc/metropolice/gear4.wav","npc/metropolice/gear5.wav","npc/metropolice/gear6.wav"} local DefaultSoundTbl_MedicAfterHeal = {"items/smallmedkit1.wav"} ENT.DefaultSoundTbl_MeleeAttack = {"physics/body/body_medium_impact_hard1.wav","physics/body/body_medium_impact_hard2.wav","physics/body/body_medium_impact_hard3.wav","physics/body/body_medium_impact_hard4.wav","physics/body/body_medium_impact_hard5.wav","physics/body/body_medium_impact_hard6.wav"} local DefaultSoundTbl_MeleeAttackMiss = {"npc/zombie/claw_miss1.wav","npc/zombie/claw_miss2.wav"} local DefaultSoundTbl_Impact = {"physics/flesh/flesh_impact_bullet1.wav","physics/flesh/flesh_impact_bullet2.wav","physics/flesh/flesh_impact_bullet3.wav","physics/flesh/flesh_impact_bullet4.wav","physics/flesh/flesh_impact_bullet5.wav"} ------ ///// WARNING: Don't change anything in this box! \\\\\ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- ====== Fade Out Time Variables ====== -- -- Put to 0 if you want it to stop instantly ENT.SoundTrackFadeOutTime = 2 -- ====== Sound Chance Variables ====== -- -- Higher number = less chance of playing | 1 = Always play ENT.IdleSoundChance = 3 ENT.IdleDialogueAnswerSoundChance = 1 ENT.CombatIdleSoundChance = 1 ENT.OnReceiveOrderSoundChance = 1 ENT.FollowPlayerSoundChance = 1 ENT.UnFollowPlayerSoundChance = 1 ENT.MoveOutOfPlayersWaySoundChance = 2 ENT.MedicBeforeHealSoundChance = 1 ENT.MedicAfterHealSoundChance = 1 ENT.MedicReceiveHealSoundChance = 1 ENT.OnPlayerSightSoundChance = 1 ENT.InvestigateSoundChance = 1 ENT.LostEnemySoundChance = 1 ENT.AlertSoundChance = 1 ENT.CallForHelpSoundChance = 1 ENT.BecomeEnemyToPlayerChance = 1 ENT.BeforeMeleeAttackSoundChance = 1 ENT.MeleeAttackSoundChance = 1 ENT.ExtraMeleeSoundChance = 1 ENT.MeleeAttackMissSoundChance = 1 ENT.GrenadeAttackSoundChance = 1 ENT.OnGrenadeSightSoundChance = 1 ENT.OnDangerSightSoundChance = 1 ENT.SuppressingSoundChance = 2 ENT.WeaponReloadSoundChance = 1 ENT.OnKilledEnemySoundChance = 1 ENT.AllyDeathSoundChance = 4 ENT.PainSoundChance = 1 ENT.ImpactSoundChance = 1 ENT.DamageByPlayerSoundChance = 1 ENT.DeathSoundChance = 1 ENT.SoundTrackChance = 1 -- ====== Timer Variables ====== -- -- Randomized time between the two variables, x amount of time has to pass for the sound to play again | Counted in seconds ENT.NextSoundTime_Breath = true -- true = Base will decide the time | VJ_Set(1, 2) = Custom time ENT.NextSoundTime_Idle = VJ_Set(8, 25) ENT.NextSoundTime_Investigate = VJ_Set(5, 5) ENT.NextSoundTime_LostEnemy = VJ_Set(5, 6) ENT.NextSoundTime_Alert = VJ_Set(2, 3) ENT.NextSoundTime_OnGrenadeSight = VJ_Set(3, 3) ENT.NextSoundTime_OnDangerSight = VJ_Set(3, 3) ENT.NextSoundTime_Suppressing = VJ_Set(7, 15) ENT.NextSoundTime_WeaponReload = VJ_Set(3, 5) ENT.NextSoundTime_OnKilledEnemy = VJ_Set(3, 5) ENT.NextSoundTime_AllyDeath = VJ_Set(3, 5) ENT.NextSoundTime_Pain = true -- true = Base will decide the time | VJ_Set(1, 2) = Custom time ENT.NextSoundTime_DamageByPlayer = VJ_Set(2, 2.3) -- ====== Volume Variables ====== -- -- Number must be between 0 and 1 -- 0 = No sound, 1 = normal/loudest ENT.SoundTrackVolume = 1 -- ====== Sound Level Variables ====== -- -- The proper number are usually range from 0 to 180, though it can go as high as 511 -- More Information: https://developer.valvesoftware.com/wiki/Soundscripts#SoundLevel_Flags ENT.FootStepSoundLevel = 70 ENT.BreathSoundLevel = 60 ENT.IdleSoundLevel = 75 ENT.IdleDialogueSoundLevel = 75 ENT.IdleDialogueAnswerSoundLevel = 75 ENT.CombatIdleSoundLevel = 80 ENT.OnReceiveOrderSoundLevel = 80 ENT.FollowPlayerSoundLevel = 75 ENT.UnFollowPlayerSoundLevel = 75 ENT.MoveOutOfPlayersWaySoundLevel = 75 ENT.BeforeHealSoundLevel = 75 ENT.AfterHealSoundLevel = 75 ENT.MedicReceiveHealSoundLevel = 75 ENT.OnPlayerSightSoundLevel = 75 ENT.InvestigateSoundLevel = 80 ENT.LostEnemySoundLevel = 75 ENT.AlertSoundLevel = 80 ENT.CallForHelpSoundLevel = 80 ENT.BecomeEnemyToPlayerSoundLevel = 75 ENT.BeforeMeleeAttackSoundLevel = 75 ENT.MeleeAttackSoundLevel = 75 ENT.ExtraMeleeAttackSoundLevel = 75 ENT.MeleeAttackMissSoundLevel = 75 ENT.SuppressingSoundLevel = 80 ENT.WeaponReloadSoundLevel = 80 ENT.GrenadeAttackSoundLevel = 80 ENT.OnGrenadeSightSoundLevel = 80 ENT.OnDangerSightSoundLevel = 80 ENT.OnKilledEnemySoundLevel = 80 ENT.AllyDeathSoundLevel = 80 ENT.PainSoundLevel = 80 ENT.ImpactSoundLevel = 60 ENT.DamageByPlayerSoundLevel = 75 ENT.DeathSoundLevel = 80 //ENT.SoundTrackLevel = 0.9 -- ====== Sound Pitch Variables ====== -- -- Range: 0 - 255 | Lower pitch < x > Higher pitch ENT.UseTheSameGeneralSoundPitch = true -- If set to true, the base will decide a number when the NPC spawns and uses it for all sound pitches set to false -- It picks the number between these two variables below: -- These two variables control any sound pitch variable that is set to false ENT.GeneralSoundPitch1 = 90 ENT.GeneralSoundPitch2 = 100 -- To not use the variables above, set the pitch to something other than false ENT.FootStepPitch = VJ_Set(80, 100) ENT.BreathSoundPitch = VJ_Set(100, 100) ENT.IdleSoundPitch = VJ_Set(false, false) ENT.IdleDialogueSoundPitch = VJ_Set(false, false) ENT.IdleDialogueAnswerSoundPitch = VJ_Set(false, false) ENT.CombatIdleSoundPitch = VJ_Set(false, false) ENT.OnReceiveOrderSoundPitch = VJ_Set(false, false) ENT.FollowPlayerPitch = VJ_Set(false, false) ENT.UnFollowPlayerPitch = VJ_Set(false, false) ENT.MoveOutOfPlayersWaySoundPitch = VJ_Set(false, false) ENT.BeforeHealSoundPitch = VJ_Set(false, false) ENT.AfterHealSoundPitch = VJ_Set(100, 100) ENT.MedicReceiveHealSoundPitch = VJ_Set(false, false) ENT.OnPlayerSightSoundPitch = VJ_Set(false, false) ENT.InvestigateSoundPitch = VJ_Set(false, false) ENT.LostEnemySoundPitch = VJ_Set(false, false) ENT.AlertSoundPitch = VJ_Set(false, false) ENT.CallForHelpSoundPitch = VJ_Set(false, false) ENT.BecomeEnemyToPlayerPitch = VJ_Set(false, false) ENT.BeforeMeleeAttackSoundPitch = VJ_Set(false, false) ENT.MeleeAttackSoundPitch = VJ_Set(95, 100) ENT.ExtraMeleeSoundPitch = VJ_Set(80, 100) ENT.MeleeAttackMissSoundPitch = VJ_Set(90, 100) ENT.SuppressingPitch = VJ_Set(false, false) ENT.WeaponReloadSoundPitch = VJ_Set(false, false) ENT.GrenadeAttackSoundPitch = VJ_Set(false, false) ENT.OnGrenadeSightSoundPitch = VJ_Set(false, false) ENT.OnDangerSightSoundPitch = VJ_Set(false, false) ENT.OnKilledEnemySoundPitch = VJ_Set(false, false) ENT.AllyDeathSoundPitch = VJ_Set(false, false) ENT.PainSoundPitch = VJ_Set(false, false) ENT.ImpactSoundPitch = VJ_Set(80, 100) ENT.DamageByPlayerPitch = VJ_Set(false, false) ENT.DeathSoundPitch = VJ_Set(false, false) -- ====== Playback Rate Variables ====== -- -- Decides how fast the sound should play -- Examples: 1 = normal, 2 = twice the normal speed, 0.5 = half the normal speed ENT.SoundTrackPlaybackRate = 1 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ Customization Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -- Use the functions below to customize certain parts of the base or to add new custom systems --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnPreInitialize() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnInitialize() -- self:SetCollisionBounds(Vector(50, 50, 100), Vector(-50, -50, 0)) -- Collision bounds of the NPC | WARNING: All 4 Xs and Ys should be the same! -- self:SetSurroundingBounds(Vector(-300, -300, 0), Vector(300, 300, 500)) -- Damage bounds of the NPC, doesn't effect collision or OBB | NOTE: Only set this if the base one is not good enough! | Use "cl_ent_absbox" to view the bounds end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnThink() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnThink_AIEnabled() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnSetupRelationships(ent, entFri, entDist) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnChangeMovementType(movType) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnIsJumpLegal(startPos, apex, endPos) end -- Return nothing to let base decide, return true to make it jump, return false to disallow jumping --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOn_PoseParameterLookingCode(pitch, yaw, roll) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnSetupWeaponHoldTypeAnims(hType) return false end -- return true to disable the base code --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnSchedule() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnChangeActivity(newAct) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:ExpressionFinished(strExp) end --------------------------------------------------------------------------------------------------------------------------------------------- -- Uncomment to use | Called whenever "VJ_CreateSound" or "VJ_EmitSound" is called | return a new file path to replace the one that is about to play -- function ENT:OnCreateSound(sdFile) return "example/sound.wav" end --------------------------------------------------------------------------------------------------------------------------------------------- -- Uncomment to use | Called whenever a sound starts playing through "VJ_CreateSound" -- function ENT:OnPlayCreateSound(sdData, sdFile) end --------------------------------------------------------------------------------------------------------------------------------------------- -- Uncomment to use | Called whenever a sound starts playing through "VJ_EmitSound" -- function ENT:OnPlayEmitSound(sdFile) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:OnFireBullet(ent, data) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnTouch(ent) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnCondition(cond) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnAcceptInput(key, activator, caller, data) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnHandleAnimEvent(ev, evTime, evCycle, evType, evOptions) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFollowPlayer(ply) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnUnFollowPlayer(ply) end --------------------------------------------------------------------------------------------------------------------------------------------- --[[--------------------------------------------------------- Called every time a change occurs in the eating system - ent = The entity that it is checking OR speaking with - status = The change that occurred, possible changes: - "CheckEnt" = Possible friendly entity found, should we speak to it? | return anything other than nil or "false" to skip and not speak to this entity! - "Speak" = Everything passed, start speaking - "Answer" = Another entity has spoken to me, answer back! | return anything other than nil or "false" to not play an answer back dialogue! - statusInfo = Some status may have extra info, possible infos: - For "CheckEnt" = Boolean value, whether or not the entity can answer back - For "Speak" = Duration of our sentence Returns - ONLY used for "CheckEnt" & "Answer" | Check above for what each status return does -----------------------------------------------------------]] function ENT:CustomOnIdleDialogue(ent, status, statusInfo) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMedic_BeforeHeal() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMedic_OnHeal(ent) return true end -- Return false to NOT update its ally's health and NOT clear its decals, allowing to custom code it --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMedic_OnReset() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnPlayerSight(ent) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFootStepSound() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFootStepSound_Run() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFootStepSound_Walk() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnWorldShakeOnMove() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDoChangeWeapon(newWeapon, oldWeapon, invSwitch) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnInvestigate(ent) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnResetEnemy() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnAlert(ent) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnCallForHelp(ally) end --------------------------------------------------------------------------------------------------------------------------------------------- -- The NPC's sight direction | Used by main sight angle, all attack angle radiuses, etc. function ENT:GetSightDirection() //return self:GetAttachment(self:LookupAttachment("mouth")).Ang:Forward() -- Attachment example //return select(2, self:GetBonePosition(self:LookupBone("bip01 head"))):Forward() -- Bone example return self:GetForward() -- Make sure to return a direction! end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:GetDynamicOrigin() return self:GetPos() + self:GetForward() -- Override this to use a different position end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomAttack(ene, eneVisible) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMeleeAttack_BeforeStartTimer(seed) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMeleeAttack_AfterStartTimer(seed) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMeleeAttack_BeforeChecks() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:GetMeleeAttackDamageOrigin() return self:GetPos() + self:GetForward() -- Override this to use a different position end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMeleeAttack_AfterChecks(hitEnt, isProp) return false end -- return true to disable the attack and move onto the next entity! --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:MeleeAttackKnockbackVelocity(hitEnt) return self:GetForward()*math.random(100, 140) + self:GetUp()*10 end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMeleeAttack_Miss() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnIsAbleToShootWeapon() return true -- Set this to false to disallow shooting end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnWeaponAttack() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMoveRandomlyWhenShooting() end -- Returning false will disable the base code --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnWaitForEnemyToComeOut() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnWeaponReload() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnWeaponReload_AfterRanToCover() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnGrenadeAttack_BeforeStartTimer() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnGrenadeAttack_SpawnPosition() return self:GetPos() end -- if self.GrenadeAttackAttachment is set to false, it will use the returned position here! --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnGrenadeAttack_ThrowVelocity(grEnt, grTargetPos) return (grTargetPos - grEnt:GetPos()) + (self:GetUp()*200 + self:GetForward()*500 + self:GetRight()*math.Rand(-20, 20)) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnGrenadeAttack_OnThrow(grEnt) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDoKilledEnemy(ent, attacker, inflictor) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnTakeDamage_BeforeImmuneChecks(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnTakeDamage_BeforeDamage(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnTakeDamage_AfterDamage(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnTakeDamage_OnBleed(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFlinch_BeforeFlinch(dmginfo, hitgroup) end -- Return false to disallow the flinch from playing --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnFlinch_AfterFlinch(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDamageByPlayer(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnBecomeEnemyToPlayer(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnSetEnemyOnDamage(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:SetUpGibesOnDeath(dmginfo, hitgroup) return false -- Return to true if it gibbed! /*-------------------------------------- -- Extra Features -- Extra features allow you to have more control over the gibbing system. --/// Types \\\-- AllowCorpse -- Should it allow corpse to spawn? DeathAnim -- Should it allow death animation? --/// Implementing it \\\-- 1. Let's use type DeathAnim as an example. NOTE: You can have as many types as you want! 2. Put a comma next to return. ===> return true, 3. Make a table after the comma. ===> return true, {} 4. Put the type(s) that you want. ===> return true, {DeathAnim=true} 5. And you are done! Example with multiple types: ===> return true, {DeathAnim=true,AllowCorpse=true} --------------------------------------*/ end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomGibOnDeathSounds(dmginfo, hitgroup) return true end -- returning false will make the default gibbing sounds not play --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnAllyDeath(ent) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnInitialKilled(dmginfo, hitgroup) end -- Ran the moment the NPC dies! --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnPriorToKilled(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomDeathAnimationCode(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnKilled(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomRareDropsOnDeathCode(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDropWeapon(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDropWeapon_AfterWeaponSpawned(dmginfo, hitgroup, wepEnt) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDeath_BeforeCorpseSpawned(dmginfo, hitgroup) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnDeath_AfterCorpseSpawned(dmginfo, hitgroup, corpseEnt) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnRemove() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:Controller_Initialize(ply, controlEnt) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:Controller_IntMsg(ply, controlEnt) //ply:ChatPrint("CTRL + MOUSE2: Rocket Attack") -- Example end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------ ///// WARNING: Don't touch anything below this line! \\\\\ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ENT.Alerted = false ENT.Dead = false ENT.Flinching = false ENT.vACT_StopAttacks = false ENT.IsFollowing = false ENT.FollowingPlayer = false ENT.VJ_IsBeingControlled = false ENT.VJ_PlayingSequence = false ENT.PlayingAttackAnimation = false ENT.DoingWeaponAttack = false ENT.DoingWeaponAttack_Standing = false ENT.WaitingForEnemyToComeOut = false ENT.VJ_DEBUG = false ENT.DidWeaponAttackAimParameter = false ENT.Medic_Status = false -- false = Not active | "Active" = Attempting to heal ally (Going after etc.) | "Healing" = Has reached ally and is healing it ENT.VJ_PlayingInterruptSequence = false ENT.IsAbleToMeleeAttack = true ENT.AllowToDo_WaitForEnemyToComeOut = true ENT.HasBeenGibbedOnDeath = false ENT.DeathAnimationCodeRan = false ENT.VJ_IsBeingControlled_Tool = false ENT.WeaponUseEnemyEyePos = false ENT.LastHiddenZone_CanWander = true ENT.NoWeapon_UseScaredBehavior_Active = false ENT.CurIdleStandMove = false ENT.CurrentWeaponAnimationIsAim = false ENT.VJ_TheController = NULL ENT.VJ_TheControllerEntity = NULL ENT.VJ_TheControllerBullseye = NULL ENT.Medic_CurrentEntToHeal = NULL ENT.Medic_SpawnedProp = NULL ENT.CurrentWeaponEntity = NULL ENT.LastPlayedVJSound = nil ENT.NextDangerDetectionT = 0 ENT.NextFollowUpdateT = 0 ENT.AngerLevelTowardsPlayer = 0 ENT.NextBreathSoundT = 0 ENT.FootStepT = 0 ENT.PainSoundT = 0 ENT.AllyDeathSoundT = 0 ENT.WorldShakeWalkT = 0 ENT.NextIdleSoundT = 0 ENT.NextNoWeaponT = 0 ENT.NextCallForHelpT = 0 ENT.NextProcessT = 0 ENT.NextThrowGrenadeT = 0 ENT.NextCallForBackUpOnDamageT = 0 ENT.NextOnGrenadeSightSoundT = 0 ENT.NextOnDangerSightSoundT = 0 ENT.NextMoveOrHideOnDamageByEnemyT = 0 ENT.NextAlertSoundT = 0 ENT.NextCallForHelpAnimationT = 0 ENT.CurrentAttackAnimation = 0 ENT.CurrentAttackAnimationDuration = 0 ENT.NextIdleTime = 0 ENT.NextChaseTime = 0 ENT.OnPlayerSightNextT = 0 ENT.NextDamageByPlayerT = 0 ENT.NextDamageByPlayerSoundT = 0 ENT.NextWeaponReloadSoundT = 0 ENT.Medic_NextHealT = 0 ENT.Weapon_TimeSinceLastShot = 0 ENT.NextMoveRandomlyWhenShootingT = 0 ENT.NextWeaponAttackT = 0 ENT.NextMeleeWeaponAttackT = 0 ENT.CurrentWeaponAnimation = -1 ENT.NextGrenadeAttackSoundT = 0 ENT.CurrentAnim_IdleStand = 0 ENT.NextSuppressingSoundT = 0 ENT.TakingCoverT = 0 ENT.NextFlinchT = 0 ENT.NextCanGetCombineBallDamageT = 0 ENT.UseTheSameGeneralSoundPitch_PickedNumber = 0 ENT.OnKilledEnemySoundT = 0 ENT.LastHiddenZoneT = 0 ENT.NextIdleStandTime = 0 ENT.NextMoveOnGunCoveredT = 0 ENT.NextWanderTime = 0 ENT.Weapon_DoingCrouchAttackT = 0 ENT.NextInvestigationMove = 0 ENT.NextInvestigateSoundT = 0 ENT.NextCallForHelpSoundT = 0 ENT.LostEnemySoundT = 0 ENT.NextDoAnyAttackT = 0 ENT.NearestPointToEnemyDistance = 0 ENT.LatestEnemyDistance = 0 ENT.HealthRegenerationDelayT = 0 ENT.NextWeaponAttackT_Base = 0 -- This is handled by the base, used to avoid running shoot animation twice ENT.CurAttackSeed = 0 ENT.CurAnimationSeed = 0 ENT.GuardingPosition = nil ENT.GuardingFacePosition = nil ENT.SelectedDifficulty = 1 ENT.ModelAnimationSet = VJ_MODEL_ANIMSET_NONE ENT.AIState = VJ_STATE_NONE ENT.AttackType = VJ_ATTACK_NONE ENT.AttackStatus = VJ_ATTACK_STATUS_NONE ENT.WeaponState = VJ_WEP_STATE_READY ENT.WeaponInventoryStatus = VJ_WEP_INVENTORY_NONE ENT.FacingStatus = VJ_FACING_NONE ENT.FacingData = nil ENT.TimersToRemove = {"timer_weapon_state_reset","timer_state_reset","timer_act_seqreset","timer_facing_end","timer_act_flinching","timer_act_playingattack","timer_act_stopattacks","timer_melee_finished","timer_melee_start","timer_melee_finished_abletomelee","timer_reload_end","timer_alerted_reset"} ENT.FollowData = {Ent = NULL, MinDist = 0, Moving = false, StopAct = false} ENT.EnemyData = { TimeSet = 0, -- Last time an enemy was set | Updated whenever "VJ_DoSetEnemy" is ran successfully TimeSinceAcquired = 0, -- Time since it acquired an enemy (Switching enemies does NOT reset this!) IsVisible = false, -- Is the enemy visible? | Updated every "Think" run! LastVisibleTime = 0, -- Last time it saw the current enemy LastVisiblePos = Vector(0, 0, 0), -- Last visible position of the current enemy VisibleCount = 0, -- Number of visible enemies SightDiff = 0, -- Difference between enemy's position and NPC's sight direction | Examples: Determine if the enemy is within the NPC's sight angle or melee attack radius Reset = true, -- Enemy has reset | Mostly a backend function } //ENT.DefaultGibOnDeathDamageTypes = {[DMG_ALWAYSGIB]=true,[DMG_ENERGYBEAM]=true,[DMG_BLAST]=true,[DMG_VEHICLE]=true,[DMG_CRUSH]=true,[DMG_DISSOLVE]=true,[DMG_SLOWBURN]=true,[DMG_PHYSGUN]=true,[DMG_PLASMA]=true,[DMG_SONIC]=true} //ENT.SavedDmgInfo = {} -- Set later -- Localized static values local destructibleEnts = {func_breakable=true, func_physbox=true, prop_door_rotating=true} // func_breakable_surf local defPos = Vector(0, 0, 0) local defAng = Angle(0, 0, 0) local IsProp = VJ_IsProp local CurTime = CurTime local IsValid = IsValid local GetConVar = GetConVar local isstring = isstring local isnumber = isnumber local tonumber = tonumber local math_clamp = math.Clamp local math_rad = math.rad local math_cos = math.cos local math_angApproach = math.ApproachAngle local math_angDif = math.AngleDifference local varCAnt = "CLASS_ANTLION" local varCCom = "CLASS_COMBINE" local varCZom = "CLASS_ZOMBIE" --------------------------------------------------------------------------------------------------------------------------------------------- local function ConvarsOnInit(self) --<>-- Convars that run on Initialize --<>-- if GetConVar("vj_npc_usedevcommands"):GetInt() == 1 then self.VJ_DEBUG = true end self.NextProcessTime = GetConVar("vj_npc_processtime"):GetInt() if GetConVar("vj_npc_sd_nosounds"):GetInt() == 1 then self.HasSounds = false end if GetConVar("vj_npc_vjfriendly"):GetInt() == 1 then self:VJTags_Add(VJ_TAG_VJ_FRIENDLY) end if GetConVar("vj_npc_playerfriendly"):GetInt() == 1 then self.PlayerFriendly = true end if GetConVar("vj_npc_antlionfriendly"):GetInt() == 1 then self.VJ_NPC_Class[#self.VJ_NPC_Class + 1] = varCAnt end if GetConVar("vj_npc_combinefriendly"):GetInt() == 1 then self.VJ_NPC_Class[#self.VJ_NPC_Class + 1] = varCCom end if GetConVar("vj_npc_zombiefriendly"):GetInt() == 1 then self.VJ_NPC_Class[#self.VJ_NPC_Class + 1] = varCZom end if GetConVar("vj_npc_noallies"):GetInt() == 1 then self.HasAllies = false self.PlayerFriendly = false end if GetConVar("vj_npc_nocorpses"):GetInt() == 1 then self.HasDeathRagdoll = false end if GetConVar("vj_npc_itemdrops"):GetInt() == 0 then self.HasItemDropsOnDeath = false end if GetConVar("vj_npc_nowandering"):GetInt() == 1 then self.DisableWandering = true end if GetConVar("vj_npc_nochasingenemy"):GetInt() == 1 then self.DisableChasingEnemy = true end if GetConVar("vj_npc_noflinching"):GetInt() == 1 then self.CanFlinch = false end if GetConVar("vj_npc_nomelee"):GetInt() == 1 then self.HasMeleeAttack = false end if GetConVar("vj_npc_nobleed"):GetInt() == 1 then self.Bleeds = false end if GetConVar("vj_npc_godmodesnpc"):GetInt() == 1 then self.GodMode = true end if GetConVar("vj_npc_noreload"):GetInt() == 1 then self.AllowWeaponReloading = false end if GetConVar("vj_npc_nobecomeenemytoply"):GetInt() == 1 then self.BecomeEnemyToPlayer = false end if GetConVar("vj_npc_nocallhelp"):GetInt() == 1 then self.CallForHelp = false end if GetConVar("vj_npc_noeating"):GetInt() == 1 then self.CanEat = false end if GetConVar("vj_npc_nofollowplayer"):GetInt() == 1 then self.FollowPlayer = false end if GetConVar("vj_npc_nosnpcchat"):GetInt() == 1 then self.AllowPrintingInChat = false end if GetConVar("vj_npc_noweapon"):GetInt() == 1 then self.DisableWeapons = true end if GetConVar("vj_npc_nothrowgrenade"):GetInt() == 1 then self.HasGrenadeAttack = false end if GetConVar("vj_npc_nodangerdetection"):GetInt() == 1 then self.CanDetectDangers = false end if GetConVar("vj_npc_dropweapon"):GetInt() == 0 then self.DropWeaponOnDeath = false end if GetConVar("vj_npc_nomedics"):GetInt() == 1 then self.IsMedicSNPC = false end if GetConVar("vj_npc_novfx_gibdeath"):GetInt() == 1 then self.HasGibDeathParticles = false end if GetConVar("vj_npc_nogib"):GetInt() == 1 then self.AllowedToGib = false self.HasGibOnDeath = false end if GetConVar("vj_npc_usegmoddecals"):GetInt() == 1 then self.BloodDecalUseGMod = true end if GetConVar("vj_npc_knowenemylocation"):GetInt() == 1 then self.FindEnemy_UseSphere = true self.FindEnemy_CanSeeThroughWalls = true end if GetConVar("vj_npc_sd_gibbing"):GetInt() == 1 then self.HasGibOnDeathSounds = false end if GetConVar("vj_npc_sd_soundtrack"):GetInt() == 1 then self.HasSoundTrack = false end if GetConVar("vj_npc_sd_footstep"):GetInt() == 1 then self.HasFootStepSound = false end if GetConVar("vj_npc_sd_idle"):GetInt() == 1 then self.HasIdleSounds = false end if GetConVar("vj_npc_sd_breath"):GetInt() == 1 then self.HasBreathSound = false end if GetConVar("vj_npc_sd_alert"):GetInt() == 1 then self.HasAlertSounds = false end if GetConVar("vj_npc_sd_ondangersight"):GetInt() == 1 then self.HasOnGrenadeSightSounds = false self.HasOnDangerSightSounds = false end if GetConVar("vj_npc_sd_meleeattack"):GetInt() == 1 then self.HasMeleeAttackSounds = false self.HasExtraMeleeAttackSounds = false end if GetConVar("vj_npc_sd_meleeattackmiss"):GetInt() == 1 then self.HasMeleeAttackMissSounds = false end if GetConVar("vj_npc_sd_pain"):GetInt() == 1 then self.HasPainSounds = false end if GetConVar("vj_npc_sd_death"):GetInt() == 1 then self.HasDeathSounds = false end if GetConVar("vj_npc_sd_followplayer"):GetInt() == 1 then self.HasFollowPlayerSounds_Follow = false self.HasFollowPlayerSounds_UnFollow = false end if GetConVar("vj_npc_sd_becomenemytoply"):GetInt() == 1 then self.HasBecomeEnemyToPlayerSounds = false end if GetConVar("vj_npc_sd_damagebyplayer"):GetInt() == 1 then self.HasDamageByPlayerSounds = false end if GetConVar("vj_npc_sd_onplayersight"):GetInt() == 1 then self.HasOnPlayerSightSounds = false end if GetConVar("vj_npc_sd_medic"):GetInt() == 1 then self.HasMedicSounds_BeforeHeal = false self.HasMedicSounds_AfterHeal = false self.HasMedicSounds_ReceiveHeal = false end if GetConVar("vj_npc_sd_reload"):GetInt() == 1 then self.HasWeaponReloadSounds = false end if GetConVar("vj_npc_sd_grenadeattack"):GetInt() == 1 then self.HasGrenadeAttackSounds = false end if GetConVar("vj_npc_sd_suppressing"):GetInt() == 1 then self.HasSuppressingSounds = false end if GetConVar("vj_npc_sd_callforhelp"):GetInt() == 1 then self.HasCallForHelpSounds = false end if GetConVar("vj_npc_sd_onreceiveorder"):GetInt() == 1 then self.HasOnReceiveOrderSounds = false end local corpseCollision = GetConVar("vj_npc_corpsecollision"):GetInt() if corpseCollision != 0 && self.DeathCorpseCollisionType == COLLISION_GROUP_DEBRIS then if corpseCollision == 1 then self.DeathCorpseCollisionType = COLLISION_GROUP_NONE elseif corpseCollision == 2 then self.DeathCorpseCollisionType = COLLISION_GROUP_WORLD elseif corpseCollision == 3 then self.DeathCorpseCollisionType = COLLISION_GROUP_INTERACTIVE elseif corpseCollision == 4 then self.DeathCorpseCollisionType = COLLISION_GROUP_WEAPON elseif corpseCollision == 5 then self.DeathCorpseCollisionType = COLLISION_GROUP_PASSABLE_DOOR elseif corpseCollision == 6 then self.DeathCorpseCollisionType = COLLISION_GROUP_NONE end end end --------------------------------------------------------------------------------------------------------------------------------------------- local defIdleTbl = {ACT_IDLE} local defWeaponAimTbl = {ACT_IDLE_ANGRY} local defScaredStandTbl = {ACT_COWER} -- function ENT:Initialize() if self.AnimTbl_IdleStand == nil then self.AnimTbl_IdleStand = defIdleTbl end if self.AnimTbl_WeaponAim == nil then self.AnimTbl_WeaponAim = defWeaponAimTbl end if self.AnimTbl_ScaredBehaviorStand == nil then self.AnimTbl_ScaredBehaviorStand = defScaredStandTbl end self:CustomOnPreInitialize() self:SetSpawnEffect(false) self:SetRenderMode(RENDERMODE_NORMAL) // RENDERMODE_TRANSALPHA self:AddEFlags(EFL_NO_DISSOLVE) self:SetUseType(SIMPLE_USE) if self:GetName() == "" then self:SetName((self.PrintName == "" and list.Get("NPC")[self:GetClass()].Name) or self.PrintName) end self.SelectedDifficulty = GetConVar("vj_npc_difficulty"):GetInt() if VJ_PICK(self.Model) != false then self:SetModel(VJ_PICK(self.Model)) end if self.HasHull == true then self:SetHullType(self.HullType) end if self.HullSizeNormal == true then self:SetHullSizeNormal() end if self.HasSetSolid == true then self:SetSolid(SOLID_BBOX) end // SOLID_OBB self:SetCollisionGroup(COLLISION_GROUP_NPC) //self:SetCustomCollisionCheck() -- Used for the hook GM:ShouldCollide, not reliable! self:SetMaxYawSpeed(self.TurningSpeed) ConvarsOnInit(self) self:DoChangeMovementType() if self.SetSurroundingBoundsType then -- !!!!!!!!!!!!!! Outdated GMod Compatibility! !!!!!!!!!!!!!! self:SetSurroundingBoundsType(BOUNDS_HITBOXES) // BOUNDS_COLLISION end self.ExtraCorpsesToRemove_Transition = {} self.VJ_AddCertainEntityAsEnemy = {} self.VJ_AddCertainEntityAsFriendly = {} self.CurrentPossibleEnemies = {} self.WeaponAnimTranslations = {} self.WeaponInventory = {} self.NextThrowGrenadeT = CurTime() + math.Rand(1, 5) self.NextIdleSoundT_RegularChange = CurTime() + math.random(0.3, 6) self.UseTheSameGeneralSoundPitch_PickedNumber = (self.UseTheSameGeneralSoundPitch and math.random(self.GeneralSoundPitch1, self.GeneralSoundPitch2)) or 0 self:SetupBloodColor(self.BloodColor) if self.Behavior == VJ_BEHAVIOR_PASSIVE or self.Behavior == VJ_BEHAVIOR_PASSIVE_NATURE then self.DisableWeapons = true self.Weapon_NoSpawnMenu = true end if self.DisableInitializeCapabilities == false then self:SetInitializeCapabilities() end self:SetHealth((GetConVar("vj_npc_allhealth"):GetInt() > 0) and GetConVar("vj_npc_allhealth"):GetInt() or self:VJ_GetDifficultyValue(self.StartHealth)) self.StartHealth = self:Health() //if self.HasSquad == true then self:Fire("setsquad", self.SquadName, 0) end self:CustomOnInitialize() self:CustomInitialize() -- !!!!!!!!!!!!!! DO NOT USE THIS FUNCTION !!!!!!!!!!!!!! [Backwards Compatibility!] self.NextWanderTime = ((self.NextWanderTime != 0) and self.NextWanderTime) or (CurTime() + (self.IdleAlwaysWander and 0 or 1)) -- If self.NextWanderTime isn't given a value THEN if self.IdleAlwaysWander isn't true, wait at least 1 sec before wandering self.SightDistance = (GetConVar("vj_npc_seedistance"):GetInt() > 0) and GetConVar("vj_npc_seedistance"):GetInt() or self.SightDistance timer.Simple(0.15, function() if IsValid(self) then self:SetSightDistance(self.SightDistance) if self:GetNPCState() <= NPC_STATE_NONE then self:SetNPCState(NPC_STATE_IDLE) end if IsValid(self:GetCreator()) && self:GetCreator():GetInfoNum("vj_npc_spawn_guard", 0) == 1 then self.IsGuard = true end self:StartSoundTrack() -- pitch if self:LookupPoseParameter("aim_pitch") then self.PoseParameterLooking_Names.pitch[#self.PoseParameterLooking_Names.pitch + 1] = "aim_pitch" end if self:LookupPoseParameter("head_pitch") then self.PoseParameterLooking_Names.pitch[#self.PoseParameterLooking_Names.pitch + 1] = "head_pitch" end -- yaw if self:LookupPoseParameter("aim_yaw") then self.PoseParameterLooking_Names.yaw[#self.PoseParameterLooking_Names.yaw + 1] = "aim_yaw" end if self:LookupPoseParameter("head_yaw") then self.PoseParameterLooking_Names.yaw[#self.PoseParameterLooking_Names.yaw + 1] = "head_yaw" end -- roll if self:LookupPoseParameter("aim_roll") then self.PoseParameterLooking_Names.roll[#self.PoseParameterLooking_Names.roll + 1] = "aim_roll" end if self:LookupPoseParameter("head_roll") then self.PoseParameterLooking_Names.roll[#self.PoseParameterLooking_Names.roll + 1] = "head_roll" end end end) duplicator.RegisterEntityClass(self:GetClass(), VJ.CreateDupe_NPC, "Class", "Equipment", "SpawnFlags", "Data") if !self.DisableWeapons then timer.Simple(0.1, function() if IsValid(self) then local wep = self:GetActiveWeapon() if IsValid(wep) then self.WeaponInventory.Primary = wep if IsValid(self:GetCreator()) && self.AllowPrintingInChat == true && !wep.IsVJBaseWeapon then self:GetCreator():PrintMessage(HUD_PRINTTALK, "WARNING: "..self:GetName().." requires a VJ Base weapon to work properly!") end if self.WeaponInventory_AntiArmor == true then local antiArmor = VJ_PICK(self.WeaponInventory_AntiArmorList) if antiArmor != false && wep:GetClass() != antiArmor then -- If the list isn't empty and it's not the current active weapon self.WeaponInventory.AntiArmor = self:Give(antiArmor) end self:SelectWeapon(wep) -- Change the weapon back to the original weapon wep:Equip(self) end if self.WeaponInventory_Melee == true then local melee = VJ_PICK(self.WeaponInventory_MeleeList) if melee != false && wep:GetClass() != melee then -- If the list isn't empty and it's not the current active weapon self.WeaponInventory.Melee = self:Give(melee) end self:SelectWeapon(wep) -- Change the weapon back to the original weapon wep:Equip(self) end elseif IsValid(self:GetCreator()) && self.AllowPrintingInChat == true && self.Weapon_NoSpawnMenu == false then self:GetCreator():PrintMessage(HUD_PRINTTALK, "WARNING: "..self:GetName().." needs a weapon!") end end end) end //self:SetSaveValue("m_debugOverlays", 1) -- Enables source engine debug overlays (some commands like 'npc_conditions' need it) end -- !!!!!!!!!!!!!! DO NOT USE THESE !!!!!!!!!!!!!! [Backwards Compatibility!] ENT.MeleeAttacking = false ENT.ThrowingGrenade = false function ENT:CustomInitialize() end function ENT:SetNearestPointToEntityPosition() return self:GetDynamicOrigin() end function ENT:SetMeleeAttackDamagePosition() return self:GetMeleeAttackDamageOrigin() end -- !!!!!!!!!!!!!!!!!!!!!!!!!!!! --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:SetInitializeCapabilities() self:CapabilitiesAdd(bit.bor(CAP_SKIP_NAV_GROUND_CHECK)) self:CapabilitiesAdd(bit.bor(CAP_ANIMATEDFACE)) self:CapabilitiesAdd(bit.bor(CAP_TURN_HEAD)) if self.CanOpenDoors == true then self:CapabilitiesAdd(bit.bor(CAP_OPEN_DOORS)) self:CapabilitiesAdd(bit.bor(CAP_AUTO_DOORS)) self:CapabilitiesAdd(bit.bor(CAP_USE)) end self:CapabilitiesAdd(bit.bor(CAP_DUCK)) //if self.HasSquad == true then self:CapabilitiesAdd(bit.bor(CAP_SQUAD)) end if self.DisableWeapons == false && self.Weapon_NoSpawnMenu == false then self:CapabilitiesAdd(bit.bor(CAP_USE_WEAPONS)) self:CapabilitiesAdd(bit.bor(CAP_WEAPON_RANGE_ATTACK1)) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:DoChangeMovementType(movType) movType = movType or -1 if movType != -1 then self.MovementType = movType end if self.MovementType == VJ_MOVETYPE_GROUND then self:RemoveFlags(FL_FLY) self:SetNavType(NAV_GROUND) self:SetMoveType(MOVETYPE_STEP) self:CapabilitiesRemove(CAP_MOVE_FLY) self:CapabilitiesAdd(bit.bor(CAP_MOVE_GROUND)) if (VJ_AnimationExists(self,ACT_JUMP) == true && GetConVar("vj_npc_human_canjump"):GetInt() == 1) or self.UsePlayerModelMovement == true then self:CapabilitiesAdd(bit.bor(CAP_MOVE_JUMP)) end //if VJ_AnimationExists(self,ACT_CLIMB_UP) == true then self:CapabilitiesAdd(bit.bor(CAP_MOVE_CLIMB)) end if self.DisableWeapons == false then self:CapabilitiesAdd(bit.bor(CAP_MOVE_SHOOT)) end elseif self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:SetGroundEntity(NULL) self:AddFlags(FL_FLY) self:SetNavType(NAV_FLY) self:SetMoveType(MOVETYPE_STEP) // MOVETYPE_FLY, causes issues like Lerp functions not being smooth self:CapabilitiesRemove(CAP_MOVE_GROUND) self:CapabilitiesRemove(CAP_MOVE_JUMP) self:CapabilitiesRemove(CAP_MOVE_CLIMB) self:CapabilitiesRemove(CAP_MOVE_SHOOT) self:CapabilitiesAdd(bit.bor(CAP_MOVE_FLY)) elseif self.MovementType == VJ_MOVETYPE_STATIONARY then self:RemoveFlags(FL_FLY) self:SetNavType(NAV_NONE) if self.Stationary_UseNoneMoveType == true then self:SetMoveType(MOVETYPE_NONE) else self:SetMoveType(MOVETYPE_FLY) end self:CapabilitiesRemove(CAP_MOVE_GROUND) self:CapabilitiesRemove(CAP_MOVE_JUMP) self:CapabilitiesRemove(CAP_MOVE_CLIMB) self:CapabilitiesRemove(CAP_MOVE_SHOOT) self:CapabilitiesRemove(CAP_MOVE_FLY) elseif self.MovementType == VJ_MOVETYPE_PHYSICS then self:RemoveFlags(FL_FLY) self:SetNavType(NAV_NONE) self:SetMoveType(MOVETYPE_VPHYSICS) self:CapabilitiesRemove(CAP_MOVE_GROUND) self:CapabilitiesRemove(CAP_MOVE_JUMP) self:CapabilitiesRemove(CAP_MOVE_CLIMB) self:CapabilitiesRemove(CAP_MOVE_SHOOT) self:CapabilitiesRemove(CAP_MOVE_FLY) end self:CustomOnChangeMovementType(movType) end --------------------------------------------------------------------------------------------------------------------------------------------- --[[--------------------------------------------------------- The main animation function, it can play activities, sequences and gestures - animation = The animation to play, it can be a table OR string OR ACT_* - Adding "vjseq_" to a string will make it play as a sequence - Adding "vjges_" to a string will make it play as a gesture - If it's a string AND "vjseq_" or "vjges_" is NOT added: - The base will attempt to convert it activity, if it fails, it will play it as a sequence - This behavior can be overridden by AlwaysUseSequence & AlwaysUseGesture options - stopActivities = If true, it will stop activities such as idle, chasing, attacking, etc. for a given amount of time | DEFAULT: false - stopActivitiesTime = How long it will stop the activities such as idle, chasing, attacking, etc. | DEFAULT: 0 - false = Base calculates the time (recommended) - faceEnemy = Should it constantly face the enemy while playing this animation? | DEFAULT: false - animDelay = Delays the animation by the given number | DEFAULT: 0 - extraOptions = Table that holds extra options to modify parts of the code - OnFinish(interrupted, anim) = A function that runs when the animation finishes | DEFAULT: nil - interrupted = Was the animation cut off? Basically something else stopped it before the animation fully completed - anim = The animation it played, it can be a string or an activity enumeration - AlwaysUseSequence = The base will force attempt to play this animation as a sequence regardless of the other options | DEFAULT: false - AlwaysUseGesture = The base will force attempt to play this animation as a gesture regardless of the other options | DEFAULT: false - SequenceInterruptible = Can this sequence be interrupted? | DEFAULT: false - SequenceDuration = How long is the sequence? | DEFAULT: Base decides - WARNING: Recommended to not change this option, it's mostly used internally by the base! - PlayBackRate = How fast should the animation play? | DEFAULT: self.AnimationPlaybackRate - PlayBackRateCalculated = If the playback rate is already calculated in the stopActivitiesTime, then set this to true! | DEFAULT: false - customFunc() = TODO: NOT FINISHED Returns - Number, Accurate animation play time after taking everything in account - WARNING: If "animDelay" parameter is used, result may be inaccurate! -----------------------------------------------------------]] local varGes = "vjges_" local varSeq = "vjseq_" -- function ENT:VJ_ACT_PLAYACTIVITY(animation, stopActivities, stopActivitiesTime, faceEnemy, animDelay, extraOptions, customFunc) animation = VJ_PICK(animation) if animation == false then return 0 end stopActivities = stopActivities or false if stopActivitiesTime == nil then -- If user didn't put anything, then default it to 0 stopActivitiesTime = 0 -- Set this value to false to let the base calculate the time end faceEnemy = faceEnemy or false -- Should it face the enemy while playing this animation? animDelay = tonumber(animDelay) or 0 -- How much time until it starts playing the animation (seconds) extraOptions = extraOptions or {} local finalPlayBackRate = extraOptions.PlayBackRate or self.AnimationPlaybackRate -- How fast should the animation play? local isGesture = false local isSequence = false local isString = isstring(animation) -- Handle "vjges_" and "vjseq_" if isString then local strExpGes = string.Explode(varGes, animation) -- Gestures if strExpGes[2] then -- If 2 exists, then vjges_ was found! isGesture = true animation = strExpGes[2] -- If current name is -1 then it's probably han activity, so turn it into an activity | EX: "vjges_"..ACT_MELEE_ATTACK1 if self:LookupSequence(animation) == -1 then animation = tonumber(animation) isString = false end else -- Sequences local strExpSeq = string.Explode(varSeq, animation) if strExpSeq[2] then -- If 2 exists, then vjseq_ was found! isSequence = true animation = strExpSeq[2] end end end if extraOptions.AlwaysUseGesture == true then isGesture = true end -- Must play a gesture if extraOptions.AlwaysUseSequence == true then -- Must play a sequence isGesture = false isSequence = true if isnumber(animation) then -- If it's an activity, then convert it to a string animation = self:GetSequenceName(self:SelectWeightedSequence(animation)) end elseif isString && !isSequence then -- Only for regular & gesture strings -- If it can be played as an activity, then convert it! local result = self:GetSequenceActivity(self:LookupSequence(animation)) if result == nil or result == -1 then -- Leave it as string isSequence = true else -- Set it as an activity animation = result end end -- If the given animation doesn't exist, then check to see if it does in the weapon translation list if VJ_AnimationExists(self, animation) == false then if !isString && IsValid(self:GetActiveWeapon()) then -- If it's an activity and has a valid weapon then check for weapon translation -- If it returns the same activity as animation, then there isn't even a translation for it so don't play any animation =( if self:GetActiveWeapon().IsVJBaseWeapon && self:TranslateToWeaponAnim(animation) == animation then return 0 end else return 0 -- No animation =( end end -- Seed the current animation, used for animation delaying & on complete check local seed = CurTime(); self.CurAnimationSeed = seed local function PlayAct() local animTime = self:DecideAnimationLength(animation, false) if stopActivities == true then if stopActivitiesTime == false then -- false = Let the base calculate the time stopActivitiesTime = animTime elseif !extraOptions.PlayBackRateCalculated then -- Make sure not to calculate the playback rate when it already has! stopActivitiesTime = stopActivitiesTime / self:GetPlaybackRate() animTime = stopActivitiesTime end self:StopAttacks(true) self.vACT_StopAttacks = true self.NextChaseTime = CurTime() + stopActivitiesTime self.NextIdleTime = CurTime() + stopActivitiesTime -- If there is already a timer, then adjust it instead of creating a new one if !timer.Adjust("timer_act_stopattacks"..self:EntIndex(), stopActivitiesTime, 1, function() self.vACT_StopAttacks = false end) then timer.Create("timer_act_stopattacks"..self:EntIndex(), stopActivitiesTime, 1, function() self.vACT_StopAttacks = false end) end end self.CurAnimationSeed = seed -- We need to set it again because self:StopAttacks() above will reset it when it calls to chase enemy! local vsched = ai_vj_schedule.New("vj_act_"..animation) if (customFunc) then customFunc(vsched, animation) end self.NextIdleStandTime = 0 self.VJ_PlayingSequence = false self.VJ_PlayingInterruptSequence = false self.AnimationPlaybackRate = finalPlayBackRate self:SetPlaybackRate(finalPlayBackRate) if isGesture == true then local gesture = false if isstring(animation) then gesture = self:AddGestureSequence(self:LookupSequence(animation)) else gesture = self:AddGesture(animation) end if gesture != false then //self:ClearSchedule() //self:SetLayerBlendIn(1, 0) //self:SetLayerBlendOut(1, 0) self:SetLayerPriority(gesture, 1) // 2 //self:SetLayerWeight(gesture, 1) self:SetLayerPlaybackRate(gesture, finalPlayBackRate * 0.5) //self:SetLayerDuration(gesture, 3) //print(self:GetLayerDuration(gesture)) end elseif isSequence == true then local dur = (extraOptions.SequenceDuration or self:SequenceDuration(self:LookupSequence(animation))) / self.AnimationPlaybackRate if faceEnemy == true then self:FaceCertainEntity(self:GetEnemy(), true, dur) end self:VJ_PlaySequence(animation, finalPlayBackRate, extraOptions.SequenceDuration != false, dur, extraOptions.SequenceInterruptible or false) end if isGesture == false then -- If it's sequence or activity -- For humans, internally the base will set these variables back to true after this function if it's called by weapon attack animations! self.DoingWeaponAttack = false self.DoingWeaponAttack_Standing = false //self:StartEngineTask(GetTaskList("TASK_RESET_ACTIVITY"), 0) //vsched:EngTask("TASK_RESET_ACTIVITY", 0) //if self.Dead then vsched:EngTask("TASK_STOP_MOVING", 0) end //self:FrameAdvance(0) self:TaskComplete() self:StopMoving() self:ClearSchedule() self:ClearGoal() if isSequence == false then -- Only if activity //self:SetActivity(ACT_RESET) self.VJ_PlayingSequence = false if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:ResetIdealActivity(animation) //vsched:EngTask("TASK_SET_ACTIVITY", animation) -- To avoid AutoMovement stopping the velocity //elseif faceEnemy == true then //vsched:EngTask("TASK_PLAY_SEQUENCE_FACE_ENEMY", animation) else if faceEnemy == true then self:FaceCertainEntity(self:GetEnemy(), true, animTime) end -- This fixes: Animation NOT applying walk frames if the previous animation was the same if self:GetActivity() == animation then self:ResetSequenceInfo() self:SetSaveValue("sequence", 0) end vsched:EngTask("TASK_PLAY_SEQUENCE", animation) //self:ResetIdealActivity(animation) //self:AutoMovement(self:GetAnimTimeInterval()) end end vsched.IsPlayActivity = true self:StartSchedule(vsched) end -- If it has a OnFinish function, then set the timer to run it when it finishes! if (extraOptions.OnFinish) then timer.Simple(animTime, function() if IsValid(self) && !self.Dead then extraOptions.OnFinish(self.CurAnimationSeed != seed, animation) end end) end return animTime end -- For delay system if animDelay > 0 then timer.Simple(animDelay, function() if IsValid(self) && self.CurAnimationSeed == seed then PlayAct() end end) return animDelay + self:DecideAnimationLength(animation, false) -- Approximation, this may be inaccurate! else return PlayAct() end end --------------------------------------------------------------------------------------------------------------------------------------------- local task_chaseEnemyLOS = ai_vj_schedule.New("vj_chase_enemy_los") task_chaseEnemyLOS:EngTask("TASK_GET_PATH_TO_ENEMY_LOS", 0) //task_chaseEnemyLOS:EngTask("TASK_RUN_PATH", 0) task_chaseEnemyLOS:EngTask("TASK_WAIT_FOR_MOVEMENT", 0) //task_chaseEnemyLOS:EngTask("TASK_FACE_ENEMY", 0) //task_chaseEnemyLOS.ResetOnFail = true task_chaseEnemyLOS.CanShootWhenMoving = true task_chaseEnemyLOS.CanBeInterrupted = true task_chaseEnemyLOS.IsMovingTask = true task_chaseEnemyLOS.MoveType = 1 -- local task_chaseEnemy = ai_vj_schedule.New("vj_chase_enemy") task_chaseEnemy:EngTask("TASK_GET_PATH_TO_ENEMY", 0) //task_chaseEnemy:EngTask("TASK_RUN_PATH", 0) task_chaseEnemy:EngTask("TASK_WAIT_FOR_MOVEMENT", 0) //task_chaseEnemy:EngTask("TASK_FACE_ENEMY", 0) //task_chaseEnemy.ResetOnFail = true task_chaseEnemy.CanShootWhenMoving = true //task_chaseEnemy.StopScheduleIfNotMoving = true task_chaseEnemy.CanBeInterrupted = true task_chaseEnemy.IsMovingTask = true task_chaseEnemy.MoveType = 1 -- local varChaseEnemy = "vj_chase_enemy" function ENT:VJ_TASK_CHASE_ENEMY(doLOSChase) doLOSChase = doLOSChase or false self:ClearCondition(COND_ENEMY_UNREACHABLE) if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:AA_ChaseEnemy() return end //if self.CurrentSchedule != nil && self.CurrentSchedule.Name == "vj_chase_enemy" then return end if self:GetNavType() == NAV_JUMP or self:GetNavType() == NAV_CLIMB then return end //if (CurTime() <= self.JumpLegalLandingTime && (self:GetActivity() == ACT_JUMP or self:GetActivity() == ACT_GLIDE or self:GetActivity() == ACT_LAND)) or self:GetActivity() == ACT_CLIMB_UP or self:GetActivity() == ACT_CLIMB_DOWN or self:GetActivity() == ACT_CLIMB_DISMOUNT then return end if (self:GetEnemyLastKnownPos():Distance(self:GetEnemy():GetPos()) <= 12) && self.CurrentSchedule != nil && self.CurrentSchedule.Name == varChaseEnemy then return end self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) if doLOSChase == true then task_chaseEnemyLOS.RunCode_OnFinish = function() local ene = self:GetEnemy() if IsValid(ene) then self:RememberUnreachable(ene, 0) self:VJ_TASK_CHASE_ENEMY(false) end end self:StartSchedule(task_chaseEnemyLOS) else self:StartSchedule(task_chaseEnemy) end end --------------------------------------------------------------------------------------------------------------------------------------------- local table_remove = table.remove -- function ENT:VJ_TASK_IDLE_STAND() if self:IsMoving() or (self.NextIdleTime > CurTime()) or (self.AA_CurrentMoveTime > CurTime()) or self:GetNavType() == NAV_JUMP or self:GetNavType() == NAV_CLIMB then return end // self.CurrentSchedule != nil if (self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC) && self:BusyWithActivity() then return end //if (self.CurrentSchedule != nil && self.CurrentSchedule.Name == "vj_idle_stand") or (self.CurrentAnim_CustomIdle != 0 && VJ_IsCurrentAnimation(self,self.CurrentAnim_CustomIdle) == true) then return end //if (self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC) && self:GetVelocity():Length() > 0 then return end //if self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC then self:AA_StopMoving() return end /*local vschedIdleStand = ai_vj_schedule.New("vj_idle_stand") //vschedIdleStand:EngTask("TASK_FACE_REASONABLE") vschedIdleStand:EngTask("TASK_STOP_MOVING") vschedIdleStand:EngTask("TASK_WAIT_INDEFINITE") vschedIdleStand.CanBeInterrupted = true self:StartSchedule(vschedIdleStand)*/ local idleAnimTbl = self.NoWeapon_UseScaredBehavior_Active == true and self.AnimTbl_ScaredBehaviorStand or ((self.Alerted && self:GetWeaponState() != VJ_WEP_STATE_HOLSTERED && IsValid(self:GetActiveWeapon())) and self.AnimTbl_WeaponAim or self.AnimTbl_IdleStand) local sameAnimFound = false -- If true then it one of the animations in the table is the same as the current! //local numOfAnims = 0 -- Number of valid animations found for k, v in ipairs(idleAnimTbl) do v = VJ_SequenceToActivity(self, v) -- Translate any sequence to activity if v != false then -- Its a valid activity //numOfAnims = numOfAnims + 1 idleAnimTbl[k] = v -- In case it was a sequence, override it with the translated activity number -- Check if its the current idle animation... if sameAnimFound == false && self.CurrentAnim_IdleStand == v then sameAnimFound = true //break end else -- Get rid of any animations that aren't valid! table_remove(idleAnimTbl, k) end end //PrintTable(idleAnimTbl) -- If there is more than 1 animation in the table AND one of the animations is the current animation AND time hasn't expired, then return! /*if #idleAnimTbl > 1 && sameAnimFound == true && self.NextIdleStandTime > CurTime() then return end*/ local pickedAnim = VJ_PICK(idleAnimTbl) -- If no animation was found, then use ACT_IDLE if pickedAnim == false then pickedAnim = ACT_IDLE //sameAnimFound = true end -- If sequence and it has no activity, then don't continue! //pickedAnim = VJ_SequenceToActivity(self,pickedAnim) //if pickedAnim == false then return false end if (!sameAnimFound /*or (sameAnimFound && numOfAnims == 1 && CurTime() > self.NextIdleStandTime)*/) or (CurTime() > self.NextIdleStandTime) then self.CurrentAnim_IdleStand = pickedAnim self.CurIdleStandMove = false -- Old system /*if (self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC) then if self:BusyWithActivity() == true then return end // self:GetSequence() == 0 self:AA_StopMoving() self:VJ_ACT_PLAYACTIVITY(pickedAnim, false, 0, false, 0, {SequenceDuration=false, SequenceInterruptible=true}) // AlwaysUseSequence=true end if self.CurrentSchedule == nil then -- If it's not doing a schedule then reset the activity to make sure it's not already playing the same idle activity! self:StartEngineTask(GetTaskList("TASK_RESET_ACTIVITY"), 0) //self:SetIdealActivity(ACT_RESET) end*/ //self:StartEngineTask(GetTaskList("TASK_PLAY_SEQUENCE"),pickedAnim) if (self.MovementType == VJ_MOVETYPE_AERIAL or self.MovementType == VJ_MOVETYPE_AQUATIC) then self:AA_StopMoving() end self.CurAnimationSeed = 0 self.VJ_PlayingSequence = false self.VJ_PlayingInterruptSequence = false self:ResetIdealActivity(pickedAnim) timer.Simple(0.01, function() -- So we can make sure the engine has enough time to set the animation if IsValid(self) && self.NextIdleStandTime != 0 then local getSeq = self:GetSequence() self.CurIdleStandMove = self:GetSequenceMoveDist(getSeq) > 0 local seqToAct = VJ_SequenceToActivity(self,self:GetSequenceName(getSeq)) if seqToAct == pickedAnim or (IsValid(self:GetActiveWeapon()) && seqToAct == self:TranslateToWeaponAnim(pickedAnim)) then -- Nayir yete himagva animation e nooynene self.NextIdleStandTime = CurTime() + ((self:SequenceDuration(getSeq) - 0.15) / self:GetPlaybackRate()) -- Yete nooynene ooremen jamanage tir animation-en yergarootyan chap! end end end) self.NextIdleStandTime = CurTime() + 0.15 -- This is temp, timer above overrides it elseif self.CurIdleStandMove && !self:IsSequenceFinished() then self:AutoMovement(self:GetAnimTimeInterval()) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:DoIdleAnimation(idleType) if self:GetState() == VJ_STATE_ONLY_ANIMATION_CONSTANT or self.Dead or self.VJ_IsBeingControlled or self.PlayingAttackAnimation == true or (self.NextIdleTime > CurTime()) or (self.AA_CurrentMoveTime > CurTime()) or (self.CurrentSchedule != nil && self.CurrentSchedule.Name == "vj_act_resetenemy") then return end idleType = idleType or 0 -- 0 = Random | 1 = Wander | 2 = Idle Stand if self.IdleAlwaysWander == true then idleType = 1 end -- Things that override can't bypass, Forces the NPC to ONLY idle stand! if self.DisableWandering == true or self.IsGuard == true or self.MovementType == VJ_MOVETYPE_STATIONARY or self.IsVJBaseSNPC_Tank == true or self.LastHiddenZone_CanWander == false or self.NextWanderTime > CurTime() or self.IsFollowing == true or self.Medic_Status then idleType = 2 end if idleType == 0 then -- Random (Wander & Idle Stand) if math.random(1, 3) == 1 then self:VJ_TASK_IDLE_WANDER() else self:VJ_TASK_IDLE_STAND() end elseif idleType == 1 then -- Wander self:VJ_TASK_IDLE_WANDER() elseif idleType == 2 then -- Idle Stand self:VJ_TASK_IDLE_STAND() return -- Don't set self.NextWanderTime below end self.NextWanderTime = CurTime() + math.Rand(3, 6) // self.NextIdleTime end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:DoChaseAnimation(alwaysChase) local ene = self:GetEnemy() if self:GetState() == VJ_STATE_ONLY_ANIMATION_CONSTANT or self.Dead or self.VJ_IsBeingControlled or self.PlayingAttackAnimation == true or self.Flinching == true or self.IsVJBaseSNPC_Tank == true or !IsValid(ene) or (self.NextChaseTime > CurTime()) or (CurTime() < self.TakingCoverT) or (self.PlayingAttackAnimation == true && self.MovementType != VJ_MOVETYPE_AERIAL && self.MovementType != VJ_MOVETYPE_AQUATIC) then return end if self:VJ_GetNearestPointToEntityDistance(ene) < self.MeleeAttackDistance && self.EnemyData.IsVisible && (self.EnemyData.SightDiff > math_cos(math_rad(self.MeleeAttackAngleRadius))) then self:VJ_TASK_IDLE_STAND() return end -- Not melee attacking yet but it is in range, so stop moving! alwaysChase = alwaysChase or false -- true = Chase no matter what -- Things that override can't bypass, Forces the NPC to ONLY idle stand! if self.MovementType == VJ_MOVETYPE_STATIONARY or self.IsFollowing == true or self.Medic_Status or self:GetState() == VJ_STATE_ONLY_ANIMATION then self:VJ_TASK_IDLE_STAND() return end -- For non-aggressive SNPCs if self.Behavior == VJ_BEHAVIOR_PASSIVE or self.Behavior == VJ_BEHAVIOR_PASSIVE_NATURE then self:VJ_TASK_COVER_FROM_ENEMY("TASK_RUN_PATH") self.NextChaseTime = CurTime() + 3 return end if alwaysChase == false && (self.DisableChasingEnemy == true or self.IsGuard == true) then self:VJ_TASK_IDLE_STAND() return end -- If the enemy is not reachable if (self:HasCondition(COND_ENEMY_UNREACHABLE) or self:IsUnreachable(ene)) && (IsValid(self:GetActiveWeapon()) == true && (!self:GetActiveWeapon().IsMeleeWeapon)) then self:VJ_TASK_CHASE_ENEMY(true) self:RememberUnreachable(ene, 2) else -- Is reachable, so chase the enemy! self:VJ_TASK_CHASE_ENEMY(false) end -- Set the next chase time if self.NextChaseTime > CurTime() then return end -- Don't set it if it's already set! self.NextChaseTime = CurTime() + (((self.LatestEnemyDistance > 2000) and 1) or 0.1) -- If the enemy is far, increase the delay! end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:SetupWeaponHoldTypeAnims(hType) -- Decide what type of animation set it uses if VJ_AnimationExists(self, "signal_takecover") == true && VJ_AnimationExists(self, "grenthrow") == true && VJ_AnimationExists(self, "bugbait_hit") == true then self.ModelAnimationSet = VJ_MODEL_ANIMSET_COMBINE -- Combine elseif VJ_AnimationExists(self, ACT_WALK_AIM_PISTOL) == true && VJ_AnimationExists(self, ACT_RUN_AIM_PISTOL) == true && VJ_AnimationExists(self, ACT_POLICE_HARASS1) == true then self.ModelAnimationSet = VJ_MODEL_ANIMSET_METROCOP -- Metrocop elseif VJ_AnimationExists(self, "coverlow_r") == true && VJ_AnimationExists(self, "wave_smg1") == true && VJ_AnimationExists(self, ACT_BUSY_SIT_GROUND) == true then self.ModelAnimationSet = VJ_MODEL_ANIMSET_REBEL -- Rebel elseif VJ_AnimationExists(self, "gmod_breath_layer") == true then self.ModelAnimationSet = VJ_MODEL_ANIMSET_PLAYER -- Player end self.WeaponAnimTranslations = {} self.NextIdleStandTime = 0 if self:CustomOnSetupWeaponHoldTypeAnims(hType) == true then return end if self.ModelAnimationSet == VJ_MODEL_ANIMSET_COMBINE then -- Combine =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- -- Use rifle animations with minor edits if it's holding a handgun local rifle_idle = ACT_IDLE_SMG1 local rifle_walk = VJ_PICK({ACT_WALK_RIFLE, VJ_SequenceToActivity(self, "walkeasy_all")}) if hType == "pistol" or hType == "revolver" or hType == "melee" or hType == "melee2" or hType == "knife" then rifle_idle = VJ_SequenceToActivity(self, "idle_unarmed") rifle_walk = VJ_SequenceToActivity(self, "walkunarmed_all") end -- "Leanwall_CrouchLeft_A_idle", "Leanwall_CrouchLeft_B_idle", "Leanwall_CrouchLeft_C_idle", "Leanwall_CrouchLeft_D_idle" self.WeaponAnimTranslations[ACT_COVER_LOW] = {ACT_COVER, "vjseq_Leanwall_CrouchLeft_A_idle", "vjseq_Leanwall_CrouchLeft_B_idle", "vjseq_Leanwall_CrouchLeft_C_idle", "vjseq_Leanwall_CrouchLeft_D_idle"} if hType == "ar2" or hType == "smg" or hType == "rpg" or hType == "pistol" or hType == "revolver" or hType == "melee" or hType == "melee2" or hType == "knife" then if hType == "ar2" or hType == "pistol" or hType == "revolver" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_AR2 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_AR2 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_AR2_LOW //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 -- No need to translate //self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY -- No need to translate, it's already the correct animation elseif hType == "smg" or hType == "rpg" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 -- No need to translate self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1 elseif hType == "melee" or hType == "melee2" or hType == "knife" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_MELEE_ATTACK1 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = false -- Don't play anything! //self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW -- Not used for melee //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 -- Not used for melee self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = rifle_idle end //self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW -- No need to translate self.WeaponAnimTranslations[ACT_IDLE] = rifle_idle self.WeaponAnimTranslations[ACT_WALK] = rifle_walk self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = ACT_RUN_RIFLE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "crossbow" or hType == "shotgun" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SHOTGUN if hType == "crossbow" then self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_AR2 else self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SHOTGUN end self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SHOTGUN_LOW //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SHOTGUN -- No need to translate //self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW -- No need to translate self.WeaponAnimTranslations[ACT_IDLE] = ACT_SHOTGUN_IDLE4 self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SHOTGUN self.WeaponAnimTranslations[ACT_WALK] = ACT_WALK_AIM_SHOTGUN self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_SHOTGUN self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = ACT_RUN_RIFLE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_SHOTGUN self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE end elseif self.ModelAnimationSet == VJ_MODEL_ANIMSET_METROCOP then -- Metrocop =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- -- Do not translate crouch walking and also make the crouch running a walking one instead self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_WALK_CROUCH if hType == "smg" or hType == "rpg" or hType == "ar2" or hType == "crossbow" or hType == "shotgun" then -- Note: Metrocops must use smg animation, they don't have any animations for AR2! self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_COVER_SMG1_LOW self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW self.WeaponAnimTranslations[ACT_IDLE] = ACT_IDLE_SMG1 self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1 self.WeaponAnimTranslations[ACT_WALK] = ACT_WALK_RIFLE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = ACT_RUN_RIFLE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "pistol" or hType == "revolver" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_PISTOL self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_PISTOL_LOW self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_COVER_PISTOL_LOW self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_PISTOL self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_PISTOL_LOW self.WeaponAnimTranslations[ACT_IDLE] = ACT_IDLE_PISTOL self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_PISTOL self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({ACT_WALK, ACT_WALK_PISTOL}) self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_PISTOL //self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE -- No need to translate self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = VJ_PICK({ACT_RUN, ACT_RUN_PISTOL}) self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_PISTOL //self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE -- No need to translate self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "melee" or hType == "melee2" or hType == "knife" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_MELEE_ATTACK_SWING self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = false //ACT_MELEE_ATTACK_SWING_GESTURE -- Don't play anything! //self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW -- Not used for melee self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_COWER //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 -- Not used for melee //self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW -- Not used for melee self.WeaponAnimTranslations[ACT_IDLE] = {ACT_IDLE, ACT_IDLE, VJ_SequenceToActivity(self, "plazathreat1")} self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_MELEE self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({ACT_WALK, ACT_WALK_ANGRY}) //self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE -- Not used for melee //self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE -- No need to translate //self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE -- Not used for melee //self.WeaponAnimTranslations[ACT_RUN] = ACT_RUN -- No need to translate //self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE -- Not used for melee //self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE -- No need to translate //self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE -- Not used for melee end elseif self.ModelAnimationSet == VJ_MODEL_ANIMSET_REBEL then -- Rebel =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- local isFemale = VJ_AnimationExists(self, ACT_IDLE_ANGRY_PISTOL) -- handguns use a different set! self.WeaponAnimTranslations[ACT_COVER_LOW] = {ACT_COVER_LOW_RPG, ACT_COVER_LOW, "vjseq_coverlow_l", "vjseq_coverlow_r"} if hType == "ar2" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_AR2 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_AR2 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_AR2_LOW self.WeaponAnimTranslations[ACT_RELOAD] = VJ_SequenceToActivity(self, "reload_ar2") self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW self.WeaponAnimTranslations[ACT_IDLE] = VJ_PICK({VJ_SequenceToActivity(self, "idle_relaxed_ar2_1"), VJ_SequenceToActivity(self, "idle_alert_ar2_1"), VJ_SequenceToActivity(self, "idle_angry_ar2")}) self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = VJ_SequenceToActivity(self, "idle_ar2_aim") self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({VJ_SequenceToActivity(self, "walk_ar2_relaxed_all"), VJ_SequenceToActivity(self, "walkalerthold_ar2_all1"), VJ_SequenceToActivity(self, "walkholdall1_ar2")}) self.WeaponAnimTranslations[ACT_WALK_AIM] = VJ_PICK({VJ_SequenceToActivity(self, "walkaimall1_ar2"), VJ_SequenceToActivity(self, "walkalertaim_ar2_all1")}) self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RPG self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = VJ_PICK({VJ_SequenceToActivity(self, "run_alert_holding_ar2_all"), VJ_SequenceToActivity(self, "run_ar2_relaxed_all"), VJ_SequenceToActivity(self, "run_holding_ar2_all")}) self.WeaponAnimTranslations[ACT_RUN_AIM] = VJ_PICK({ACT_RUN_AIM_RIFLE, VJ_SequenceToActivity(self, "run_alert_aiming_ar2_all")}) self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RPG self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "smg" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW self.WeaponAnimTranslations[ACT_IDLE] = VJ_PICK({ACT_IDLE_SMG1_RELAXED, ACT_IDLE_SMG1_STIMULATED, ACT_IDLE_SMG1, VJ_SequenceToActivity(self, "idle_smg1_relaxed")}) self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_SMG1 self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({ACT_WALK_RIFLE, ACT_WALK_RIFLE_RELAXED, ACT_WALK_RIFLE_STIMULATED}) self.WeaponAnimTranslations[ACT_WALK_AIM] = VJ_PICK({ACT_WALK_AIM_RIFLE, ACT_WALK_AIM_RIFLE_STIMULATED}) self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = VJ_PICK({ACT_RUN_RIFLE, ACT_RUN_RIFLE_STIMULATED, ACT_RUN_RIFLE_RELAXED}) self.WeaponAnimTranslations[ACT_RUN_AIM] = VJ_PICK({ACT_RUN_AIM_RIFLE, ACT_RUN_AIM_RIFLE_STIMULATED}) self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "crossbow" or hType == "shotgun" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_SHOTGUN self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_SHOTGUN self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SHOTGUN self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW //ACT_RELOAD_SHOTGUN_LOW self.WeaponAnimTranslations[ACT_IDLE] = VJ_PICK({ACT_IDLE_SHOTGUN_RELAXED, ACT_IDLE_SHOTGUN_STIMULATED}) self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = VJ_SequenceToActivity(self, "idle_ar2_aim") self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({VJ_SequenceToActivity(self, "walk_ar2_relaxed_all"), VJ_SequenceToActivity(self, "walkalerthold_ar2_all1"), VJ_SequenceToActivity(self, "walkholdall1_ar2")}) self.WeaponAnimTranslations[ACT_WALK_AIM] = VJ_PICK({VJ_SequenceToActivity(self, "walkaimall1_ar2"), VJ_SequenceToActivity(self, "walkalertaim_ar2_all1")}) self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RPG self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = VJ_PICK({VJ_SequenceToActivity(self, "run_alert_holding_ar2_all"), VJ_SequenceToActivity(self, "run_ar2_relaxed_all"), VJ_SequenceToActivity(self, "run_holding_ar2_all")}) self.WeaponAnimTranslations[ACT_RUN_AIM] = VJ_PICK({ACT_RUN_AIM_RIFLE, VJ_SequenceToActivity(self, "run_alert_aiming_ar2_all")}) self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RPG self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "rpg" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_RPG self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_RPG self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW self.WeaponAnimTranslations[ACT_IDLE] = VJ_PICK({ACT_IDLE_RPG, ACT_IDLE_RPG_RELAXED}) self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_RPG self.WeaponAnimTranslations[ACT_WALK] = VJ_PICK({ACT_WALK_RPG, ACT_WALK_RPG_RELAXED}) self.WeaponAnimTranslations[ACT_WALK_AIM] = VJ_PICK({VJ_SequenceToActivity(self, "walkaimall1_ar2"), VJ_SequenceToActivity(self, "walkalertaim_ar2_all1")}) self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RPG self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = VJ_PICK({ACT_RUN_RPG, ACT_RUN_RPG_RELAXED}) self.WeaponAnimTranslations[ACT_RUN_AIM] = VJ_PICK({ACT_RUN_AIM_RIFLE, VJ_SequenceToActivity(self, "run_alert_aiming_ar2_all")}) self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RPG self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "pistol" or hType == "revolver" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_RANGE_ATTACK_PISTOL self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_GESTURE_RANGE_ATTACK_PISTOL self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_PISTOL_LOW self.WeaponAnimTranslations[ACT_COVER_LOW] = {"crouchidle_panicked4", "vjseq_crouchidlehide"} self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_PISTOL self.WeaponAnimTranslations[ACT_RELOAD_LOW] = isFemale and ACT_RELOAD_SMG1_LOW or ACT_RELOAD_PISTOL_LOW -- Only males have covered pistol reload! self.WeaponAnimTranslations[ACT_IDLE] = ACT_IDLE_PISTOL self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = isFemale and ACT_IDLE_ANGRY_PISTOL or VJ_SequenceToActivity(self, "idle_ar2_aim") -- Only females have angry pistol animation self.WeaponAnimTranslations[ACT_WALK] = ACT_WALK_PISTOL self.WeaponAnimTranslations[ACT_WALK_AIM] = VJ_PICK({VJ_SequenceToActivity(self, "walkaimall1_ar2"), VJ_SequenceToActivity(self, "walkalertaim_ar2_all1")}) //self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE -- No need to translate self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE self.WeaponAnimTranslations[ACT_RUN] = ACT_RUN_PISTOL self.WeaponAnimTranslations[ACT_RUN_AIM] = VJ_SequenceToActivity(self, "run_alert_aiming_ar2_all") //self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE -- No need to translate self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE elseif hType == "melee" or hType == "melee2" or hType == "knife" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_MELEE_ATTACK_SWING self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = false -- Don't play anything! //self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_RANGE_ATTACK_SMG1_LOW -- Not used for melee self.WeaponAnimTranslations[ACT_COVER_LOW] = {"crouchidle_panicked4", "vjseq_crouchidlehide"} //self.WeaponAnimTranslations[ACT_RELOAD] = ACT_RELOAD_SMG1 -- Not used for melee //self.WeaponAnimTranslations[ACT_RELOAD_LOW] = ACT_RELOAD_SMG1_LOW -- Not used for melee self.WeaponAnimTranslations[ACT_IDLE] = ACT_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_IDLE_ANGRY_MELEE //self.WeaponAnimTranslations[ACT_WALK] = ACT_WALK -- No need to translate //self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_WALK_AIM_RIFLE -- Not used for melee //self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_WALK_CROUCH_RIFLE -- No need to translate //self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_WALK_CROUCH_AIM_RIFLE -- Not used for melee self.WeaponAnimTranslations[ACT_RUN] = VJ_SequenceToActivity(self, "run_all_panicked") //self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_RUN_AIM_RIFLE -- Not used for melee //self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_RUN_CROUCH_RIFLE -- No need to translate //self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_RUN_CROUCH_AIM_RIFLE -- Not used for melee end elseif self.ModelAnimationSet == VJ_MODEL_ANIMSET_PLAYER then -- Player =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- if hType == "ar2" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_AR2 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_AR2 self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_AR2 self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_AR2 self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_AR2 self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_AR2 self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_AR2 self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_AR2 self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_AR2 self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_AR2 self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_AR2 elseif hType == "pistol" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_PISTOL self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_PISTOL self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_PISTOL self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_PISTOL self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_PISTOL self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_PISTOL self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_PISTOL self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_PISTOL self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_PISTOL self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_FAST self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_PISTOL self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_PISTOL elseif hType == "smg" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_SMG1 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_SMG1 self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_smg1" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_smg1" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_SMG1 self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_SMG1 self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_SMG1 self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_SMG1 self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_SMG1 self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_SMG1 self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SMG1 self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_SMG1 self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SMG1 elseif hType == "grenade" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_GRENADE self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_GRENADE -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_GRENADE self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_GRENADE self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_GRENADE self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_GRENADE self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_GRENADE self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_GRENADE self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_GRENADE self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_GRENADE self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_GRENADE elseif hType == "shotgun" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_SHOTGUN self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_SHOTGUN self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_shotgun" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_shotgun" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_SHOTGUN self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_SHOTGUN self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_SHOTGUN self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_SHOTGUN self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_SHOTGUN self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_SHOTGUN self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SHOTGUN self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_SHOTGUN self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SHOTGUN elseif hType == "rpg" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_RPG self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_RPG self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_RPG self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_RPG self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_RPG self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_RPG self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_RPG self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_RPG self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_RPG self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_RPG self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_RPG elseif hType == "physgun" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_PHYSGUN self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_PHYSGUN self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_PHYSGUN self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_PHYSGUN self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_PHYSGUN self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_PHYSGUN self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_PHYSGUN self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_PHYSGUN self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_PHYSGUN self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_PHYSGUN self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_PHYSGUN elseif hType == "crossbow" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_CROSSBOW self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_CROSSBOW self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_ar2" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_CROSSBOW self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE_PASSIVE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_CROSSBOW self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_CROSSBOW self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_CROSSBOW self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_CROSSBOW self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK_PASSIVE self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_CROSSBOW self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_CROSSBOW self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN_PASSIVE self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_CROSSBOW self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH_PASSIVE self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_CROSSBOW elseif hType == "slam" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_SLAM self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_SLAM -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_SLAM self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_SLAM self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_SLAM self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_SLAM self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_SLAM self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_SLAM self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SLAM self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_SLAM self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_SLAM elseif hType == "duel" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_DUEL self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_DUEL self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_DUEL self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_duel" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_duel" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_DUEL self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_DUEL self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_DUEL self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_DUEL self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_DUEL self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_DUEL self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_DUEL self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_DUEL self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_DUEL elseif hType == "revolver" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_REVOLVER self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_REVOLVER self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_revolver" self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_revolver" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_REVOLVER self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_REVOLVER self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_REVOLVER self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_REVOLVER self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_REVOLVER self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_REVOLVER self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_REVOLVER self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_REVOLVER self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_REVOLVER elseif hType == "melee" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_MELEE self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_MELEE -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_MELEE self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_MELEE self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_MELEE self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_MELEE self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_MELEE self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_MELEE self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_MELEE self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_MELEE self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_MELEE elseif hType == "melee2" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_MELEE2 self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2 self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_MELEE2 -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_MELEE2 self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_MELEE2 self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_MELEE2 self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_MELEE2 self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_MELEE2 self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_MELEE2 self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_MELEE2 self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_MELEE2 self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_MELEE2 elseif hType == "knife" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_KNIFE self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_KNIFE self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_KNIFE -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_KNIFE self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_KNIFE self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_KNIFE self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_KNIFE self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_KNIFE self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_KNIFE self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_KNIFE self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_KNIFE self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_KNIFE elseif hType == "camera" then self.WeaponAnimTranslations[ACT_RANGE_ATTACK1] = ACT_HL2MP_IDLE_CAMERA -- self.WeaponAnimTranslations[ACT_GESTURE_RANGE_ATTACK1] = ACT_HL2MP_GESTURE_RANGE_ATTACK_CAMERA self.WeaponAnimTranslations[ACT_RANGE_ATTACK1_LOW] = ACT_HL2MP_IDLE_CROUCH_CAMERA -- self.WeaponAnimTranslations[ACT_RELOAD] = "vjges_reload_pistol" -- self.WeaponAnimTranslations[ACT_RELOAD_LOW] = "vjges_reload_pistol" self.WeaponAnimTranslations[ACT_COVER_LOW] = ACT_HL2MP_IDLE_CROUCH_CAMERA self.WeaponAnimTranslations[ACT_IDLE] = ACT_HL2MP_IDLE self.WeaponAnimTranslations[ACT_IDLE_ANGRY] = ACT_HL2MP_IDLE_CAMERA self.WeaponAnimTranslations[ACT_JUMP] = ACT_HL2MP_JUMP_CAMERA self.WeaponAnimTranslations[ACT_GLIDE] = ACT_HL2MP_JUMP_CAMERA self.WeaponAnimTranslations[ACT_LAND] = ACT_HL2MP_IDLE_CAMERA self.WeaponAnimTranslations[ACT_WALK] = ACT_HL2MP_WALK self.WeaponAnimTranslations[ACT_WALK_AIM] = ACT_HL2MP_WALK_CAMERA self.WeaponAnimTranslations[ACT_WALK_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_WALK_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_CAMERA self.WeaponAnimTranslations[ACT_RUN] = ACT_HL2MP_RUN self.WeaponAnimTranslations[ACT_RUN_AIM] = ACT_HL2MP_RUN_CAMERA self.WeaponAnimTranslations[ACT_RUN_CROUCH] = ACT_HL2MP_WALK_CROUCH self.WeaponAnimTranslations[ACT_RUN_CROUCH_AIM] = ACT_HL2MP_WALK_CROUCH_CAMERA end end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:TranslateToWeaponAnim(act) local translate = self.WeaponAnimTranslations[act] if translate == nil then -- If no animation found, then just return the given activity return act else -- Found an animation! return VJ_PICK(translate) end end --------------------------------------------------------------------------------------------------------------------------------------------- local sdWepSwitch = {"physics/metal/weapon_impact_soft1.wav","physics/metal/weapon_impact_soft2.wav","physics/metal/weapon_impact_soft3.wav"} -- function ENT:DoChangeWeapon(wep, invSwitch) wep = wep or nil -- The weapon to give or setup | Setting it nil will only setup the current active weapon invSwitch = invSwitch or false -- If true, it will not delete the previous weapon! local curWep = self:GetActiveWeapon() -- If not supposed to have a weapon, then return! if self.DisableWeapons && IsValid(curWep) then curWep:Remove() return NULL end -- Only remove and actually give the weapon if the function is given a weapon class to set if wep != nil then if invSwitch then self:SelectWeapon(wep) VJ_EmitSound(self, sdWepSwitch, 70) curWep = wep else if IsValid(curWep) && self.WeaponInventoryStatus <= VJ_WEP_INVENTORY_PRIMARY then curWep:Remove() end curWep = self:Give(wep) self.WeaponInventory.Primary = curWep end end -- If we are given a new weapon or switching weapon, then do all of the necessary set up if IsValid(curWep) then self.CurrentWeaponAnimation = -1 self:SetWeaponState() -- Reset the weapon state because we do NOT want previous weapon's state to be used! if invSwitch then if curWep.IsVJBaseWeapon then curWep:Equip(self) end else -- If we are not switching weapons, then we know curWep is the primary weapon self.WeaponInventoryStatus = VJ_WEP_INVENTORY_PRIMARY -- If this is completely new weapon, then set the weapon inventory's primary to this weapon local curPrimary = self.WeaponInventory.Primary if curWep != self.WeaponInventory.Primary then if IsValid(curPrimary) then curPrimary:Remove() end -- Remove the old primary weapon self.WeaponInventory.Primary = curWep end end self:SetupWeaponHoldTypeAnims(curWep:GetHoldType()) self:CustomOnDoChangeWeapon(curWep, self.CurrentWeaponEntity, invSwitch) self.CurrentWeaponEntity = curWep else self.WeaponInventoryStatus = VJ_WEP_INVENTORY_NONE end return curWep end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:SetWeaponState(state, time) time = time or -1 self.WeaponState = state or VJ_WEP_STATE_READY if time >= 0 then timer.Create("timer_weapon_state_reset"..self:EntIndex(), time, 1, function() self:SetWeaponState() end) else timer.Remove("timer_weapon_state_reset"..self:EntIndex()) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:GetWeaponState() return self.WeaponState end --------------------------------------------------------------------------------------------------------------------------------------------- local finishAttack = { [VJ_ATTACK_MELEE] = function(self, skipStopAttacks) if skipStopAttacks != true then timer.Create("timer_melee_finished"..self:EntIndex(), self:DecideAttackTimer(self.NextAnyAttackTime_Melee, self.NextAnyAttackTime_Melee_DoRand, self.TimeUntilMeleeAttackDamage, self.CurrentAttackAnimationDuration), 1, function() self:StopAttacks() self:DoChaseAnimation() end) end timer.Create("timer_melee_finished_abletomelee"..self:EntIndex(), self:DecideAttackTimer(self.NextMeleeAttackTime, self.NextMeleeAttackTime_DoRand), 1, function() self.IsAbleToMeleeAttack = true end) end } --------------------------------------------------------------------------------------------------------------------------------------------- //function ENT:OnActiveWeaponChanged(old, new) print(old, new) end --------------------------------------------------------------------------------------------------------------------------------------------- /* Variable Notes: m_flMoveWaitFinished = Current move and wait time, used for things like when opening doors and have to stop for a second m_hOpeningDoor = The door entity it's opening m_vDefaultEyeOffset = The eye position, it's very close to self:EyePos() m_flTimeEnemyAcquired = Every time setenemy is called (including NULL!) --> print(math.abs(self:GetInternalVariable("m_flTimeEnemyAcquired"))) m_flGroundChangeTime = Time since it touched the ground (Must be from high place) m_bSequenceFinished = Is it playing a animation? m_vecLean = How much it's leaning (ex: Drag around with physgun) m_flAnimTime = Changes the self:GetAnimTimeInterval() m_bIsMoving = Same as self:IsMoving() m_flLastEventCheck = Cycle index of when events were last checked m_flGroundSpeed = Computed linear movement rate for current sequence m_flOriginalYaw = This is the direction facing when the level designer placed the NPC in the level. m_spawnEquipment = Class name of the weapon it spawned with, stays even when weapon is removed or another weapon from its inventory is used! m_takedamage = Defines how it can take damage #define DAMAGE_NO 0 #define DAMAGE_EVENTS_ONLY 1 // Call damage functions, but don't modify health #define DAMAGE_YES 2 #define DAMAGE_AIM 3 m_nWaterType = Type of water the entity is in --> 1 = water, 2 = slime -- Following is just used for the face and eye looking: m_hLookTarget = The entity it's looking at m_flNextRandomLookTime = Next time it can look at something (Can be used to set it as well) m_flEyeIntegRate = How fast the eyes move m_viewtarget = Returns the position the NPC's eye pupils are looking at (Can be used to set it as well) m_flBlinktime = Time until it blinks again (Can be used to set it as well) -- Change movement speed: self:SetLocalVelocity(self:GetMoveVelocity() * 1.5) -- To test sound hints: local test = getSdHint(bit.bor(SOUND_DANGER, SOUND_CONTEXT_PLAYER_VEHICLE), self:GetPos()) if istable(test) then print("---------------------") print(test.origin:Distance(self:GetPos())) PrintTable(test) end */ --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:Think() //PrintTable(self:GetAnimInfo(self:GetActivity())) //self:MoveStop() //self:ResetMoveCalc() //print("---------------------") //PrintTable(self:GetSaveTable()) //print(self:GetInternalVariable("m_flFieldOfView")) //print(self:GetInternalVariable("m_flMoveWaitFinished") - CurTime()) //self:SetSaveValue("m_flMoveWaitFinished", CurTime() + 2) self:SetCondition(1) -- Fix attachments, bones, positions, angles etc. being broken in NPCs! This condition is used as a backup in case sv_pvsskipanimation isn't disabled! //if self.CurrentSchedule != nil then PrintTable(self.CurrentSchedule) end //if self.CurrentTask != nil then PrintTable(self.CurrentTask) end if self.MovementType == VJ_MOVETYPE_GROUND && self:GetVelocity():Length() <= 0 && !self:IsEFlagSet(EFL_IS_BEING_LIFTED_BY_BARNACLE) /*&& curSched.IsMovingTask == true*/ then self:DropToFloor() end local curSched = self.CurrentSchedule if curSched != nil then if self:IsMoving() then if curSched.MoveType == 0 && !VJ_HasValue(self.AnimTbl_Walk, self:GetMovementActivity()) then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) elseif curSched.MoveType == 1 && !VJ_HasValue(self.AnimTbl_Run, self:GetMovementActivity()) then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) end end local blockingEnt = self:GetBlockingEntity() -- No longer needed as the engine now does detects and opens the doors //if self.CanOpenDoors && IsValid(blockingEnt) && (blockingEnt:GetClass() == "func_door" or blockingEnt:GetClass() == "func_door_rotating") && (blockingEnt:HasSpawnFlags(256) or blockingEnt:HasSpawnFlags(1024)) && !blockingEnt:HasSpawnFlags(512) then //blockingEnt:Fire("Open") //end if (curSched.StopScheduleIfNotMoving == true or curSched.StopScheduleIfNotMoving_Any == true) && (!self:IsMoving() or (IsValid(blockingEnt) && (blockingEnt:IsNPC() or curSched.StopScheduleIfNotMoving_Any == true))) then // (self:GetGroundSpeedVelocity():Length() <= 0) == true self:ScheduleFinished(curSched) //self:SetCondition(COND_TASK_FAILED) //self:StopMoving() end -- self:OnMovementFailed() handles some of them, but we do still need this for non-movement failures (EX: Finding cover area) if self:HasCondition(COND_TASK_FAILED) then //print("VJ Base: Task Failed Condition Identified! "..self:GetName()) if self:DoRunCode_OnFail(curSched) == true then self:ClearCondition(COND_TASK_FAILED) end if curSched.ResetOnFail == true then self:ClearCondition(COND_TASK_FAILED) self:StopMoving() //self:SelectSchedule() end end end //print("------------------") //print(self:GetActiveWeapon()) //PrintTable(self:GetWeapons()) if self.DoingWeaponAttack == false then self.DoingWeaponAttack_Standing = false end if self.CurrentWeaponEntity != self:GetActiveWeapon() then self.CurrentWeaponEntity = self:DoChangeWeapon() end self:CustomOnThink() local curTime = CurTime() if !self.Dead && self.HasBreathSound && self.HasSounds && curTime > self.NextBreathSoundT then local sdtbl = VJ_PICK(self.SoundTbl_Breath) local dur = 1 if sdtbl != false then VJ_STOPSOUND(self.CurrentBreathSound) dur = (self.NextSoundTime_Breath == true and SoundDuration(sdtbl)) or math.Rand(self.NextSoundTime_Breath.a, self.NextSoundTime_Breath.b) self.CurrentBreathSound = VJ_CreateSound(self, sdtbl, self.BreathSoundLevel, self:VJ_DecideSoundPitch(self.BreathSoundPitch.a, self.BreathSoundPitch.b)) end self.NextBreathSoundT = curTime + dur end --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- if GetConVar("ai_disabled"):GetInt() == 0 && self:GetState() != VJ_STATE_FREEZE && !self:IsEFlagSet(EFL_IS_BEING_LIFTED_BY_BARNACLE) then if self.VJ_DEBUG == true then if GetConVar("vj_npc_printcurenemy"):GetInt() == 1 then print(self:GetClass().."'s Enemy: ",self:GetEnemy()," Alerted? ",self.Alerted) end if GetConVar("vj_npc_printtakingcover"):GetInt() == 1 then if curTime > self.TakingCoverT == true then print(self:GetClass().." Is Not Taking Cover") else print(self:GetClass().." Is Taking Cover ("..self.TakingCoverT-curTime..")") end end if GetConVar("vj_npc_printlastseenenemy"):GetInt() == 1 then PrintMessage(HUD_PRINTTALK, (curTime - self.EnemyData.LastVisibleTime).." ("..self:GetName()..")") end if IsValid(self.CurrentWeaponEntity) && GetConVar("vj_npc_dev_printwepinfo"):GetInt() == 1 then print(self:GetName().." -->", self.CurrentWeaponEntity, "Ammo: "..self.CurrentWeaponEntity:Clip1().."/"..self.CurrentWeaponEntity:GetMaxClip1().." | Accuracy: "..self.WeaponSpread) end end local eneData = self.EnemyData self:SetPlaybackRate(self.AnimationPlaybackRate) if self:GetArrivalActivity() == -1 then self:SetArrivalActivity(self.CurrentAnim_IdleStand) end if self.UsePlayerModelMovement == true && self.MovementType == VJ_MOVETYPE_GROUND then local moveDir = self:GetMoveDirection(true) if moveDir != defPos then self:SetPoseParameter("move_x", moveDir.x) self:SetPoseParameter("move_y", moveDir.y) if curSched != nil && !curSched.ConstantlyFaceEnemy then self:FaceCertainPosition(self:GetCurWaypointPos()) end end end self:CustomOnThink_AIEnabled() if self.DisableFootStepSoundTimer == false then self:FootStepSoundCode() end -- Update follow system's data //print("------------------") //PrintTable(self.FollowData) if self.IsFollowing == true then local followData = self.FollowData local followEnt = followData.Ent local followIsLiving = followData.IsLiving //print(self:GetTarget()) if IsValid(followEnt) && (!followIsLiving or (followIsLiving && (self:Disposition(followEnt) == D_LI or self:GetClass() == followEnt:GetClass()) && VJ_IsAlive(followEnt))) then if curTime > self.NextFollowUpdateT && !self.VJTags[VJ_TAG_HEALING] then local distToPly = self:GetPos():Distance(followEnt:GetPos()) local busy = self:BusyWithActivity() self:SetTarget(followEnt) followData.StopAct = false if distToPly > followData.MinDist then -- Entity is far away, move towards it! local isFar = distToPly > (followData.MinDist * 4) -- IF (we are busy but far) OR (not busy) THEN move if (busy && isFar) or (!busy) then followData.Moving = true -- If we are far then stop all activities (ex: attacks) and just go there already! if isFar then followData.StopAct = true end -- If we are close then walk otherwise run self:VJ_TASK_GOTO_TARGET((distToPly < (followData.MinDist * 1.5) and "TASK_WALK_PATH") or "TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemyVisible = (IsValid(self:GetActiveWeapon()) and true) or false end) end elseif followData.Moving == true then -- Entity is very close, stop moving! if !busy then -- If not busy then make it stop moving and do something self:StopMoving() self:SelectSchedule() end followData.Moving = false end self.NextFollowUpdateT = curTime + self.NextFollowUpdateTime end else self:FollowReset() end end //print("MAX CLIP: ", self.CurrentWeaponEntity:GetMaxClip1()) //print("CLIP: ", self.CurrentWeaponEntity:Clip1()) -- Turn to the current face position or entity if self.FacingStatus == VJ_FACING_POSITION then local faceAng = self.FacingData if self.TurningUseAllAxis == true then local myAngs = self:GetAngles() self:SetAngles(LerpAngle(FrameTime()*self.TurningSpeed, myAngs, Angle(faceAng.p, myAngs.y, faceAng.r))) end self:SetIdealYawAndUpdate(faceAng.y) elseif self.FacingStatus == VJ_FACING_ENTITY then local faceEnt = self.FacingData if IsValid(faceEnt) then local faceAng = self:GetFaceAngle((faceEnt:GetPos() - self:GetPos()):Angle()) if self.TurningUseAllAxis == true then local myAngs = self:GetAngles() self:SetAngles(LerpAngle(FrameTime()*self.TurningSpeed, myAngs, Angle(faceAng.p, myAngs.y, faceAng.r))) end self:SetIdealYawAndUpdate(faceAng.y) end end /*VJ_CreateTestObject(self:GetEnemyLastSeenPos()) print(self:HasEnemyMemory()) print(curTime - self:GetEnemyLastTimeSeen()) print(curTime - self:GetEnemyFirstTimeSeen())*/ if !self.Dead then -- Health Regeneration System if self.HasHealthRegeneration == true && curTime > self.HealthRegenerationDelayT then local myHP = self:Health() self:SetHealth(math_clamp(myHP + self.HealthRegenerationAmount, myHP, self:GetMaxHealth())) self.HealthRegenerationDelayT = curTime + math.Rand(self.HealthRegenerationDelay.a, self.HealthRegenerationDelay.b) end -- Run the heavy processes if curTime > self.NextProcessT then self:SetupRelationships() self:CheckForDangers() self:DoMedicCheck() self.NextProcessT = curTime + self.NextProcessTime end local plyControlled = self.VJ_IsBeingControlled local myPos = self:GetPos() local ene = self:GetEnemy() local eneValid = IsValid(ene) if eneData.Reset == false then -- Reset enemy if it doesn't exist or it's dead if (!eneValid) or (eneValid && ene:Health() <= 0) then eneData.Reset = true self:ResetEnemy(true) ene = self:GetEnemy() eneValid = IsValid(ene) end -- Reset enemy if it has been unseen for a while if (curTime - eneData.LastVisibleTime) > ((self.LatestEnemyDistance < 4000 and self.TimeUntilEnemyLost) or (self.TimeUntilEnemyLost / 2)) && (!self.IsVJBaseSNPC_Tank) then self:PlaySoundSystem("LostEnemy") eneData.Reset = true self:ResetEnemy(true) ene = self:GetEnemy() eneValid = IsValid(ene) end end if self.DoingWeaponAttack == true then self:CapabilitiesRemove(CAP_TURN_HEAD) else self:CapabilitiesAdd(bit.bor(CAP_TURN_HEAD)) end -- Fixes their heads breaking -- If we have a valid weapon... if IsValid(self.CurrentWeaponEntity) then -- Weapon Inventory System if !plyControlled && !self:BusyWithActivity() then // self.IsReloadingWeapon == false if eneValid then if IsValid(self.WeaponInventory.Melee) && ((self.LatestEnemyDistance < self.MeleeAttackDistance) or (self.LatestEnemyDistance < 300 && self.CurrentWeaponEntity:Clip1() <= 0)) && (self:Health() > self:GetMaxHealth() * 0.25) && self.CurrentWeaponEntity != self.WeaponInventory.Melee then if self:GetWeaponState() == VJ_WEP_STATE_RELOADING then self:SetWeaponState() end -- Since the reloading can be cut off, reset it back to false, or else it can mess up its behavior! //timer.Remove("timer_reload_end"..self:EntIndex()) -- No longer needed self.WeaponInventoryStatus = VJ_WEP_INVENTORY_MELEE self:DoChangeWeapon(self.WeaponInventory.Melee, true) elseif self:GetWeaponState() != VJ_WEP_STATE_RELOADING && IsValid(self.WeaponInventory.AntiArmor) && (ene.IsVJBaseSNPC_Tank == true or ene.VJ_IsHugeMonster == true) && self.CurrentWeaponEntity != self.WeaponInventory.AntiArmor then self.WeaponInventoryStatus = VJ_WEP_INVENTORY_ANTI_ARMOR self:DoChangeWeapon(self.WeaponInventory.AntiArmor, true) end end if self:GetWeaponState() != VJ_WEP_STATE_RELOADING then -- Reset weapon status from melee to primary if self.WeaponInventoryStatus == VJ_WEP_INVENTORY_MELEE && (!eneValid or (eneValid && self.LatestEnemyDistance >= 300)) then self.WeaponInventoryStatus = VJ_WEP_INVENTORY_PRIMARY self:DoChangeWeapon(self.WeaponInventory.Primary, true) -- Reset weapon status from anti-armor to primary elseif self.WeaponInventoryStatus == VJ_WEP_INVENTORY_ANTI_ARMOR && (!eneValid or (eneValid && ene.IsVJBaseSNPC_Tank != true && ene.VJ_IsHugeMonster != true)) then self.WeaponInventoryStatus = VJ_WEP_INVENTORY_PRIMARY self:DoChangeWeapon(self.WeaponInventory.Primary, true) end end end -- Weapon Reloading if self.AllowWeaponReloading && !self:BusyWithActivity() && self:GetWeaponState() == VJ_WEP_STATE_READY && (!self.CurrentWeaponEntity.IsMeleeWeapon) && self.AttackType == VJ_ATTACK_NONE && self.VJ_PlayingSequence == false && ((!plyControlled && ((!eneValid && self.CurrentWeaponEntity:GetMaxClip1() > self.CurrentWeaponEntity:Clip1() && (curTime - eneData.TimeSet) > math.random(3, 8) && !self:IsMoving()) or (eneValid && self.CurrentWeaponEntity:Clip1() <= 0))) or (plyControlled && self.VJ_TheController:KeyDown(IN_RELOAD) && self.CurrentWeaponEntity:GetMaxClip1() > self.CurrentWeaponEntity:Clip1())) then self.DoingWeaponAttack = false self.DoingWeaponAttack_Standing = false if !plyControlled then self:SetWeaponState(VJ_WEP_STATE_RELOADING) end self.NextChaseTime = curTime + 2 if eneValid == true then self:PlaySoundSystem("WeaponReload") end -- tsayn han e minag yete teshnami ga! self:CustomOnWeaponReload() if self.DisableWeaponReloadAnimation == false then local function DoReloadAnimation(anim) if VJ_AnimationExists(self, anim) then -- Only if the given animation actually exists! local dur = self:DecideAnimationLength(anim, false, self.WeaponReloadAnimationDecreaseLengthAmount) local wep = self.CurrentWeaponEntity if wep.IsVJBaseWeapon == true then wep:NPC_Reload() end timer.Create("timer_reload_end"..self:EntIndex(), dur, 1, function() if IsValid(self) && IsValid(wep) && self:GetWeaponState() == VJ_WEP_STATE_RELOADING then wep:SetClip1(wep:GetMaxClip1()) if wep.IsVJBaseWeapon == true then wep:CustomOnReload_Finish() end self:SetWeaponState() end end) self:VJ_ACT_PLAYACTIVITY(anim, true, dur, self.WeaponReloadAnimationFaceEnemy, self.WeaponReloadAnimationDelay, {SequenceDuration=dur, PlayBackRateCalculated=true}) self.AllowToDo_WaitForEnemyToComeOut = false -- If NOT controlled by a player AND is a gesture make it stop moving so it doesn't run after the enemy right away if !plyControlled && string.find(anim, "vjges_") then self:StopMoving() end return true -- We have successfully ran the animation! end return false -- The given animation was invalid! end -- Controlled by a player... if plyControlled == true then self:SetWeaponState(VJ_WEP_STATE_RELOADING) DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReload))) -- NOT controlled by a player... else -- NPC is hidden, so attempt to crouch reload if eneValid == true && self:VJ_ForwardIsHidingZone(self:NearestPoint(myPos + self:OBBCenter()), ene:EyePos(), false, {SetLastHiddenTime=true}) == true then -- Behvedadz -- if It does NOT have a cover reload animation, then just play the regular standing reload animation if !DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReloadBehindCover))) then DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReload))) end else -- NPC is NOT hidden... -- Under certain situations, simply do standing reload without running to a hiding spot if self.IsGuard == true or self.IsFollowing == true or self.VJ_IsBeingControlled_Tool == true or eneValid == false or self.MovementType == VJ_MOVETYPE_STATIONARY or self.LatestEnemyDistance < 650 then DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReload))) else -- If all is good, then run to a hiding spot and then reload! if self.WeaponReload_FindCover == true then self:SetMovementActivity(VJ_PICK(self.AnimTbl_Run)) local vsched = ai_vj_schedule.New("vj_weapon_reload") vsched:EngTask("TASK_FIND_COVER_FROM_ENEMY", 0) vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0) vsched.StopScheduleIfNotMoving = true vsched.IsMovingTask = true vsched.MoveType = 1 vsched.RunCode_OnFinish = function() if self:GetWeaponState() == VJ_WEP_STATE_RELOADING then -- If the current situation isn't favorable, then abandon the current reload, and try again! if (self.AttackType != VJ_ATTACK_NONE) or (IsValid(self:GetEnemy()) && self.HasWeaponBackAway == true && (self:GetPos():Distance(self:GetEnemy():GetPos()) <= self.WeaponBackAway_Distance)) then self:SetWeaponState() //timer.Remove("timer_reload_end"..self:EntIndex()) -- Remove the timer to make sure it doesn't set reloading to false at a random time (later on) else -- Our hiding spot is good, so reload! DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReload))) self:CustomOnWeaponReload_AfterRanToCover() end end end self:StartSchedule(vsched) else DoReloadAnimation(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponReload))) end end end end else -- If the reload animation is disabled if self:GetWeaponState() == VJ_WEP_STATE_RELOADING then self:SetWeaponState() end self.CurrentWeaponEntity:SetClip1(self.CurrentWeaponEntity:GetMaxClip1()) self.CurrentWeaponEntity:NPC_Reload() end end end if eneValid then local enePos = ene:GetPos() if self.DoingWeaponAttack then self:PlaySoundSystem("Suppressing") end -- Set latest enemy information self:UpdateEnemyMemory(ene, enePos) eneData.Reset = false eneData.IsVisible = plyControlled and self:VisibleVec(enePos) or self:Visible(ene) -- Need to use VisibleVec when controlled because "Visible" will return false randomly eneData.SightDiff = self:GetSightDirection():Dot((enePos - myPos):GetNormalized()) self.LatestEnemyDistance = myPos:Distance(enePos) self.NearestPointToEnemyDistance = self:VJ_GetNearestPointToEntityDistance(ene) if (eneData.SightDiff > math_cos(math_rad(self.SightAngle))) && (self.LatestEnemyDistance < self:GetMaxLookDistance()) && eneData.IsVisible then eneData.LastVisibleTime = curTime eneData.LastVisiblePos = enePos end -- Turning / Facing Enemy if self.ConstantlyFaceEnemy then self:DoConstantlyFaceEnemy() end if self.FacingStatus == VJ_FACING_ENEMY or (self.CombatFaceEnemy == true && self.CurrentSchedule != nil && ((self.CurrentSchedule.ConstantlyFaceEnemy == true) or (self.CurrentSchedule.ConstantlyFaceEnemyVisible == true && eneData.IsVisible))) then local faceAng = self:GetFaceAngle((enePos - myPos):Angle()) if self.TurningUseAllAxis == true then local myAngs = self:GetAngles() self:SetAngles(LerpAngle(FrameTime()*self.TurningSpeed, myAngs, Angle(faceAng.p, myAngs.y, faceAng.r))) end self:SetIdealYawAndUpdate(faceAng.y) end -- Call for help if self.AttackType != VJ_ATTACK_GRENADE && self.CallForHelp == true && curTime > self.NextCallForHelpT then self:Allies_CallHelp(self.CallForHelpDistance) self.NextCallForHelpT = curTime + self.NextCallForHelpTime end -- Grenade attack if self.HasGrenadeAttack && self:GetState() != VJ_STATE_ONLY_ANIMATION_NOATTACK && self:GetWeaponState() != VJ_WEP_STATE_RELOADING && !self:BusyWithActivity() && curTime > self.NextThrowGrenadeT && curTime > self.TakingCoverT then if plyControlled && self.VJ_TheController:KeyDown(IN_JUMP) then self:ThrowGrenadeCode() self.NextThrowGrenadeT = curTime + math.random(self.NextThrowGrenadeTime.a, self.NextThrowGrenadeTime.b) elseif !plyControlled then local chance = self.ThrowGrenadeChance -- If chance is above 4, then half it by 2 if the enemy is a tank OR not visible if math.random(1, (chance > 3 && (ene.IsVJBaseSNPC_Tank or !eneData.IsVisible) and math.floor(chance / 2)) or chance) == 1 && self.LatestEnemyDistance < self.GrenadeAttackThrowDistance && self.LatestEnemyDistance > self.GrenadeAttackThrowDistanceClose then self:ThrowGrenadeCode() end self.NextThrowGrenadeT = curTime + math.random(self.NextThrowGrenadeTime.a, self.NextThrowGrenadeTime.b) end end -- Sets the scared behavior movement activity if !IsValid(self.CurrentWeaponEntity) && self.NoWeapon_UseScaredBehavior && !plyControlled then local anim = VJ_PICK(self.AnimTbl_ScaredBehaviorMovement) if anim != false then self:SetMovementActivity(anim) else if VJ_AnimationExists(self, ACT_RUN_PROTECTED) == true then self:SetMovementActivity(ACT_RUN_PROTECTED) elseif VJ_AnimationExists(self, ACT_RUN_CROUCH_RIFLE) == true then self:SetMovementActivity(ACT_RUN_CROUCH_RIFLE) end end //self:SetArrivalActivity(VJ_PICK(self.AnimTbl_ScaredBehaviorStand)) -- Already done by self.CurrentAnim_IdleStand end if !eneData.IsVisible then self.DoingWeaponAttack = false self.DoingWeaponAttack_Standing = false end self:DoWeaponAttackMovementCode() self:DoPoseParameterLooking() -- Face enemy for stationary types OR attacks if (self.MovementType == VJ_MOVETYPE_STATIONARY && self.CanTurnWhileStationary == true) or (self.MeleeAttackAnimationFaceEnemy == true && self.AttackType == VJ_ATTACK_MELEE) or (self.GrenadeAttackAnimationFaceEnemy == true && self.AttackType == VJ_ATTACK_GRENADE && eneData.IsVisible == true) then self:FaceCertainEntity(ene, true) end if !self.vACT_StopAttacks && self:GetState() != VJ_STATE_ONLY_ANIMATION_NOATTACK && self.Behavior != VJ_BEHAVIOR_PASSIVE && self.Behavior != VJ_BEHAVIOR_PASSIVE_NATURE && curTime > self.NextDoAnyAttackT then self:CustomAttack(ene, eneData.IsVisible) -- Custom attack -- Melee Attack if self.HasMeleeAttack == true && !self.vACT_StopAttacks && !self.Flinching && !self.FollowData.StopAct && self.AttackType == VJ_ATTACK_NONE && self.IsAbleToMeleeAttack && (!IsValid(self.CurrentWeaponEntity) or (IsValid(self.CurrentWeaponEntity) && (!self.CurrentWeaponEntity.IsMeleeWeapon))) && ((plyControlled == true && self.VJ_TheController:KeyDown(IN_ATTACK)) or (plyControlled == false && (self.NearestPointToEnemyDistance < self.MeleeAttackDistance && eneData.IsVisible) && (eneData.SightDiff > math_cos(math_rad(self.MeleeAttackAngleRadius))))) then local seed = curTime; self.CurAttackSeed = seed self.AttackType = VJ_ATTACK_MELEE self.AttackStatus = VJ_ATTACK_STATUS_STARTED self.MeleeAttacking = true self.IsAbleToMeleeAttack = false self:FaceCertainEntity(ene, true) self:CustomOnMeleeAttack_BeforeStartTimer(seed) timer.Simple(self.BeforeMeleeAttackSounds_WaitTime, function() if IsValid(self) then self:PlaySoundSystem("BeforeMeleeAttack") end end) self.NextAlertSoundT = curTime + 0.4 if self.DisableMeleeAttackAnimation == false then self.CurrentAttackAnimation = VJ_PICK(self.AnimTbl_MeleeAttack) self.CurrentAttackAnimationDuration = self:DecideAnimationLength(self.CurrentAttackAnimation, false, self.MeleeAttackAnimationDecreaseLengthAmount) if self.MeleeAttackAnimationAllowOtherTasks == false then -- Useful for gesture-based attacks self.PlayingAttackAnimation = true timer.Create("timer_act_playingattack"..self:EntIndex(), self.CurrentAttackAnimationDuration, 1, function() self.PlayingAttackAnimation = false end) end self:VJ_ACT_PLAYACTIVITY(self.CurrentAttackAnimation,false,0,false,self.MeleeAttackAnimationDelay,{SequenceDuration=self.CurrentAttackAnimationDuration}) end if self.TimeUntilMeleeAttackDamage == false then finishAttack[VJ_ATTACK_MELEE](self) else -- If it's not event based... timer.Create("timer_melee_start"..self:EntIndex(), self.TimeUntilMeleeAttackDamage / self:GetPlaybackRate(), self.MeleeAttackReps, function() if self.CurAttackSeed == seed then self:MeleeAttackCode() end end) if self.MeleeAttackExtraTimers then for k, t in ipairs(self.MeleeAttackExtraTimers) do self:DoAddExtraAttackTimers("timer_melee_start"..curTime + k, t, function() if self.CurAttackSeed == seed then self:MeleeAttackCode() end end) end end end self:CustomOnMeleeAttack_AfterStartTimer(seed) end end else -- No Enemy self.DoingWeaponAttack = false self.DoingWeaponAttack_Standing = false if !self.Alerted && self.DidWeaponAttackAimParameter && !plyControlled then self:ClearPoseParameters() self.DidWeaponAttackAimParameter = false end if self:GetArrivalActivity() == self.CurrentWeaponAnimation then self:SetArrivalActivity(self.CurrentAnim_IdleStand) end eneData.TimeSinceAcquired = 0 if eneData.Reset == false && (!self.IsVJBaseSNPC_Tank) then self:PlaySoundSystem("LostEnemy") eneData.Reset = true self:ResetEnemy(true) end end -- Guarding Position if self.IsGuard == true && self.IsFollowing == false then if self.GuardingPosition == nil then -- If it hasn't been set then set the guard position to its current position self.GuardingPosition = myPos self.GuardingFacePosition = myPos + self:GetForward()*51 end -- If it's far from the guarding position, then go there! if !self:IsMoving() && self:BusyWithActivity() == false then local dist = myPos:Distance(self.GuardingPosition) -- Distance to the guard position if dist > 50 then self:SetLastPosition(self.GuardingPosition) self:VJ_TASK_GOTO_LASTPOS(dist <= 800 and "TASK_WALK_PATH" or "TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true x.RunCode_OnFinish = function() timer.Simple(0.01, function() if IsValid(self) && !self:IsMoving() && self:BusyWithActivity() == false && self.GuardingFacePosition != nil then self:SetLastPosition(self.GuardingFacePosition) self:VJ_TASK_FACE_X("TASK_FACE_LASTPOSITION") end end) end end) end end end end else -- AI Not enabled self.DoingWeaponAttack = false end self:NextThink(curTime + (0.069696968793869 + FrameTime())) return true end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:MeleeAttackCode(customEnt) if self.Dead or self.vACT_StopAttacks or self.Flinching or self.AttackType == VJ_ATTACK_GRENADE or (self.StopMeleeAttackAfterFirstHit && self.AttackStatus == VJ_ATTACK_STATUS_EXECUTED_HIT) then return end local curEnemy = customEnt or self:GetEnemy() if self.MeleeAttackAnimationFaceEnemy then self:FaceCertainEntity(curEnemy, true) end //self.MeleeAttacking = true self:CustomOnMeleeAttack_BeforeChecks() if self.DisableDefaultMeleeAttackCode then return end local myPos = self:GetPos() local hitRegistered = false for _, v in ipairs(ents.FindInSphere(self:GetMeleeAttackDamageOrigin(), self.MeleeAttackDamageDistance)) do if (self.VJ_IsBeingControlled && self.VJ_TheControllerBullseye == v) or (v:IsPlayer() && v.IsControlingNPC == true) then continue end -- If controlled and v is the bullseye OR it's a player controlling then don't damage! if v != self && v:GetClass() != self:GetClass() && (((v:IsNPC() or (v:IsPlayer() && v:Alive() && !VJ_CVAR_IGNOREPLAYERS)) && self:Disposition(v) != D_LI) or IsProp(v) == true or v:GetClass() == "func_breakable_surf" or destructibleEnts[v:GetClass()] or v.VJ_AddEntityToSNPCAttackList == true) && self:GetSightDirection():Dot((Vector(v:GetPos().x, v:GetPos().y, 0) - Vector(myPos.x, myPos.y, 0)):GetNormalized()) > math_cos(math_rad(self.MeleeAttackDamageAngleRadius)) then local vProp = IsProp(v) if self:CustomOnMeleeAttack_AfterChecks(v, vProp) == true then continue end -- Knockback if self.HasMeleeAttackKnockBack && v.MovementType != VJ_MOVETYPE_STATIONARY && (!v.VJ_IsHugeMonster or v.IsVJBaseSNPC_Tank) then v:SetGroundEntity(NULL) v:SetVelocity(self:MeleeAttackKnockbackVelocity(v)) end -- Apply actual damage if !self.DisableDefaultMeleeAttackDamageCode then local applyDmg = DamageInfo() applyDmg:SetDamage(self:VJ_GetDifficultyValue(self.MeleeAttackDamage)) applyDmg:SetDamageType(self.MeleeAttackDamageType) //applyDmg:SetDamagePosition(self:VJ_GetNearestPointToEntity(v).MyPosition) if v:IsNPC() or v:IsPlayer() then applyDmg:SetDamageForce(self:GetForward() * ((applyDmg:GetDamage() + 100) * 70)) end applyDmg:SetInflictor(self) applyDmg:SetAttacker(self) v:TakeDamageInfo(applyDmg, self) end if v:IsPlayer() then v:ViewPunch(Angle(math.random(-1, 1) * self.MeleeAttackDamage, math.random(-1, 1) * self.MeleeAttackDamage, math.random(-1, 1) * self.MeleeAttackDamage)) end VJ_DestroyCombineTurret(self,v) if !vProp then -- Only for non-props... hitRegistered = true end end end if self.AttackStatus < VJ_ATTACK_STATUS_EXECUTED then self.AttackStatus = VJ_ATTACK_STATUS_EXECUTED if self.TimeUntilMeleeAttackDamage != false then finishAttack[VJ_ATTACK_MELEE](self) end end if hitRegistered == true then self:PlaySoundSystem("MeleeAttack") self.AttackStatus = VJ_ATTACK_STATUS_EXECUTED_HIT else self:CustomOnMeleeAttack_Miss() self:PlaySoundSystem("MeleeAttackMiss", {}, VJ_EmitSound) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:ThrowGrenadeCode(customEnt, noOwner) if self.Dead or self.Flinching == true or self.AttackType == VJ_ATTACK_MELEE /*or (IsValid(self:GetEnemy()) && !self:Visible(self:GetEnemy()))*/ then return end //if self:VJ_ForwardIsHidingZone(self:NearestPoint(self:GetPos() + self:OBBCenter()),self:GetEnemy():EyePos()) == true then return end noOwner = noOwner or false local getIsCustom = false local gerModel = VJ_PICK(self.GrenadeAttackModel) local gerClass = self.GrenadeAttackEntity local gerFussTime = self.GrenadeAttackFussTime local eneData = self.EnemyData if IsValid(self:GetEnemy()) && !eneData.IsVisible then if self:VisibleVec(eneData.LastVisiblePos) && self:GetEnemy():GetPos():Distance(eneData.LastVisiblePos) <= 600 then self:FaceCertainPosition(eneData.LastVisiblePos) else return end end if self.DisableGrenadeAttackAnimation == false then self.CurrentAttackAnimation = VJ_PICK(self.AnimTbl_GrenadeAttack) self.CurrentAttackAnimationDuration = self:DecideAnimationLength(self.CurrentAttackAnimation, false, 0.2) self.PlayingAttackAnimation = true timer.Create("timer_act_playingattack"..self:EntIndex(), self.CurrentAttackAnimationDuration, 1, function() self.PlayingAttackAnimation = false end) self:VJ_ACT_PLAYACTIVITY(self.CurrentAttackAnimation, self.GrenadeAttackAnimationStopAttacks, self:DecideAnimationLength(self.CurrentAttackAnimation, self.GrenadeAttackAnimationStopAttacksTime), true, self.GrenadeAttackAnimationDelay, {PlayBackRateCalculated=true}) end if IsValid(customEnt) then -- Custom nernagner gamal nernagner vor yete bidi nede local getSpawnPos = self.GrenadeAttackAttachment local getSpawnAngle; if getSpawnPos == false then getSpawnPos = self:CustomOnGrenadeAttack_SpawnPosition() getSpawnAngle = getSpawnPos:Angle() else getSpawnPos = self:GetAttachment(self:LookupAttachment(self.GrenadeAttackAttachment)).Pos getSpawnAngle = self:GetAttachment(self:LookupAttachment(self.GrenadeAttackAttachment)).Ang end getIsCustom = true gerModel = customEnt:GetModel() gerClass = customEnt:GetClass() customEnt:SetMoveType(MOVETYPE_NONE) customEnt:SetParent(self) if self.GrenadeAttackAttachment == false then customEnt:SetPos(getSpawnPos) else customEnt:Fire("SetParentAttachment", self.GrenadeAttackAttachment) end customEnt:SetAngles(getSpawnAngle) if gerClass == "obj_vj_grenade" then gerFussTime = math.abs(customEnt.FussTime - customEnt.TimeSinceSpawn) elseif gerClass == "obj_handgrenade" or gerClass == "obj_spore" then gerFussTime = 1 elseif gerClass == "npc_grenade_frag" or gerClass == "doom3_grenade" or gerClass == "fas2_thrown_m67" or gerClass == "cw_grenade_thrown" or gerClass == "cw_flash_thrown" or gerClass == "cw_smoke_thrown" then gerFussTime = 1.5 elseif gerClass == "obj_cpt_grenade" then gerFussTime = 2 end end if !IsValid(self:GetEnemy()) then local sideCheck = VJ_PICK(self:VJ_CheckAllFourSides(200, true)) if sideCheck then self:FaceCertainPosition(sideCheck, self.CurrentAttackAnimationDuration or 1.5) doit = true end end self.AttackType = VJ_ATTACK_GRENADE self.ThrowingGrenade = true self:CustomOnGrenadeAttack_BeforeStartTimer() self:PlaySoundSystem("GrenadeAttack") timer.Simple(self.TimeUntilGrenadeIsReleased, function() if getIsCustom == true && !IsValid(customEnt) then return end if IsValid(customEnt) then customEnt.VJ_IsPickedUpDanger = false customEnt:Remove() end if IsValid(self) && !self.Dead /*&& IsValid(self:GetEnemy())*/ then -- Yete SNPC ter artoon e... local getSpawnPos = self.GrenadeAttackAttachment local getSpawnAngle; if getSpawnPos == false then getSpawnPos = self:CustomOnGrenadeAttack_SpawnPosition() getSpawnAngle = getSpawnPos:Angle() else getSpawnPos = self:GetAttachment(self:LookupAttachment(self.GrenadeAttackAttachment)).Pos getSpawnAngle = self:GetAttachment(self:LookupAttachment(self.GrenadeAttackAttachment)).Ang end local greTargetPos = self:GetPos() + self:GetForward()*200 if IsValid(self:GetEnemy()) then eneData = self.EnemyData if !eneData.IsVisible && self:VisibleVec(eneData.LastVisiblePos) && self:GetEnemy():GetPos():Distance(eneData.LastVisiblePos) <= 600 then greTargetPos = eneData.LastVisiblePos self:FaceCertainPosition(greTargetPos, self.CurrentAttackAnimationDuration - self.TimeUntilGrenadeIsReleased) else greTargetPos = self:GetEnemy():GetPos() end else -- Yete teshnami chooni, nede amenan lav goghme if !IsValid(self:GetEnemy()) then local test = self:VJ_CheckAllFourSides(200, true) local sideCheck = VJ_PICK(test) if sideCheck then greTargetPos = sideCheck self:FaceCertainPosition(sideCheck, self.CurrentAttackAnimationDuration - self.TimeUntilGrenadeIsReleased) end end end local gent = ents.Create(gerClass) if noOwner == false then gent:SetOwner(self) end gent:SetPos(getSpawnPos) gent:SetAngles(getSpawnAngle) if gerModel then gent:SetModel(Model(gerModel)) end local getThrowVel = self:CustomOnGrenadeAttack_ThrowVelocity(gent, greTargetPos, getSpawnPos) -- Set the timers for all the different grenade entities if gerClass == "obj_vj_grenade" then gent.FussTime = gerFussTime elseif gerClass == "obj_cpt_grenade" then gent:SetTimer(gerFussTime) elseif gerClass == "obj_spore" then gent:SetGrenade(true) elseif gerClass == "ent_hl1_grenade" then gent:ShootTimed(customEnt, getThrowVel, gerFussTime) elseif gerClass == "doom3_grenade" or gerClass == "obj_handgrenade" then gent:SetExplodeDelay(gerFussTime) elseif gerClass == "cw_grenade_thrown" or gerClass == "cw_flash_thrown" or gerClass == "cw_smoke_thrown" then gent:SetOwner(self) gent:Fuse(gerFussTime) end gent:Spawn() gent:Activate() if gerClass == "npc_grenade_frag" then gent:Input("SetTimer",self:GetOwner(),self:GetOwner(),gerFussTime) end local phys = gent:GetPhysicsObject() if IsValid(phys) then phys:Wake() phys:AddAngleVelocity(Vector(math.Rand(500, 500), math.Rand(500, 500), math.Rand(500, 500))) phys:SetVelocity(getThrowVel) end self:CustomOnGrenadeAttack_OnThrow(gent) end if self.AttackType == VJ_ATTACK_GRENADE then self.AttackType = VJ_ATTACK_NONE end self.ThrowingGrenade = false end) end --------------------------------------------------------------------------------------------------------------------------------------------- /* Old system (Replaced by condition system) local getSdHint = sound.GetLoudestSoundHint local sdBitSource = bit.bor(SOUND_DANGER, SOUND_CONTEXT_REACT_TO_SOURCE) ---> Combine dropship impact position, Combine gunship turret impact position, Strider minigun impact position local sdBitCombine = bit.bor(SOUND_DANGER, SOUND_CONTEXT_EXCLUDE_COMBINE) ---> Flechette impact position, Strider foot impact position local sdBitPlyVehicle = bit.bor(SOUND_DANGER, SOUND_CONTEXT_PLAYER_VEHICLE) ---> Player driving a vehicle local sdBitMortar = bit.bor(SOUND_DANGER, SOUND_CONTEXT_MORTAR) ---> Combine mortars impact position -- function ENT:GetPossibleDangers() local myPos = self:GetPos() return getSdHint(SOUND_DANGER, myPos) or getSdHint(sdBitSource, myPos) or getSdHint(sdBitCombine, myPos) or getSdHint(sdBitPlyVehicle, myPos) or getSdHint(sdBitMortar, myPos) end */ --------------------------------------------------------------------------------------------------------------------------------------------- --[[--------------------------------------------------------- 3 types of danger detections: - ent.VJ_IsDetectableGrenade - Detected as a grenade - Distance based on self.DangerDetectionDistance - Ignores grenades from allies - BEST USE: Grenade type of entities - ent.VJ_IsDetectableDanger - Detected as a danger - Distance based on self.DangerDetectionDistance - Ignores dangers from allies - BEST USE: Entities that should NOT scare the owner's allies, commonly used for projectiles - NPC Conditions (Old system: sound.EmitHint) - Detected as a danger - Distance based on the sound hint's volume/distance - Does NOT ignore, is detected by everyone that catches the hint, including allies - BEST USE: Sounds that should scare the owner's allies -----------------------------------------------------------]] function ENT:CheckForDangers() if !self.CanDetectDangers or self.AttackType == VJ_ATTACK_GRENADE or self.NextDangerDetectionT > CurTime() or self.VJ_IsBeingControlled then return end local regDangerDetected = false -- A regular non-grenade danger has been found (This is done to make sure grenades take priority over other dangers!) for _, v in ipairs(ents.FindInSphere(self:GetPos(), self.DangerDetectionDistance)) do if (v.VJ_IsDetectableDanger or v.VJ_IsDetectableGrenade) && self:Visible(v) then local vOwner = v:GetOwner() if !(IsValid(vOwner) && vOwner.IsVJBaseSNPC && ((self:GetClass() == vOwner:GetClass()) or (self:Disposition(vOwner) == D_LI))) then if v.VJ_IsDetectableDanger then regDangerDetected = true continue end -- If it's a regular danger then just skip it for now self:PlaySoundSystem("OnGrenadeSight") self.NextDangerDetectionT = CurTime() + 4 self.TakingCoverT = CurTime() + 4 -- If has the ability to throw it back, then throw the grenade! if self.CanThrowBackDetectedGrenades && self.HasGrenadeAttack && v.VJ_IsPickupableDanger && !v.VJ_IsPickedUpDanger && v:GetVelocity():Length() < 400 && self:VJ_GetNearestPointToEntityDistance(v) < 100 then self.NextGrenadeAttackSoundT = CurTime() + 3 self:ThrowGrenadeCode(v, true) v.VJ_IsPickedUpDanger = true //v:Remove() return end self:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) return end end end if regDangerDetected or self:HasCondition(COND_HEAR_DANGER) or self:HasCondition(COND_HEAR_PHYSICS_DANGER) or self:HasCondition(COND_HEAR_MOVE_AWAY) then self:PlaySoundSystem("OnDangerSight") self.NextDangerDetectionT = CurTime() + 4 self.TakingCoverT = CurTime() + 4 self:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) return end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:StopAttacks(checkTimers) if self:Health() <= 0 then return end if self.VJ_DEBUG == true && GetConVar("vj_npc_printstoppedattacks"):GetInt() == 1 then print(self:GetClass().." Stopped all Attacks!") end if checkTimers == true && self.AttackType == VJ_ATTACK_MELEE && self.AttackStatus < VJ_ATTACK_STATUS_EXECUTED then finishAttack[VJ_ATTACK_MELEE](self, true) end self.AttackType = VJ_ATTACK_NONE self.AttackStatus = VJ_ATTACK_STATUS_DONE self.CurAttackSeed = 0 self.MeleeAttacking = false self:DoChaseAnimation() end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:WeaponAimPoseParameters(resetPoses) self:DoPoseParameterLooking(resetPoses) end -- !!!!!!!!!!!!!! DO NOT USE THIS FUNCTION !!!!!!!!!!!!!! [Backwards Compatibility!] --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:DoPoseParameterLooking(resetPoses) if (self.HasPoseParameterLooking == false) or (self.VJ_IsBeingControlled == false && self.DoingWeaponAttack == false) then return end resetPoses = resetPoses or false //self:GetPoseParameters(true) local ent = (self.VJ_IsBeingControlled and self.VJ_TheController) or self:GetEnemy() local p_enemy = 0 -- Pitch local y_enemy = 0 -- Yaw local r_enemy = 0 -- Roll if IsValid(ent) && !resetPoses then local enemy_pos = (self.VJ_IsBeingControlled and self.VJ_TheControllerBullseye:GetPos()) or ent:GetPos() + ent:OBBCenter() local self_ang = self:GetAngles() local enemy_ang = (enemy_pos - (self:GetPos() + self:OBBCenter())):Angle() p_enemy = math_angDif(enemy_ang.p, self_ang.p) if self.PoseParameterLooking_InvertPitch == true then p_enemy = -p_enemy end y_enemy = math_angDif(enemy_ang.y, self_ang.y) if self.PoseParameterLooking_InvertYaw == true then y_enemy = -y_enemy end r_enemy = math_angDif(enemy_ang.z, self_ang.z) if self.PoseParameterLooking_InvertRoll == true then r_enemy = -r_enemy end elseif !self.PoseParameterLooking_CanReset then -- Should it reset its pose parameters if there is no enemies? return end self:CustomOn_PoseParameterLookingCode(p_enemy, y_enemy, r_enemy) local names = self.PoseParameterLooking_Names for x = 1, #names.pitch do self:SetPoseParameter(names.pitch[x], math_angApproach(self:GetPoseParameter(names.pitch[x]), p_enemy, self.PoseParameterLooking_TurningSpeed)) end for x = 1, #names.yaw do self:SetPoseParameter(names.yaw[x], math_angApproach(self:GetPoseParameter(names.yaw[x]), y_enemy, self.PoseParameterLooking_TurningSpeed)) end for x = 1, #names.roll do self:SetPoseParameter(names.roll[x], math_angApproach(self:GetPoseParameter(names.roll[x]), r_enemy, self.PoseParameterLooking_TurningSpeed)) end self.DidWeaponAttackAimParameter = true end -------------------------------------------------------------------------------------------------------------------------------------------- function ENT:DoWeaponAttackMovementCode(override, moveType) override = override or false -- Overrides some of the checks, only used for the internal task system! moveType = moveType or 0 -- This is used with override | 0 = Run, 1 = Walk if (self.CurrentWeaponEntity.IsMeleeWeapon) then self.DoingWeaponAttack = true elseif self.HasShootWhileMoving == true then if self.EnemyData.IsVisible && self:IsAbleToShootWeapon(true, false) == true && ((self:IsMoving() && (self.CurrentSchedule != nil && self.CurrentSchedule.CanShootWhenMoving == true)) or (override == true)) then if (override == true && moveType == 0) or (self.CurrentSchedule != nil && self.CurrentSchedule.MoveType == 1) then local anim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_ShootWhileMovingRun)) if VJ_AnimationExists(self,anim) == true then self.DoingWeaponAttack = true self.DoingWeaponAttack_Standing = false self:CapabilitiesAdd(bit.bor(CAP_MOVE_SHOOT)) self:SetMovementActivity(anim) self:SetArrivalActivity(self.CurrentWeaponAnimation) end elseif (override == true && moveType == 1) or (self.CurrentSchedule != nil && self.CurrentSchedule.MoveType == 0) then local anim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_ShootWhileMovingWalk)) if VJ_AnimationExists(self,anim) == true then self.DoingWeaponAttack = true self.DoingWeaponAttack_Standing = false self:CapabilitiesAdd(bit.bor(CAP_MOVE_SHOOT)) self:SetMovementActivity(anim) self:SetArrivalActivity(self.CurrentWeaponAnimation) end end end else -- Can't move shoot! self:CapabilitiesRemove(CAP_MOVE_SHOOT) -- Remove the capability if it can't even move-shoot end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:IsAbleToShootWeapon(checkDistance, checkDistanceOnly, enemyDist) checkDistance = checkDistance or false -- Check for distance and weapon time as well? checkDistanceOnly = checkDistanceOnly or false -- Should it only check the above statement? enemyDist = enemyDist or self:EyePos():Distance(self:GetEnemy():EyePos()) -- Distance used for checkDistance if self:CustomOnIsAbleToShootWeapon() == false then return end local hasDist = false local hasChecks = false if self:GetWeaponState() == VJ_WEP_STATE_HOLSTERED or self.vACT_StopAttacks then return false end if self.VJ_IsBeingControlled then checkDistance = false checkDistanceOnly = false end if checkDistance == true && CurTime() > self.NextWeaponAttackT && enemyDist < self.Weapon_FiringDistanceFar && ((enemyDist > self.Weapon_FiringDistanceClose) or self.CurrentWeaponEntity.IsMeleeWeapon) then hasDist = true end if checkDistanceOnly == true then if hasDist == true then return true else return false end end if IsValid(self:GetActiveWeapon()) && self.AttackType != VJ_ATTACK_GRENADE && self:BusyWithActivity() == false && ((self:GetActiveWeapon().IsMeleeWeapon) or (self:GetWeaponState() != VJ_WEP_STATE_RELOADING && self.AttackType != VJ_ATTACK_MELEE && self.NearestPointToEnemyDistance > self.MeleeAttackDistance)) then hasChecks = true if checkDistance == false then return true end end if checkDistanceOnly == false && hasDist == true && hasChecks == true then return true end return false end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:SelectSchedule() if self.VJ_IsBeingControlled then return end self:CustomOnSchedule() if self.DisableSelectSchedule == true or self.Dead then return end local ene = self:GetEnemy() -- Idle Behavior -- if !IsValid(ene) then self:IdleSoundCode() if self.AttackType != VJ_ATTACK_GRENADE then self:DoIdleAnimation() end if self.Alerted == false then self.TakingCoverT = 0 end self.NoWeapon_UseScaredBehavior_Active = false -- Combat Behavior -- else local wep = self:GetActiveWeapon() local myPos = self:GetPos() -- If the enemy is in sight then continue if self.LatestEnemyDistance < self:GetMaxLookDistance() then self:IdleSoundCode() -- Check for weapon validity if !IsValid(wep) then -- Scared behavior system if self.NoWeapon_UseScaredBehavior then if !self:IsBusy() && CurTime() > self.NextChaseTime then self.NoWeapon_UseScaredBehavior_Active = true -- Tells the idle system to use the scared behavior animation if self.IsFollowing == false && self.EnemyData.IsVisible then self:VJ_TASK_COVER_FROM_ENEMY("TASK_RUN_PATH") return end end elseif self.HasMeleeAttack then -- If it doesn't do scared behavior, then make it chase the enemy if it can melee! self.NoWeapon_UseScaredBehavior_Active = false -- In case it was scared, return it back to normal self.NextDangerDetectionT = CurTime() + 4 -- Ignore dangers while chasing! self:DoChaseAnimation() return end self:DoIdleAnimation(2) return end self.NoWeapon_UseScaredBehavior_Active = false -- In case it was scared, return it back to normal local enePos_Eye = ene:EyePos() local eneDist_Eye = self:EyePos():Distance(enePos_Eye) local myPosCentered = myPos + self:OBBCenter() local canAttack = true -- Back away from the enemy if it's to close if self.HasWeaponBackAway == true && (!wep.IsMeleeWeapon) && self.LatestEnemyDistance <= self.WeaponBackAway_Distance && CurTime() > self.TakingCoverT && CurTime() > self.NextChaseTime && self.AttackType == VJ_ATTACK_NONE && !self.IsFollowing && !self.VJ_PlayingSequence && ene.Behavior != VJ_BEHAVIOR_PASSIVE && self:VJ_ForwardIsHidingZone(self:NearestPoint(myPosCentered), enePos_Eye) == false then local moveCheck = VJ_PICK(self:VJ_CheckAllFourSides(200, true, "0111")) if moveCheck then self:SetLastPosition(moveCheck) if self:GetWeaponState() == VJ_WEP_STATE_RELOADING then self:SetWeaponState() end self.TakingCoverT = CurTime() + 2 canAttack = false self:VJ_TASK_GOTO_LASTPOS("TASK_RUN_PATH", function(x) x:EngTask("TASK_FACE_ENEMY", 0) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) end end if canAttack && self:IsAbleToShootWeapon(false, false, eneDist_Eye) == true && self:GetState() != VJ_STATE_ONLY_ANIMATION_NOATTACK then -- Enemy to far away or not allowed to fire a weapon if eneDist_Eye > self.Weapon_FiringDistanceFar or CurTime() < self.NextWeaponAttackT then self:DoChaseAnimation() self.AllowToDo_WaitForEnemyToComeOut = false -- Check if enemy is in sight, then continue... elseif self:IsAbleToShootWeapon(true, true, eneDist_Eye) == true then //self:VJ_ForwardIsHidingZone(self:EyePos(), enePos_Eye, true, {Debug=true}) -- If I can't see the enemy then either wait for it or charge at the enemy if self:VJ_ForwardIsHidingZone(self:EyePos(), enePos_Eye, true) == true && self:VJ_ForwardIsHidingZone(self:NearestPoint(myPosCentered) + self:GetUp()*30, enePos_Eye + self:GetUp()*30, true) /*or self:VJ_ForwardIsHidingZone(util.VJ_GetWeaponPos(self),enePos_Eye) == true*/ /*or (!self.EnemyData.IsVisible)*/ then if self:GetWeaponState() != VJ_WEP_STATE_RELOADING then -- Wait for the enemy to come out if self.WaitForEnemyToComeOut && !self.WaitingForEnemyToComeOut && (!wep.IsMeleeWeapon) && self.AllowToDo_WaitForEnemyToComeOut && ((CurTime() - self.Weapon_TimeSinceLastShot) <= 4.5) && (eneDist_Eye > self.WaitForEnemyToComeOutDistance) then self.WaitingForEnemyToComeOut = true if self.HasLostWeaponSightAnimation == true then self:VJ_ACT_PLAYACTIVITY(self.AnimTbl_WeaponAim, false, 0, true) end self.NextChaseTime = CurTime() + math.Rand(self.WaitForEnemyToComeOutTime.a, self.WaitForEnemyToComeOutTime.b) -- If I am not supposed to wait for the enemy, then go after the enemy! elseif /*self.DisableChasingEnemy == false &&*/ CurTime() > self.LastHiddenZoneT then self.DoingWeaponAttack = false self.DoingWeaponAttack_Standing = false self:DoChaseAnimation() end end else -- I can see the enemy... self.AllowToDo_WaitForEnemyToComeOut = true if (wep.IsVJBaseWeapon) then -- VJ Base weapons self:FaceCertainEntity(ene, true) local noAttack = false // self:DoChaseAnimation() -- if covered, try to move forward by calculating the distance between the prop and the NPC local cover_npc, cover_npc_tr = self:VJ_ForwardIsHidingZone(self:NearestPoint(myPosCentered), enePos_Eye, false, {SetLastHiddenTime=true}) local cover_npc_ent = cover_npc_tr.Entity local cover_wep, cover_wep_tr = self:VJ_ForwardIsHidingZone(wep:GetNW2Vector("VJ_CurBulletPos"), enePos_Eye, false) local cover_wep_ent = cover_wep_tr.Entity //print("Is covered? ", cover_npc) //print("Is gun covered? ", cover_wep) local cover_npc_isObj = true -- The covered entity is NOT an NPC / Player if cover_npc == false or (IsValid(cover_npc_ent) and (cover_npc_ent:IsNPC() or cover_npc_ent:IsPlayer())) then cover_npc_isObj = false end if !wep.IsMeleeWeapon then -- If friendly in line of fire, then move! if !cover_npc_isObj && self.DoingWeaponAttack_Standing == true && CurTime() > self.TakingCoverT && IsValid(cover_wep_ent) && cover_wep_ent:IsNPC() && cover_wep_ent != self && (self:Disposition(cover_wep_ent) == D_LI or self:Disposition(cover_wep_ent) == D_NU) && cover_wep_tr.HitPos:Distance(cover_wep_tr.StartPos) <= 3000 then local moveCheck = VJ_PICK(self:VJ_CheckAllFourSides(50, true, "0011")) if moveCheck then self:StopMoving() if self.IsGuard then self.GuardingPosition = moveCheck end -- Set the guard position to this new position that avoids friendly fire self:SetLastPosition(moveCheck) self.NextChaseTime = CurTime() + 1 self:VJ_TASK_GOTO_LASTPOS("TASK_WALK_PATH", function(x) x:EngTask("TASK_FACE_ENEMY", 0) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) end end -- If the NPC is behind cover... if cover_npc == true then self.WeaponUseEnemyEyePos = true -- Make the bullet direction go towards the head of the enemy -- Behind cover and I am taking cover, don't fire! if CurTime() < self.TakingCoverT then noAttack = true elseif CurTime() > self.NextMoveOnGunCoveredT && ((cover_npc_tr.HitPos:Distance(myPos) > 150 && cover_npc_isObj == true) or (cover_wep == true && !cover_wep_ent:IsNPC() && !cover_wep_ent:IsPlayer())) then local nearestPos; local enePos; if IsValid(cover_npc_ent) then nearestPos, nearestEnePos = self:VJ_GetNearestPointToEntity(cover_npc_ent, true) else nearestPos, nearestEnePos = self:VJ_GetNearestPointToVector(cover_npc_tr.HitPos, true) end enePos = nearestEnePos - self:GetForward()*15 if nearestPos:Distance(enePos) <= (self.IsGuard and 60 or 1000) then if self.IsGuard then self.GuardingPosition = enePos end -- Set the guard position to this new position that provides cover self:SetLastPosition(enePos) //VJ_CreateTestObject(enePos, self:GetAngles(), Color(0,255,255)) local vsched = ai_vj_schedule.New("vj_goto_cover") vsched:EngTask("TASK_GET_PATH_TO_LASTPOSITION", 0) vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0) vsched.IsMovingTask = true vsched.ConstantlyFaceEnemy = true vsched.StopScheduleIfNotMoving_Any = true local coverRunAnim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_MoveToCover)) if VJ_AnimationExists(self, coverRunAnim) == true then self:SetMovementActivity(coverRunAnim) else vsched.CanShootWhenMoving = true vsched.MoveType = 1 end self:StartSchedule(vsched) //self:VJ_TASK_GOTO_LASTPOS("TASK_WALK_PATH",function(x) x:EngTask("TASK_FACE_ENEMY", 0) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) end self.NextMoveOnGunCoveredT = CurTime() + 2 end else -- NPC not covered self.WeaponUseEnemyEyePos = false -- Make the bullet direction go towards the center of the enemy rather then its head end end if noAttack == false && CurTime() > self.NextWeaponAttackT && CurTime() > self.NextWeaponAttackT_Base /*&& self.DoingWeaponAttack == false*/ then -- Melee weapons if (wep.IsMeleeWeapon) then self:CustomOnWeaponAttack() local finalAnim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponAttack)) if CurTime() > self.NextMeleeWeaponAttackT && VJ_AnimationExists(self, finalAnim) == true /*&& VJ_IsCurrentAnimation(self, finalAnim) == false*/ then local animDur = VJ_GetSequenceDuration(self, finalAnim) wep.NPC_NextPrimaryFire = animDur -- Make melee weapons dynamically change the next primary fire VJ_EmitSound(self, wep.NPC_BeforeFireSound, wep.NPC_BeforeFireSoundLevel, math.Rand(wep.NPC_BeforeFireSoundPitch.a, wep.NPC_BeforeFireSoundPitch.b)) self.NextMeleeWeaponAttackT = CurTime() + animDur self.CurrentWeaponAnimation = finalAnim self:VJ_ACT_PLAYACTIVITY(finalAnim, false, false, true) self.DoingWeaponAttack = true end -- Normal ranged weapons else local hasAmmo = wep:Clip1() > 0 // AllowWeaponReloading if !hasAmmo && !self.CurrentWeaponAnimationIsAim then self.CurrentWeaponAnimation = -1 end -- If the current animation is already a firing animation, then just tell the base it's already firing and do NOT restart the animation if VJ_IsCurrentAnimation(self, self:TranslateToWeaponAnim(self.CurrentWeaponAnimation)) == true then self.DoingWeaponAttack = true self.DoingWeaponAttack_Standing = true -- If the current activity isn't the last weapon animation and it's not a transition, then continue elseif self:GetActivity() != self.CurrentWeaponAnimation && self:GetActivity() != ACT_TRANSITION then self:CustomOnWeaponAttack() self.WaitingForEnemyToComeOut = false self.Weapon_TimeSinceLastShot = CurTime() //self.NextMoveRandomlyWhenShootingT = CurTime() + 2 local finalAnim; -- Check if the NPC has ammo if !hasAmmo then finalAnim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponAim)) self.CurrentWeaponAnimationIsAim = true else local anim_crouch = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponAttackCrouch)) if self.CanCrouchOnWeaponAttack == true && cover_npc == false && cover_wep == false && eneDist_Eye > 500 && VJ_AnimationExists(self, anim_crouch) == true && ((math.random(1, self.CanCrouchOnWeaponAttackChance) == 1) or (CurTime() <= self.Weapon_DoingCrouchAttackT)) && self:VJ_ForwardIsHidingZone(wep:GetNW2Vector("VJ_CurBulletPos") + self:GetUp()*-18, enePos_Eye, false) == false then finalAnim = anim_crouch self.Weapon_DoingCrouchAttackT = CurTime() + 2 -- Asiga bedke vor vestah elank yed votgi cheler hemen else -- Not crouching finalAnim = self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_WeaponAttack)) end end if VJ_AnimationExists(self, finalAnim) == true && ((VJ_IsCurrentAnimation(self, finalAnim) == false) or (!self.DoingWeaponAttack)) then VJ_EmitSound(self, wep.NPC_BeforeFireSound, wep.NPC_BeforeFireSoundLevel, math.Rand(wep.NPC_BeforeFireSoundPitch.a, wep.NPC_BeforeFireSoundPitch.b)) self.CurrentWeaponAnimation = finalAnim self.NextWeaponAttackT_Base = CurTime() + 0.2 self:VJ_ACT_PLAYACTIVITY(finalAnim, false, 0, true) self.DoingWeaponAttack = true self.DoingWeaponAttack_Standing = true end end end end -- Move randomly when shooting if self.MoveRandomlyWhenShooting && cover_npc == false && !self.IsGuard && !self.IsFollowing && (!wep.IsMeleeWeapon) && (!wep.NPC_StandingOnly) && self.DoingWeaponAttack && self.DoingWeaponAttack_Standing && CurTime() > self.NextMoveRandomlyWhenShootingT && (CurTime() - self.EnemyData.TimeSinceAcquired) > 2 && (eneDist_Eye < (self.Weapon_FiringDistanceFar / 1.25)) && self:VJ_ForwardIsHidingZone(self:NearestPoint(myPosCentered), enePos_Eye) == false then if self:CustomOnMoveRandomlyWhenShooting() != false then local moveCheck = VJ_PICK(self:VJ_CheckAllFourSides(math.random(150, 400), true, "0111")) if moveCheck then self:StopMoving() self:SetLastPosition(moveCheck) self:VJ_TASK_GOTO_LASTPOS(VJ_PICK({"TASK_RUN_PATH", "TASK_WALK_PATH"}), function(x) x:EngTask("TASK_FACE_ENEMY", 0) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) end end self.NextMoveRandomlyWhenShootingT = CurTime() + math.Rand(self.NextMoveRandomlyWhenShootingTime1, self.NextMoveRandomlyWhenShootingTime2) end else -- None VJ Base weapons self:FaceCertainEntity(ene, true) self.WaitingForEnemyToComeOut = false self.DoingWeaponAttack = true self.DoingWeaponAttack_Standing = true self:CustomOnWeaponAttack() self.Weapon_TimeSinceLastShot = CurTime() //wep:SetClip1(99999) self:VJ_SetSchedule(SCHED_RANGE_ATTACK1) end end end end else -- Not in sight, reset the enemy self:ResetEnemy(false) end self.LatestEnemyDistance = ene:GetPos():Distance(myPos) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:ResetEnemy(checkAlliesEnemy) if /*self.NextResetEnemyT > CurTime() or*/ self.Dead then self.EnemyData.Reset = false return false end checkAlliesEnemy = checkAlliesEnemy or false local moveToEnemy = false local ene = self:GetEnemy() local eneValid = IsValid(ene) if checkAlliesEnemy == true then local eneData = self.EnemyData local getAllies = self:Allies_Check(1000) if getAllies != false then for _, v in ipairs(getAllies) do local allyEne = v:GetEnemy() if IsValid(allyEne) && (CurTime() - v.EnemyData.LastVisibleTime) < self.TimeUntilEnemyLost && VJ_IsAlive(allyEne) && self:CheckRelationship(allyEne) == D_HT && self:GetPos():Distance(allyEne:GetPos()) <= self:GetMaxLookDistance() then self:VJ_DoSetEnemy(allyEne, false) eneData.Reset = false return false end end end local curEnemies = eneData.VisibleCount //self.CurrentReachableEnemies -- If the current number of reachable enemies is higher then 1, then don't reset if (eneValid && (curEnemies - 1) >= 1) or (!eneValid && curEnemies >= 1) then //self:VJ_DoSetEnemy(v, false, true) self:SetupRelationships() -- Select a new enemy self.NextProcessT = CurTime() + self.NextProcessTime eneData.Reset = false return false end end self:SetNPCState(NPC_STATE_ALERT) timer.Create("timer_alerted_reset"..self:EntIndex(), math.Rand(self.AlertedToIdleTime.a, self.AlertedToIdleTime.b), 1, function() if !IsValid(self:GetEnemy()) then self.Alerted = false self:SetNPCState(NPC_STATE_IDLE) end end) self:CustomOnResetEnemy() if self.VJ_DEBUG == true && GetConVar("vj_npc_printresetenemy"):GetInt() == 1 then print(self:GetName().." has reseted its enemy") end if eneValid then if self.IsFollowing == false && self.VJ_PlayingSequence == false && (!self.IsVJBaseSNPC_Tank) && self:GetEnemyLastKnownPos() != defPos then self:SetLastPosition(self:GetEnemyLastKnownPos()) moveToEnemy = true end self:MarkEnemyAsEluded(ene) //self:ClearEnemyMemory(ene) // Completely resets the enemy memory self:AddEntityRelationship(ene, D_NU, 10) end self.LastHiddenZone_CanWander = CurTime() > self.LastHiddenZoneT and true or false self.LastHiddenZoneT = 0 -- Clear memory of the enemy if it's not a player AND it's dead if eneValid && !ene:IsPlayer() && !VJ_IsAlive(ene) then //print("Clear memory", ene) self:ClearEnemyMemory(ene) end //self:UpdateEnemyMemory(self,self:GetPos()) //local vsched = ai_vj_schedule.New("vj_act_resetenemy") //if eneValid then vsched:EngTask("TASK_FORGET", ene) end //vsched:EngTask("TASK_IGNORE_OLD_ENEMIES", 0) self.NextWanderTime = CurTime() + math.Rand(3, 5) -- This is needed for the human base because when taking cover from enemy, the AI can get stuck in a loop (EX: When self.NoWeapon_UseScaredBehavior_Active is true!) local curSched = self.CurrentSchedule if (curSched != nil && (curSched.Name == "vj_cover_from_enemy" or curSched.Name == "vj_cover_from_enemy_fail")) then self:StopMoving() end if !self:IsBusy() && !self.IsGuard && self.Behavior != VJ_BEHAVIOR_PASSIVE && self.Behavior != VJ_BEHAVIOR_PASSIVE_NATURE && self.VJ_IsBeingControlled == false && moveToEnemy == true && self.LastHiddenZone_CanWander == true && !self.NoWeapon_UseScaredBehavior_Active then //ParticleEffect("explosion_turret_break", self.LatestEnemyPosition, Angle(0,0,0)) self:SetMovementActivity(VJ_PICK(self.AnimTbl_Walk)) local vsched = ai_vj_schedule.New("vj_act_resetenemy") vsched:EngTask("TASK_GET_PATH_TO_LASTPOSITION", 0) //vsched:EngTask("TASK_WALK_PATH", 0) vsched:EngTask("TASK_WAIT_FOR_MOVEMENT", 0) vsched.ResetOnFail = true vsched.CanShootWhenMoving = true vsched.ConstantlyFaceEnemy = true vsched.CanBeInterrupted = true vsched.IsMovingTask = true vsched.MoveType = 0 //self.NextIdleTime = CurTime() + 10 self:StartSchedule(vsched) end //if vsched.TaskCount > 0 then //self:StartSchedule(vsched) //end self:SetEnemy(NULL) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:OnTakeDamage(dmginfo) local dmgInflictor = dmginfo:GetInflictor() local hitgroup = self:GetLastDamageHitGroup() if IsValid(dmgInflictor) && dmgInflictor:GetClass() == "prop_ragdoll" && dmgInflictor:GetVelocity():Length() <= 100 then return 0 end -- Avoid taking damage when walking on ragdolls self:CustomOnTakeDamage_BeforeImmuneChecks(dmginfo, hitgroup) if self.GodMode or dmginfo:GetDamage() <= 0 then return 0 end if self:IsOnFire() && self:WaterLevel() == 2 then self:Extinguish() end -- If we are in water, then extinguish the fire local dmgAttacker = dmginfo:GetAttacker() local dmgType = dmginfo:GetDamageType() local curTime = CurTime() local isFireDmg = self:IsOnFire() && IsValid(dmgInflictor) && IsValid(dmgAttacker) && dmgInflictor:GetClass() == "entityflame" && dmgAttacker:GetClass() == "entityflame" -- If it should always take damage from huge monsters, then skip immunity checks! if self.GetDamageFromIsHugeMonster && dmgAttacker.VJ_IsHugeMonster then goto skip_immunity end if VJ_HasValue(self.ImmuneDamagesTable, dmgType) then return 0 end if !self.AllowIgnition && isFireDmg then self:Extinguish() return 0 end if self.Immune_Fire == true && (dmgType == DMG_BURN or dmgType == DMG_SLOWBURN or isFireDmg) then return 0 end if (self.Immune_AcidPoisonRadiation == true && (dmgType == DMG_ACID or dmgType == DMG_RADIATION or dmgType == DMG_POISON or dmgType == DMG_NERVEGAS or dmgType == DMG_PARALYZE)) or (self.Immune_Bullet == true && (dmginfo:IsBulletDamage() or dmgType == DMG_BULLET or dmgType == DMG_AIRBOAT or dmgType == DMG_BUCKSHOT)) or (self.Immune_Blast == true && (dmgType == DMG_BLAST or dmgType == DMG_BLAST_SURFACE)) or (self.Immune_Dissolve == true && dmgType == DMG_DISSOLVE) or (self.Immune_Electricity == true && (dmgType == DMG_SHOCK or dmgType == DMG_ENERGYBEAM or dmgType == DMG_PHYSGUN)) or (self.Immune_Melee == true && (dmgType == DMG_CLUB or dmgType == DMG_SLASH)) or (self.Immune_Physics == true && dmgType == DMG_CRUSH) or (self.Immune_Sonic == true && dmgType == DMG_SONIC) then return 0 end if (IsValid(dmgInflictor) && dmgInflictor:GetClass() == "prop_combine_ball") or (IsValid(dmgAttacker) && dmgAttacker:GetClass() == "prop_combine_ball") then if self.Immune_Dissolve == true then return 0 end -- Make sure combine ball does reasonable damage and doesn't spam it! if curTime > self.NextCanGetCombineBallDamageT then dmginfo:SetDamage(math.random(400, 500)) dmginfo:SetDamageType(DMG_DISSOLVE) self.NextCanGetCombineBallDamageT = curTime + 0.2 else return 0 end end ::skip_immunity:: local function DoBleed() if self.Bleeds == true then self:CustomOnTakeDamage_OnBleed(dmginfo, hitgroup) -- Spawn the blood particle only if it's not caused by the default fire entity [Causes the damage position to be at Vector(0, 0, 0)] if self.HasBloodParticle == true && !isFireDmg then self:SpawnBloodParticles(dmginfo, hitgroup) end if self.HasBloodDecal == true then self:SpawnBloodDecal(dmginfo, hitgroup) end self:PlaySoundSystem("Impact", nil, VJ_EmitSound) end end if self.Dead then DoBleed() return 0 end -- If dead then just bleed but take no damage self:CustomOnTakeDamage_BeforeDamage(dmginfo, hitgroup) if dmginfo:GetDamage() <= 0 then return 0 end -- Only take damage if it's above 0! -- Why? Because GMod resets/randomizes dmginfo after a tick... self.SavedDmgInfo = { dmginfo = dmginfo, -- The actual CTakeDamageInfo object | WARNING: Can be corrupted after a tick, recommended not to use this! attacker = dmginfo:GetAttacker(), inflictor = dmginfo:GetInflictor(), amount = dmginfo:GetDamage(), pos = dmginfo:GetDamagePosition(), type = dmginfo:GetDamageType(), force = dmginfo:GetDamageForce(), ammoType = dmginfo:GetAmmoType(), hitgroup = hitgroup, } self:SetHealth(self:Health() - dmginfo:GetDamage()) if self.VJ_DEBUG == true && GetConVar("vj_npc_printondamage"):GetInt() == 1 then print(self:GetClass().." Got Damaged! | Amount = "..dmginfo:GetDamage()) end if self.HasHealthRegeneration == true && self.HealthRegenerationResetOnDmg == true then self.HealthRegenerationDelayT = curTime + (math.Rand(self.HealthRegenerationDelay.a, self.HealthRegenerationDelay.b) * 1.5) end self:SetSaveValue("m_iDamageCount", self:GetSaveTable().m_iDamageCount + 1) self:SetSaveValue("m_flLastDamageTime", curTime) self:CustomOnTakeDamage_AfterDamage(dmginfo, hitgroup) DoBleed() -- I/O events, from: https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/sp/src/game/server/ai_basenpc.cpp#L764 if IsValid(dmgAttacker) then self:TriggerOutput("OnDamaged", dmgAttacker) self:MarkTookDamageFromEnemy(dmgAttacker) else self:TriggerOutput("OnDamaged", self) end local stillAlive = self:Health() > 0 if stillAlive then self:PlaySoundSystem("Pain") end if GetConVar("ai_disabled"):GetInt() == 0 && self:GetState() != VJ_STATE_FREEZE then -- Make passive NPCs move away | RESULT: May move away AND may cause other passive NPCs to move as well if (self.Behavior == VJ_BEHAVIOR_PASSIVE or self.Behavior == VJ_BEHAVIOR_PASSIVE_NATURE) && curTime > self.TakingCoverT then if stillAlive && self.Passive_RunOnDamage then self:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH") end if self.Passive_AlliesRunOnDamage then -- Make passive allies run too! local allies = self:Allies_Check(self.Passive_AlliesRunOnDamageDistance) if allies != false then for _, v in ipairs(allies) do v.TakingCoverT = curTime + math.Rand(v.Passive_NextRunOnDamageTime.b, v.Passive_NextRunOnDamageTime.a) v:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH") v:PlaySoundSystem("Alert") end end end self.TakingCoverT = curTime + math.Rand(self.Passive_NextRunOnDamageTime.a, self.Passive_NextRunOnDamageTime.b) end if stillAlive then self:DoFlinch(dmginfo, hitgroup) -- React to damage by a player -- 0 = Run it every time | 1 = Run it only when friendly to player | 2 = Run it only when enemy to player if self.HasDamageByPlayer && dmgAttacker:IsPlayer() && curTime > self.NextDamageByPlayerT && self:Visible(dmgAttacker) && (self.DamageByPlayerDispositionLevel == 0 or (self.DamageByPlayerDispositionLevel == 1 && (self:Disposition(dmgAttacker) == D_LI or self:Disposition(dmgAttacker) == D_NU)) or (self.DamageByPlayerDispositionLevel == 2 && self:Disposition(dmgAttacker) != D_HT)) then self:CustomOnDamageByPlayer(dmginfo, hitgroup) self:PlaySoundSystem("DamageByPlayer") self.NextDamageByPlayerT = curTime + math.Rand(self.DamageByPlayerTime.a, self.DamageByPlayerTime.b) end self:PlaySoundSystem("Pain") -- Move or hide when damaged by an enemy | RESULT: May play a hiding animation OR may move to take cover from enemy if self.MoveOrHideOnDamageByEnemy && self.Behavior != VJ_BEHAVIOR_PASSIVE && self.Behavior != VJ_BEHAVIOR_PASSIVE_NATURE && IsValid(self:GetEnemy()) && curTime > self.NextMoveOrHideOnDamageByEnemyT && !self.IsFollowing && self.AttackType == VJ_ATTACK_NONE && curTime > self.TakingCoverT && self.EnemyData.IsVisible && self.VJ_IsBeingControlled == false && self:GetWeaponState() != VJ_WEP_STATE_RELOADING && self:EyePos():Distance(self:GetEnemy():EyePos()) < self.Weapon_FiringDistanceFar then local wep = self:GetActiveWeapon() if !self.MoveOrHideOnDamageByEnemy_OnlyMove && self:VJ_ForwardIsHidingZone(self:NearestPoint(self:GetPos() + self:OBBCenter()) ,self:GetEnemy():EyePos()) == true then local anim = VJ_PICK(self:TranslateToWeaponAnim(VJ_PICK(self.AnimTbl_TakingCover))) if VJ_AnimationExists(self, anim) == true then local hideTime = math.Rand(self.MoveOrHideOnDamageByEnemy_HideTime.a, self.MoveOrHideOnDamageByEnemy_HideTime.b) self:VJ_ACT_PLAYACTIVITY(anim, false, hideTime, false, 0, {SequenceDuration=hideTime}) -- Don't set stopActivities because we want it to shoot if an enemy is suddenly visible! self.NextChaseTime = curTime + hideTime self.TakingCoverT = curTime + hideTime self.DoingWeaponAttack = false end self.NextMoveOrHideOnDamageByEnemyT = curTime + math.random(self.NextMoveOrHideOnDamageByEnemy1, self.NextMoveOrHideOnDamageByEnemy2) elseif !self:IsMoving() && (!IsValid(wep) or (IsValid(wep) && !wep.IsMeleeWeapon)) then -- Run away if not moving AND has a non-melee weapon self:VJ_TASK_COVER_FROM_ENEMY("TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) self.NextMoveOrHideOnDamageByEnemyT = curTime + math.random(self.NextMoveOrHideOnDamageByEnemy1, self.NextMoveOrHideOnDamageByEnemy2) end end -- Call for back on damage | RESULT: May play an animation OR it may move away, AND it may bring allies to its location if self.CallForBackUpOnDamage && curTime > self.NextCallForBackUpOnDamageT && self.AttackType != VJ_ATTACK_GRENADE && !IsValid(self:GetEnemy()) && self.IsFollowing == false && self.Behavior != VJ_BEHAVIOR_PASSIVE && self.Behavior != VJ_BEHAVIOR_PASSIVE_NATURE && !isFireDmg then local allies = self:Allies_Check(self.CallForBackUpOnDamageDistance) if allies != false then self:Allies_Bring("Diamond", self.CallForBackUpOnDamageDistance, allies, self.CallForBackUpOnDamageLimit) self:ClearSchedule() self.NextFlinchT = curTime + 1 local chosenAnim = VJ_PICK(self.CallForBackUpOnDamageAnimation) local playedAnim = !self.DisableCallForBackUpOnDamageAnimation and self:VJ_ACT_PLAYACTIVITY(chosenAnim, true, self:DecideAnimationLength(chosenAnim, self.CallForBackUpOnDamageAnimationTime), true, 0, {PlayBackRateCalculated=true}) or 0 if playedAnim == 0 && !self:BusyWithActivity() then self:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) end self.NextCallForBackUpOnDamageT = curTime + math.Rand(self.NextCallForBackUpOnDamageTime.a, self.NextCallForBackUpOnDamageTime.b) end end -- Become enemy to a friendly player | RESULT: May become alerted if self.BecomeEnemyToPlayer == true && self.VJ_IsBeingControlled == false && dmgAttacker:IsPlayer() && self:CheckRelationship(dmgAttacker) == D_LI then self.AngerLevelTowardsPlayer = self.AngerLevelTowardsPlayer + 1 if self.AngerLevelTowardsPlayer > self.BecomeEnemyToPlayerLevel then if self:Disposition(dmgAttacker) != D_HT then self:CustomOnBecomeEnemyToPlayer(dmginfo, hitgroup) if self.IsFollowing == true && self.FollowData.Ent == dmgAttacker then self:FollowReset() end self.VJ_AddCertainEntityAsEnemy[#self.VJ_AddCertainEntityAsEnemy + 1] = dmgAttacker self:AddEntityRelationship(dmgAttacker, D_HT, 2) self.TakingCoverT = curTime + 2 self:PlaySoundSystem("BecomeEnemyToPlayer") if !IsValid(self:GetEnemy()) then self:StopMoving() self:SetTarget(dmgAttacker) self:VJ_TASK_FACE_X("TASK_FACE_TARGET") end if self.AllowPrintingInChat == true then dmgAttacker:PrintMessage(HUD_PRINTTALK, self:GetName().." no longer likes you.") end end self.Alerted = true self:SetNPCState(NPC_STATE_ALERT) end end -- Attempt to find who damaged me | RESULT: May become alerted if enemy is visible OR it may move away if !self.DisableTakeDamageFindEnemy && !self:BusyWithActivity() && !IsValid(self:GetEnemy()) && curTime > self.TakingCoverT && self.VJ_IsBeingControlled == false && self.Behavior != VJ_BEHAVIOR_PASSIVE && self.Behavior != VJ_BEHAVIOR_PASSIVE_NATURE then // self.Alerted == false local eneFound = false local sightDist = self:GetMaxLookDistance() sightDist = math_clamp(sightDist / 2, sightDist <= 1000 and sightDist or 1000, sightDist) -- IF normal sight dist is less than 1000 then change nothing, OR ELSE use half the distance with 1000 as minimum for _, v in ipairs(ents.FindInSphere(self:GetPos(), sightDist)) do if (curTime - self.EnemyData.TimeSet) > 2 && self:Visible(v) && self:CheckRelationship(v) == D_HT then self:CustomOnSetEnemyOnDamage(dmginfo, hitgroup) self.NextCallForHelpT = curTime + 1 self:VJ_DoSetEnemy(v, true) self:DoChaseAnimation() eneFound = true break end end if !eneFound && self.HideOnUnknownDamage && !self.IsFollowing && self.MovementType != VJ_MOVETYPE_STATIONARY then self:VJ_TASK_COVER_FROM_ORIGIN("TASK_RUN_PATH", function(x) x.CanShootWhenMoving = true x.ConstantlyFaceEnemy = true end) self.TakingCoverT = curTime + self.HideOnUnknownDamage end end end end -- If eating, stop! if self.CanEat && self.VJTags[VJ_TAG_EATING] then self.EatingData.NextCheck = curTime + 15 self:EatingReset("Injured") end if self:Health() <= 0 && !self.Dead then self:RemoveEFlags(EFL_NO_DISSOLVE) if (dmginfo:IsDamageType(DMG_DISSOLVE)) or (IsValid(dmgInflictor) && dmgInflictor:GetClass() == "prop_combine_ball") then local dissolve = DamageInfo() dissolve:SetDamage(self:Health()) dissolve:SetAttacker(dmgAttacker) dissolve:SetDamageType(DMG_DISSOLVE) self:TakeDamageInfo(dissolve) end self:PriorToKilled(dmginfo, hitgroup) end return 1 end --------------------------------------------------------------------------------------------------------------------------------------------- local vecZ500 = Vector(0, 0, 500) local vecZ4 = Vector(0, 0, 4) -- function ENT:PriorToKilled(dmginfo, hitgroup) self:CustomOnInitialKilled(dmginfo, hitgroup) if self.Medic_Status then self:DoMedicReset() end local dmgInflictor = dmginfo:GetInflictor() local dmgAttacker = dmginfo:GetAttacker() local allies = self:Allies_Check(math.max(800, self.BringFriendsOnDeathDistance, self.AlertFriendsOnDeathDistance)) if allies != false then local noAlert = true -- Don't run the AlertFriendsOnDeath if we have BringFriendsOnDeath enabled! if self.BringFriendsOnDeath == true then self:Allies_Bring("Diamond", self.BringFriendsOnDeathDistance, allies, self.BringFriendsOnDeathLimit, true) noAlert = false end local doBecomeEnemyToPlayer = (self.BecomeEnemyToPlayer == true && dmgAttacker:IsPlayer() && GetConVar("ai_disabled"):GetInt() == 0 && !VJ_CVAR_IGNOREPLAYERS) or false local it = 0 -- Number of allies that have been alerted for _, v in ipairs(allies) do v:CustomOnAllyDeath(self) v:PlaySoundSystem("AllyDeath") -- AlertFriendsOnDeath if noAlert == true && self.AlertFriendsOnDeath == true && !IsValid(v:GetEnemy()) && v.AlertFriendsOnDeath == true && it != self.AlertFriendsOnDeathLimit && self:GetPos():Distance(v:GetPos()) < self.AlertFriendsOnDeathDistance && (!IsValid(v:GetActiveWeapon()) or (IsValid(v:GetActiveWeapon()) && !(v:GetActiveWeapon().IsMeleeWeapon))) then it = it + 1 v:FaceCertainPosition(self:GetPos(), 1) v:VJ_ACT_PLAYACTIVITY(VJ_PICK(v.AnimTbl_AlertFriendsOnDeath)) v.NextIdleTime = CurTime() + math.Rand(5, 8) end -- BecomeEnemyToPlayer if doBecomeEnemyToPlayer && v.BecomeEnemyToPlayer == true && v:Disposition(dmgAttacker) == D_LI then v.AngerLevelTowardsPlayer = v.AngerLevelTowardsPlayer + 1 if v.AngerLevelTowardsPlayer > v.BecomeEnemyToPlayerLevel then if v:Disposition(dmgAttacker) != D_HT then v:CustomOnBecomeEnemyToPlayer(dmginfo, hitgroup) if v.IsFollowing == true && v.FollowData.Ent == dmgAttacker then v:FollowReset() end v.VJ_AddCertainEntityAsEnemy[#v.VJ_AddCertainEntityAsEnemy+1] = dmgAttacker v:AddEntityRelationship(dmgAttacker,D_HT,2) if v.AllowPrintingInChat == true then dmgAttacker:PrintMessage(HUD_PRINTTALK, v:GetName().." no longer likes you.") end v:PlaySoundSystem("BecomeEnemyToPlayer") end v.Alerted = true end end end end local function DoKilled() if IsValid(self) then if self.WaitBeforeDeathTime == 0 then self:OnKilled(dmginfo, hitgroup) else timer.Simple(self.WaitBeforeDeathTime, function() if IsValid(self) then self:OnKilled(dmginfo, hitgroup) end end) end end end -- Blood decal on the ground if self.Bleeds == true && self.HasBloodDecal == true then local bloodDecal = VJ_PICK(self.CustomBlood_Decal) if bloodDecal != false then local decalPos = self:GetPos() + vecZ4 self:SetLocalPos(decalPos) -- NPC is too close to the ground, we need to move it up a bit local tr = util.TraceLine({ start = decalPos, endpos = decalPos - vecZ500, filter = self }) util.Decal(bloodDecal, tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal) end end self.Dead = true if self.IsFollowing == true then self:FollowReset() end self:RemoveTimers() self.AttackType = VJ_ATTACK_NONE self.MeleeAttacking = false self.HasMeleeAttack = false self:StopAllCommonSounds() if IsValid(dmgAttacker) then if dmgAttacker:GetClass() == "npc_barnacle" then self.HasDeathRagdoll = false end -- Don't make a corpse if it's killed by a barnacle! if GetConVar("vj_npc_addfrags"):GetInt() == 1 && dmgAttacker:IsPlayer() then dmgAttacker:AddFrags(1) end if IsValid(dmgInflictor) then gamemode.Call("OnNPCKilled", self, dmgAttacker, dmgInflictor, dmginfo) end end self:CustomOnPriorToKilled(dmginfo, hitgroup) self:SetCollisionGroup(1) self:RunGibOnDeathCode(dmginfo, hitgroup) self:PlaySoundSystem("Death") //self:AA_StopMoving() -- I/O events, from: https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/server/basecombatcharacter.cpp#L1582 if IsValid(dmgAttacker) then -- Someone else killed me self:TriggerOutput("OnDeath", dmgAttacker) dmgAttacker:Fire("KilledNPC", "", 0, self, self) -- Allows player companions (npc_citizen) to respond to kill else self:TriggerOutput("OnDeath", self) end if self.HasDeathAnimation == true && !dmginfo:IsDamageType(DMG_REMOVENORAGDOLL) then if IsValid(dmgInflictor) && dmgInflictor:GetClass() == "prop_combine_ball" then DoKilled() return end if GetConVar("vj_npc_nodeathanimation"):GetInt() == 0 && GetConVar("ai_disabled"):GetInt() == 0 && !dmginfo:IsDamageType(DMG_DISSOLVE) && math.random(1, self.DeathAnimationChance) == 1 then self:RemoveAllGestures() self:CustomDeathAnimationCode(dmginfo, hitgroup) local chosenAnim = VJ_PICK(self.AnimTbl_Death) local animTime = self:DecideAnimationLength(chosenAnim, self.DeathAnimationTime) - self.DeathAnimationDecreaseLengthAmount self:VJ_ACT_PLAYACTIVITY(chosenAnim, true, animTime, false, 0, {PlayBackRateCalculated=true}) self.DeathAnimationCodeRan = true timer.Simple(animTime, DoKilled) else DoKilled() end else DoKilled() end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:OnKilled(dmginfo, hitgroup) if self.VJ_DEBUG == true && GetConVar("vj_npc_printdied"):GetInt() == 1 then print(self:GetClass().." Died!") end self:CustomOnKilled(dmginfo, hitgroup) self:RunItemDropsOnDeathCode(dmginfo, hitgroup) -- Item drops on death self:ClearEnemyMemory() //self:ClearSchedule() //self:SetNPCState(NPC_STATE_DEAD) if bit.band(self.SavedDmgInfo.type, DMG_REMOVENORAGDOLL) == 0 then self:DropWeaponOnDeathCode(dmginfo, hitgroup) self:CreateDeathCorpse(dmginfo, hitgroup) end self:Remove() end --------------------------------------------------------------------------------------------------------------------------------------------- local colorGrey = Color(90, 90, 90) -- function ENT:CreateDeathCorpse(dmginfo, hitgroup) -- In case it was not set -- NOTE: dmginfo at this point can be incorrect/corrupted, but its better than leaving the self.SavedDmgInfo empty! if !self.SavedDmgInfo then self.SavedDmgInfo = { dmginfo = dmginfo, -- The actual CTakeDamageInfo object | WARNING: Can be corrupted after a tick, recommended not to use this! attacker = dmginfo:GetAttacker(), inflictor = dmginfo:GetInflictor(), amount = dmginfo:GetDamage(), pos = dmginfo:GetDamagePosition(), type = dmginfo:GetDamageType(), force = dmginfo:GetDamageForce(), ammoType = dmginfo:GetAmmoType(), hitgroup = hitgroup, } end self:CustomOnDeath_BeforeCorpseSpawned(dmginfo, hitgroup) if self.HasDeathRagdoll == true then local corpseMdl = self:GetModel() local corpseMdlCustom = VJ_PICK(self.DeathCorpseModel) if corpseMdlCustom != false then corpseMdl = corpseMdlCustom end local corpseType = "prop_physics" if self.DeathCorpseEntityClass == "UseDefaultBehavior" then if util.IsValidRagdoll(corpseMdl) == true then corpseType = "prop_ragdoll" elseif util.IsValidProp(corpseMdl) == false or util.IsValidModel(corpseMdl) == false then if IsValid(self.TheDroppedWeapon) then self.TheDroppedWeapon:Remove() end return false end else corpseType = self.DeathCorpseEntityClass end //if self.VJCorpseDeleted == true then self.Corpse = ents.Create(corpseType) //end self.Corpse:SetModel(corpseMdl) self.Corpse:SetPos(self:GetPos()) self.Corpse:SetAngles(self:GetAngles()) self.Corpse:Spawn() self.Corpse:Activate() self.Corpse:SetColor(self:GetColor()) self.Corpse:SetMaterial(self:GetMaterial()) if corpseMdlCustom == false && self.DeathCorpseSubMaterials != nil then -- Take care of sub materials for _, x in ipairs(self.DeathCorpseSubMaterials) do if self:GetSubMaterial(x) != "" then self.Corpse:SetSubMaterial(x, self:GetSubMaterial(x)) end end -- This causes lag, not a very good way to do it. /*for x = 0, #self:GetMaterials() do if self:GetSubMaterial(x) != "" then self.Corpse:SetSubMaterial(x, self:GetSubMaterial(x)) end end*/ end //self.Corpse:SetName("self.Corpse" .. self:EntIndex()) //self.Corpse:SetModelScale(self:GetModelScale()) self.Corpse.FadeCorpseType = (self.Corpse:GetClass() == "prop_ragdoll" and "FadeAndRemove") or "kill" self.Corpse.IsVJBaseCorpse = true self.Corpse.DamageInfo = dmginfo self.Corpse.ExtraCorpsesToRemove = self.ExtraCorpsesToRemove_Transition self.Corpse.BloodData = {Color = self.BloodColor, Particle = self.CustomBlood_Particle, Decal = self.CustomBlood_Decal} if self.Bleeds == true && self.HasBloodPool == true && GetConVar("vj_npc_nobloodpool"):GetInt() == 0 then self:SpawnBloodPool(dmginfo, hitgroup) end -- Collision -- self.Corpse:SetCollisionGroup(self.DeathCorpseCollisionType) if GetConVar("ai_serverragdolls"):GetInt() == 1 then undo.ReplaceEntity(self, self.Corpse) else -- Keep corpses is not enabled... VJ_AddCorpse(self.Corpse) //hook.Call("VJ_CreateSNPCCorpse", nil, self.Corpse, self) if GetConVar("vj_npc_undocorpse"):GetInt() == 1 then undo.ReplaceEntity(self, self.Corpse) end -- Undoable end cleanup.ReplaceEntity(self, self.Corpse) -- Delete on cleanup -- Miscellaneous -- self.Corpse:SetSkin((self.DeathCorpseSkin == -1 and self:GetSkin()) or self.DeathCorpseSkin) if self.DeathCorpseSetBodyGroup == true then -- Yete asega true-e, ooremen gerna bodygroup tenel for i = 0,18 do -- 18 = Bodygroup limit self.Corpse:SetBodygroup(i,self:GetBodygroup(i)) end if self.DeathCorpseBodyGroup.a != -1 then -- Yete asiga nevaz meg chene, user-in teradz tevere kordzadze self.Corpse:SetBodygroup(self.DeathCorpseBodyGroup.a, self.DeathCorpseBodyGroup.b) end end if self:IsOnFire() then -- If was on fire then... self.Corpse:Ignite(math.Rand(8, 10), 0) self.Corpse:SetColor(colorGrey) //self.Corpse:SetMaterial("models/props_foliage/tree_deciduous_01a_trunk") end //gamemode.Call("CreateEntityRagdoll",self,self.Corpse) -- Dissolve -- if (bit.band(self.SavedDmgInfo.type, DMG_DISSOLVE) != 0) or (IsValid(self.SavedDmgInfo.inflictor) && self.SavedDmgInfo.inflictor:GetClass() == "prop_combine_ball") then self.Corpse:SetName("vj_dissolve_corpse") local dissolver = ents.Create("env_entity_dissolver") dissolver:SetPos(self.Corpse:GetPos()) dissolver:Spawn() dissolver:Activate() //dissolver:SetKeyValue("target","vj_dissolve_corpse") dissolver:SetKeyValue("magnitude",100) dissolver:SetKeyValue("dissolvetype",0) dissolver:Fire("Dissolve","vj_dissolve_corpse") if IsValid(self.TheDroppedWeapon) then self.TheDroppedWeapon:SetName("vj_dissolve_weapon") dissolver:Fire("Dissolve","vj_dissolve_weapon") end dissolver:Fire("Kill", "", 0.1) //dissolver:Remove() end -- Bone and Angle -- -- If it's a bullet, it will use localized velocity on each bone depending on how far away the bone is from the dmg position local useLocalVel = (bit.band(self.SavedDmgInfo.type, DMG_BULLET) != 0 and self.SavedDmgInfo.pos != defPos) or false local dmgForce = (self.SavedDmgInfo.force / 40) + self:GetMoveVelocity() + self:GetVelocity() if self.DeathAnimationCodeRan then useLocalVel = false dmgForce = self:GetMoveVelocity() == defPos and self:GetGroundSpeedVelocity() or self:GetMoveVelocity() end local totalSurface = 0 local physCount = self.Corpse:GetPhysicsObjectCount() for boneLimit = 0, physCount - 1 do -- 128 = Bone Limit local childphys = self.Corpse:GetPhysicsObjectNum(boneLimit) if IsValid(childphys) then totalSurface = totalSurface + childphys:GetSurfaceArea() local childphys_bonepos, childphys_boneang = self:GetBonePosition(self.Corpse:TranslatePhysBoneToBone(boneLimit)) if (childphys_bonepos) then //if math.Round(math.abs(childphys_boneang.r)) != 90 then -- Fixes ragdolls rotating, no longer needed! ---> sv_pvsskipanimation 0 if self.DeathCorpseSetBoneAngles == true then childphys:SetAngles(childphys_boneang) end childphys:SetPos(childphys_bonepos) //end if self.Corpse:GetName() == "vj_dissolve_corpse" then childphys:EnableGravity(false) childphys:SetVelocity(self:GetForward()*-150 + self:GetRight()*math.Rand(100,-100) + self:GetUp()*50) else if self.DeathCorpseApplyForce == true /*&& self.DeathAnimationCodeRan == false*/ then childphys:SetVelocity(dmgForce / math.max(1, (useLocalVel and childphys_bonepos:Distance(self.SavedDmgInfo.pos)/12) or 1)) end end elseif physCount == 1 then -- If it's only 1, then it's likely a regular physics model with no bones if self.Corpse:GetName() == "vj_dissolve_corpse" then childphys:EnableGravity(false) childphys:SetVelocity(self:GetForward()*-150 + self:GetRight()*math.Rand(100,-100) + self:GetUp()*50) else if self.DeathCorpseApplyForce == true /*&& self.DeathAnimationCodeRan == false*/ then childphys:SetVelocity(dmgForce / math.max(1, (useLocalVel and self.Corpse:GetPos():Distance(self.SavedDmgInfo.pos)/12) or 1)) end end end end end if self.Corpse:Health() <= 0 then local hpCalc = totalSurface / 60 // self.Corpse:OBBMaxs():Distance(self.Corpse:OBBMins()) self.Corpse:SetMaxHealth(hpCalc) self.Corpse:SetHealth(hpCalc) end VJ_AddStinkyEnt(self.Corpse, true) if IsValid(self.TheDroppedWeapon) then self.Corpse.ExtraCorpsesToRemove[#self.Corpse.ExtraCorpsesToRemove+1] = self.TheDroppedWeapon end if self.DeathCorpseFade == true then self.Corpse:Fire(self.Corpse.FadeCorpseType,"",self.DeathCorpseFadeTime) end if GetConVar("vj_npc_corpsefade"):GetInt() == 1 then self.Corpse:Fire(self.Corpse.FadeCorpseType,"",GetConVar("vj_npc_corpsefadetime"):GetInt()) end self:CustomOnDeath_AfterCorpseSpawned(dmginfo, hitgroup, self.Corpse) self.Corpse:CallOnRemove("vj_"..self.Corpse:EntIndex(),function(ent,exttbl) for _,v in ipairs(exttbl) do if IsValid(v) then if v:GetClass() == "prop_ragdoll" then v:Fire("FadeAndRemove","",0) else v:Fire("kill","",0) end end end end,self.Corpse.ExtraCorpsesToRemove) hook.Call("CreateEntityRagdoll", nil, self, self.Corpse) return self.Corpse else if IsValid(self.TheDroppedWeapon) then self.TheDroppedWeapon:Remove() end for _,v in ipairs(self.ExtraCorpsesToRemove_Transition) do if v.IsVJBase_Gib == true && v.RemoveOnCorpseDelete == true then v:Remove() end end end end --------------------------------------------------------------------------------------------------------------------------------------------- local wepDropTbl1 = {weapon_ar2=true, weapon_vj_ar2=true, weapon_vj_blaster=true, weapon_pistol=true, weapon_vj_9mmpistol=true, weapon_vj_357=true, weapon_shotgun=true, weapon_vj_spas12=true, weapon_annabelle=true, weapon_rpg = true} local wepDropTbl2 = {weapon_crowbar=true, weapon_stunstick=true} local wepAng180y = Angle(0, 180, 0) local wepAng90x = Angle(90, 0, 0) -- function ENT:DropWeaponOnDeathCode(dmginfo, hitgroup) if self.DropWeaponOnDeath != true or !IsValid(self:GetActiveWeapon()) /*or dmginfo:IsDamageType(DMG_DISSOLVE)*/ then return end self:CustomOnDropWeapon(dmginfo, hitgroup) -- Rotate the weapon for certain guns self.CurrentWeaponEntity = self:GetActiveWeapon() local gunang = defAng if wepDropTbl1[self.CurrentWeaponEntity:GetClass()] == true then gunang = wepAng180y elseif wepDropTbl2[self.CurrentWeaponEntity:GetClass()] == true then gunang = wepAng90x end local getAttach = false -- true = Found an attachment on the NPC's model if !self.CurrentWeaponEntity.WorldModel_UseCustomPosition then for _,v in ipairs(self:GetAttachments()) do if v.name == self.DropWeaponOnDeathAttachment then getAttach = self:GetAttachment(self:LookupAttachment(self.DropWeaponOnDeathAttachment)) break end end end self.TheDroppedWeapon = ents.Create(self.CurrentWeaponEntity:GetClass()) if getAttach != false then self.TheDroppedWeapon:SetPos(getAttach.Pos) else self.TheDroppedWeapon:SetPos(self.CurrentWeaponEntity:GetPos()) end if getAttach != false then self.TheDroppedWeapon:SetAngles(getAttach.Ang + gunang) else self.TheDroppedWeapon:SetAngles(self.CurrentWeaponEntity:GetAngles() + gunang) end self.TheDroppedWeapon:Spawn() self.TheDroppedWeapon:Activate() local phys = self.TheDroppedWeapon:GetPhysicsObject() if IsValid(phys) then if (bit.band(self.SavedDmgInfo.type, DMG_DISSOLVE) != 0) or (IsValid(self.SavedDmgInfo.inflictor) && self.SavedDmgInfo.inflictor:GetClass() == "prop_combine_ball") then phys:EnableGravity(false) phys:SetVelocity(self:GetForward()*-150 + self:GetRight()*math.Rand(100,-100) + self:GetUp()*50) else local dmgForce = (self.SavedDmgInfo.force / 40) + self:GetMoveVelocity() + self:GetVelocity() if self.DeathAnimationCodeRan then dmgForce = self:GetMoveVelocity() == defPos and self:GetGroundSpeedVelocity() or self:GetMoveVelocity() end phys:SetMass(1) phys:ApplyForceCenter(dmgForce) end end self:CustomOnDropWeapon_AfterWeaponSpawned(dmginfo, hitgroup, self.TheDroppedWeapon) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:PlaySoundSystem(sdSet, customSd, sdType) if self.HasSounds == false or sdSet == nil then return end sdType = sdType or VJ_CreateSound local cTbl = VJ_PICK(customSd) if sdSet == "GeneralSpeech" then -- Used to just play general speech sounds (Custom by developers) if cTbl != false then self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + ((((SoundDuration(cTbl) > 0) and SoundDuration(cTbl)) or 2) + 1) self.CurrentGeneralSpeechSound = sdType(self, cTbl, 80, self:VJ_DecideSoundPitch(self.GeneralSoundPitch1, self.GeneralSoundPitch2)) end return elseif sdSet == "FollowPlayer" then if self.HasFollowPlayerSounds_Follow == true then local sdtbl = VJ_PICK(self.SoundTbl_FollowPlayer) if (math.random(1, self.FollowPlayerSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentFollowPlayerSound = sdType(self, sdtbl, self.FollowPlayerSoundLevel, self:VJ_DecideSoundPitch(self.FollowPlayerPitch.a, self.FollowPlayerPitch.b)) end end return elseif sdSet == "UnFollowPlayer" then if self.HasFollowPlayerSounds_UnFollow == true then local sdtbl = VJ_PICK(self.SoundTbl_UnFollowPlayer) if (math.random(1, self.UnFollowPlayerSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentUnFollowPlayerSound = sdType(self, sdtbl, self.UnFollowPlayerSoundLevel, self:VJ_DecideSoundPitch(self.UnFollowPlayerPitch.a, self.UnFollowPlayerPitch.b)) end end return elseif sdSet == "OnReceiveOrder" then if self.HasOnReceiveOrderSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_OnReceiveOrder) if (math.random(1, self.OnReceiveOrderSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.NextAlertSoundT = CurTime() + 2 self.CurrentOnReceiveOrderSound = sdType(self, sdtbl, self.OnReceiveOrderSoundLevel, self:VJ_DecideSoundPitch(self.OnReceiveOrderSoundPitch.a, self.OnReceiveOrderSoundPitch.b)) end end return elseif sdSet == "MoveOutOfPlayersWay" then if self.HasMoveOutOfPlayersWaySounds == true then local sdtbl = VJ_PICK(self.SoundTbl_MoveOutOfPlayersWay) if (math.random(1, self.MoveOutOfPlayersWaySoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentMoveOutOfPlayersWaySound = sdType(self, sdtbl, self.MoveOutOfPlayersWaySoundLevel, self:VJ_DecideSoundPitch(self.MoveOutOfPlayersWaySoundPitch.a, self.MoveOutOfPlayersWaySoundPitch.b)) end end return elseif sdSet == "MedicBeforeHeal" then if self.HasMedicSounds_BeforeHeal == true then local sdtbl = VJ_PICK(self.SoundTbl_MedicBeforeHeal) if (math.random(1, self.MedicBeforeHealSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentMedicBeforeHealSound = sdType(self, sdtbl, self.BeforeHealSoundLevel, self:VJ_DecideSoundPitch(self.BeforeHealSoundPitch.a, self.BeforeHealSoundPitch.b)) end end return elseif sdSet == "MedicOnHeal" then if self.HasMedicSounds_AfterHeal == true then local sdtbl = VJ_PICK(self.SoundTbl_MedicAfterHeal) if sdtbl == false then sdtbl = VJ_PICK(DefaultSoundTbl_MedicAfterHeal) end -- Default table if (math.random(1, self.MedicAfterHealSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentMedicAfterHealSound = sdType(self, sdtbl, self.AfterHealSoundLevel, self:VJ_DecideSoundPitch(self.AfterHealSoundPitch.a, self.AfterHealSoundPitch.b)) end end return elseif sdSet == "MedicReceiveHeal" then if self.HasMedicSounds_ReceiveHeal == true then local sdtbl = VJ_PICK(self.SoundTbl_MedicReceiveHeal) if (math.random(1, self.MedicReceiveHealSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentMedicReceiveHealSound = sdType(self, sdtbl, self.MedicReceiveHealSoundLevel, self:VJ_DecideSoundPitch(self.MedicReceiveHealSoundPitch.a, self.MedicReceiveHealSoundPitch.b)) end end return elseif sdSet == "OnPlayerSight" then if self.HasOnPlayerSightSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_OnPlayerSight) if (math.random(1, self.OnPlayerSightSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.NextAlertSoundT = CurTime() + math.random(1,2) self.CurrentOnPlayerSightSound = sdType(self, sdtbl, self.OnPlayerSightSoundLevel, self:VJ_DecideSoundPitch(self.OnPlayerSightSoundPitch.a, self.OnPlayerSightSoundPitch.b)) end end return elseif sdSet == "InvestigateSound" then if self.HasInvestigateSounds == true && CurTime() > self.NextInvestigateSoundT then local sdtbl = VJ_PICK(self.SoundTbl_Investigate) if (math.random(1, self.InvestigateSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.CurrentInvestigateSound = sdType(self, sdtbl, self.InvestigateSoundLevel, self:VJ_DecideSoundPitch(self.InvestigateSoundPitch.a, self.InvestigateSoundPitch.b)) end self.NextInvestigateSoundT = CurTime() + math.Rand(self.NextSoundTime_Investigate.a, self.NextSoundTime_Investigate.b) end return elseif sdSet == "LostEnemy" then if self.HasLostEnemySounds == true && CurTime() > self.LostEnemySoundT then local sdtbl = VJ_PICK(self.SoundTbl_LostEnemy) if (math.random(1, self.LostEnemySoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.CurrentLostEnemySound = sdType(self, sdtbl, self.LostEnemySoundLevel, self:VJ_DecideSoundPitch(self.LostEnemySoundPitch.a, self.LostEnemySoundPitch.b)) end self.LostEnemySoundT = CurTime() + math.Rand(self.NextSoundTime_LostEnemy.a, self.NextSoundTime_LostEnemy.b) end return elseif sdSet == "Alert" then if self.HasAlertSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_Alert) if (math.random(1, self.AlertSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() local dur = CurTime() + ((((SoundDuration(sdtbl) > 0) and SoundDuration(sdtbl)) or 2) + 1) self.NextIdleSoundT = dur self.PainSoundT = dur self.NextSuppressingSoundT = CurTime() + 4 self.NextAlertSoundT = CurTime() + math.Rand(self.NextSoundTime_Alert.a, self.NextSoundTime_Alert.b) self.CurrentAlertSound = sdType(self, sdtbl, self.AlertSoundLevel, self:VJ_DecideSoundPitch(self.AlertSoundPitch.a, self.AlertSoundPitch.b)) end end return elseif sdSet == "CallForHelp" then if self.HasCallForHelpSounds == true && CurTime() > self.NextCallForHelpSoundT then local sdtbl = VJ_PICK(self.SoundTbl_CallForHelp) if (math.random(1, self.CallForHelpSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.NextSuppressingSoundT = CurTime() + math.random(2.5, 4) self.CurrentCallForHelpSound = sdType(self, sdtbl, self.CallForHelpSoundLevel, self:VJ_DecideSoundPitch(self.CallForHelpSoundPitch.a, self.CallForHelpSoundPitch.b)) self.NextCallForHelpSoundT = CurTime() + 2 end end return elseif sdSet == "BecomeEnemyToPlayer" then if self.HasBecomeEnemyToPlayerSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_BecomeEnemyToPlayer) if (math.random(1, self.BecomeEnemyToPlayerChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() timer.Simple(0.05,function() if IsValid(self) then VJ_STOPSOUND(self.CurrentPainSound) end end) //timer.Simple(1.3,function() if IsValid(self) then VJ_STOPSOUND(self.CurrentAlertSound) end end) local dur = CurTime() + ((((SoundDuration(sdtbl) > 0) and SoundDuration(sdtbl)) or 2) + 1) self.PainSoundT = dur self.NextAlertSoundT = dur self.NextInvestigateSoundT = CurTime() + 2 self.NextIdleSoundT_RegularChange = CurTime() + math.random(2, 3) self.NextSuppressingSoundT = CurTime() + math.random(2.5, 4) self.CurrentBecomeEnemyToPlayerSound = sdType(self, sdtbl, self.BecomeEnemyToPlayerSoundLevel, self:VJ_DecideSoundPitch(self.BecomeEnemyToPlayerPitch.a, self.BecomeEnemyToPlayerPitch.b)) end end return elseif sdSet == "OnKilledEnemy" then if self.HasOnKilledEnemySound == true && CurTime() > self.OnKilledEnemySoundT then local sdtbl = VJ_PICK(self.SoundTbl_OnKilledEnemy) if (math.random(1, self.OnKilledEnemySoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.CurrentOnKilledEnemySound = sdType(self, sdtbl, self.OnKilledEnemySoundLevel, self:VJ_DecideSoundPitch(self.OnKilledEnemySoundPitch.a, self.OnKilledEnemySoundPitch.b)) end self.OnKilledEnemySoundT = CurTime() + math.Rand(self.NextSoundTime_OnKilledEnemy.a, self.NextSoundTime_OnKilledEnemy.b) end return elseif sdSet == "AllyDeath" then if self.HasOnKilledEnemySound == true && CurTime() > self.AllyDeathSoundT then local sdtbl = VJ_PICK(self.SoundTbl_AllyDeath) if (math.random(1, self.AllyDeathSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT = self.NextIdleSoundT + 2 self.CurrentAllyDeathSound = sdType(self, sdtbl, self.AllyDeathSoundLevel, self:VJ_DecideSoundPitch(self.AllyDeathSoundPitch.a, self.AllyDeathSoundPitch.b)) end self.AllyDeathSoundT = CurTime() + math.Rand(self.NextSoundTime_AllyDeath.a, self.NextSoundTime_AllyDeath.b) end return elseif sdSet == "Pain" then if self.HasPainSounds == true && CurTime() > self.PainSoundT then local sdtbl = VJ_PICK(self.SoundTbl_Pain) local sdDur = 2 if (math.random(1, self.PainSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() VJ_STOPSOUND(self.CurrentIdleSound) self.NextIdleSoundT_RegularChange = CurTime() + 1 self.CurrentPainSound = sdType(self, sdtbl, self.PainSoundLevel, self:VJ_DecideSoundPitch(self.PainSoundPitch.a, self.PainSoundPitch.b)) sdDur = (SoundDuration(sdtbl) > 0 and SoundDuration(sdtbl)) or sdDur end self.PainSoundT = CurTime() + ((self.NextSoundTime_Pain == true and sdDur) or math.Rand(self.NextSoundTime_Pain.a, self.NextSoundTime_Pain.b)) end return elseif sdSet == "Impact" then if self.HasImpactSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_Impact) if sdtbl == false then sdtbl = VJ_PICK(DefaultSoundTbl_Impact) end -- Default table if (math.random(1, self.ImpactSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self.CurrentImpactSound = sdType(self, sdtbl, self.ImpactSoundLevel, self:VJ_DecideSoundPitch(self.ImpactSoundPitch.a, self.ImpactSoundPitch.b)) end end return elseif sdSet == "DamageByPlayer" then if self.HasDamageByPlayerSounds == true && CurTime() > self.NextDamageByPlayerSoundT then local sdtbl = VJ_PICK(self.SoundTbl_DamageByPlayer) if (math.random(1, self.DamageByPlayerSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() local dur = CurTime() + ((((SoundDuration(sdtbl) > 0) and SoundDuration(sdtbl)) or 2) + 1) self.PainSoundT = dur self.NextIdleSoundT_RegularChange = CurTime() + dur timer.Simple(0.05, function() if IsValid(self) then VJ_STOPSOUND(self.CurrentPainSound) end end) self.CurrentDamageByPlayerSound = sdType(self, sdtbl, self.DamageByPlayerSoundLevel, self:VJ_DecideSoundPitch(self.DamageByPlayerPitch.a, self.DamageByPlayerPitch.b)) end self.NextDamageByPlayerSoundT = CurTime() + math.Rand(self.NextSoundTime_DamageByPlayer.a, self.NextSoundTime_DamageByPlayer.b) end return elseif sdSet == "Death" then if self.HasDeathSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_Death) if (math.random(1, self.DeathSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self.CurrentDeathSound = sdType(self, sdtbl, self.DeathSoundLevel, self:VJ_DecideSoundPitch(self.DeathSoundPitch.a, self.DeathSoundPitch.b)) end end return --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- Base-Specific Sound Tables --=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-- elseif sdSet == "Suppressing" then if self.HasSuppressingSounds == true && CurTime() > self.NextSuppressingSoundT then local sdtbl = VJ_PICK(self.SoundTbl_Suppressing) if (math.random(1, self.SuppressingSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + 2 self.CurrentSuppressingSound = sdType(self, sdtbl, self.SuppressingSoundLevel, self:VJ_DecideSoundPitch(self.SuppressingPitch.a, self.SuppressingPitch.b)) end self.NextSuppressingSoundT = CurTime() + math.Rand(self.NextSoundTime_Suppressing.a, self.NextSoundTime_Suppressing.b) end return elseif sdSet == "WeaponReload" then if self.HasWeaponReloadSounds == true && CurTime() > self.NextWeaponReloadSoundT then local sdtbl = VJ_PICK(self.SoundTbl_WeaponReload) if (math.random(1, self.WeaponReloadSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentWeaponReloadSound = sdType(self, sdtbl, self.WeaponReloadSoundLevel, self:VJ_DecideSoundPitch(self.WeaponReloadSoundPitch.a, self.WeaponReloadSoundPitch.b)) end self.NextWeaponReloadSoundT = CurTime() + math.Rand(self.NextSoundTime_WeaponReload.a, self.NextSoundTime_WeaponReload.b) end return elseif sdSet == "BeforeMeleeAttack" then if self.HasMeleeAttackSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_BeforeMeleeAttack) if (math.random(1, self.BeforeMeleeAttackSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end if self.IdleSounds_PlayOnAttacks == false then VJ_STOPSOUND(self.CurrentIdleSound) end -- Don't stop idle sounds if we aren't suppose to self.NextIdleSoundT_RegularChange = CurTime() + 1 self.CurrentBeforeMeleeAttackSound = sdType(self, sdtbl, self.BeforeMeleeAttackSoundLevel, self:VJ_DecideSoundPitch(self.BeforeMeleeAttackSoundPitch.a, self.BeforeMeleeAttackSoundPitch.b)) end end return elseif sdSet == "MeleeAttack" then if self.HasMeleeAttackSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_MeleeAttack) if sdtbl == false then sdtbl = VJ_PICK(self.DefaultSoundTbl_MeleeAttack) end -- Default table if (math.random(1, self.MeleeAttackSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end if self.IdleSounds_PlayOnAttacks == false then VJ_STOPSOUND(self.CurrentIdleSound) end -- Don't stop idle sounds if we aren't suppose to self.NextIdleSoundT_RegularChange = CurTime() + 1 self.CurrentMeleeAttackSound = sdType(self, sdtbl, self.MeleeAttackSoundLevel, self:VJ_DecideSoundPitch(self.MeleeAttackSoundPitch.a, self.MeleeAttackSoundPitch.b)) end if self.HasExtraMeleeAttackSounds == true then sdtbl = VJ_PICK(self.SoundTbl_MeleeAttackExtra) if (math.random(1, self.ExtraMeleeSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if self.IdleSounds_PlayOnAttacks == false then VJ_STOPSOUND(self.CurrentIdleSound) end -- Don't stop idle sounds if we aren't suppose to self.CurrentExtraMeleeAttackSound = VJ_EmitSound(self, sdtbl, self.ExtraMeleeAttackSoundLevel, self:VJ_DecideSoundPitch(self.ExtraMeleeSoundPitch.a, self.ExtraMeleeSoundPitch.b)) end end end return elseif sdSet == "MeleeAttackMiss" then if self.HasMeleeAttackMissSounds == true then local sdtbl = VJ_PICK(self.SoundTbl_MeleeAttackMiss) if sdtbl == false then sdtbl = VJ_PICK(DefaultSoundTbl_MeleeAttackMiss) end -- Default table if (math.random(1, self.MeleeAttackMissSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end VJ_STOPSOUND(self.CurrentIdleSound) self.NextIdleSoundT_RegularChange = CurTime() + 1 self.CurrentMeleeAttackMissSound = sdType(self, sdtbl, self.MeleeAttackMissSoundLevel, self:VJ_DecideSoundPitch(self.MeleeAttackMissSoundPitch.a, self.MeleeAttackMissSoundPitch.b)) end end return elseif sdSet == "GrenadeAttack" then if self.HasGrenadeAttackSounds == true && CurTime() > self.NextGrenadeAttackSoundT then local sdtbl = VJ_PICK(self.SoundTbl_GrenadeAttack) if (math.random(1, self.GrenadeAttackSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end if self.IdleSounds_PlayOnAttacks == false then self:StopAllCommonSpeechSounds() end -- Don't stop idle sounds if we aren't suppose to self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentGrenadeAttackSound = sdType(self, sdtbl, self.GrenadeAttackSoundLevel, self:VJ_DecideSoundPitch(self.GrenadeAttackSoundPitch.a, self.GrenadeAttackSoundPitch.b)) end end return elseif sdSet == "OnGrenadeSight" then if self.HasOnGrenadeSightSounds == true && CurTime() > self.NextOnGrenadeSightSoundT then local sdtbl = VJ_PICK(self.SoundTbl_OnGrenadeSight) if (math.random(1, self.OnGrenadeSightSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentOnGrenadeSightSound = sdType(self, sdtbl, self.OnGrenadeSightSoundLevel, self:VJ_DecideSoundPitch(self.OnGrenadeSightSoundPitch.a, self.OnGrenadeSightSoundPitch.b)) end self.NextOnGrenadeSightSoundT = CurTime() + math.Rand(self.NextSoundTime_OnGrenadeSight.a, self.NextSoundTime_OnGrenadeSight.b) end return elseif sdSet == "OnDangerSight" then if self.HasOnDangerSightSounds == true && CurTime() > self.NextOnDangerSightSoundT then local sdtbl = VJ_PICK(self.SoundTbl_OnDangerSight) if (math.random(1, self.OnDangerSightSoundChance) == 1 && sdtbl != false) or (cTbl != false) then if cTbl != false then sdtbl = cTbl end self:StopAllCommonSpeechSounds() self.NextIdleSoundT_RegularChange = CurTime() + math.random(3, 4) self.CurrentOnDangerSightSound = sdType(self, sdtbl, self.OnDangerSightSoundLevel, self:VJ_DecideSoundPitch(self.OnDangerSightSoundPitch.a, self.OnDangerSightSoundPitch.b)) end self.NextOnDangerSightSoundT = CurTime() + math.Rand(self.NextSoundTime_OnDangerSight.a, self.NextSoundTime_OnDangerSight.b) end return end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:FootStepSoundCode(CustomTbl) if self.HasSounds == false or self.HasFootStepSound == false or self.MovementType == VJ_MOVETYPE_STATIONARY then return end if self:IsOnGround() && self:GetGroundEntity() != NULL then if self.DisableFootStepSoundTimer == true then self:CustomOnFootStepSound() local soundtbl = self.SoundTbl_FootStep if CustomTbl != nil && #CustomTbl != 0 then soundtbl = CustomTbl end if VJ_PICK(soundtbl) == false then soundtbl = DefaultSoundTbl_FootStep end VJ_EmitSound(self,soundtbl,self.FootStepSoundLevel,self:VJ_DecideSoundPitch(self.FootStepPitch.a,self.FootStepPitch.b)) if self.HasWorldShakeOnMove == true then util.ScreenShake(self:GetPos(), self.WorldShakeOnMoveAmplitude, self.WorldShakeOnMoveFrequency, self.WorldShakeOnMoveDuration, self.WorldShakeOnMoveRadius) end return elseif self:IsMoving() && CurTime() > self.FootStepT && self:GetInternalVariable("m_flMoveWaitFinished") <= 0 then self:CustomOnFootStepSound() local soundtbl = self.SoundTbl_FootStep if CustomTbl != nil && #CustomTbl != 0 then soundtbl = CustomTbl end if VJ_PICK(soundtbl) == false then soundtbl = DefaultSoundTbl_FootStep end local curSched = self.CurrentSchedule if self.DisableFootStepOnRun == false && ((VJ_HasValue(self.AnimTbl_Run,self:GetMovementActivity())) or (curSched != nil && curSched.MoveType == 1)) /*(VJ_HasValue(VJ_RunActivites,self:GetMovementActivity()) or VJ_HasValue(self.CustomRunActivites,self:GetMovementActivity()))*/ then self:CustomOnFootStepSound_Run() VJ_EmitSound(self,soundtbl,self.FootStepSoundLevel,self:VJ_DecideSoundPitch(self.FootStepPitch.a,self.FootStepPitch.b)) if self.HasWorldShakeOnMove == true then util.ScreenShake(self:GetPos(), self.WorldShakeOnMoveAmplitude, self.WorldShakeOnMoveFrequency, self.WorldShakeOnMoveDuration, self.WorldShakeOnMoveRadius) end self.FootStepT = CurTime() + self.FootStepTimeRun return elseif self.DisableFootStepOnWalk == false && (VJ_HasValue(self.AnimTbl_Walk,self:GetMovementActivity()) or (curSched != nil && curSched.MoveType == 0)) /*(VJ_HasValue(VJ_WalkActivites,self:GetMovementActivity()) or VJ_HasValue(self.CustomWalkActivites,self:GetMovementActivity()))*/ then self:CustomOnFootStepSound_Walk() VJ_EmitSound(self,soundtbl,self.FootStepSoundLevel,self:VJ_DecideSoundPitch(self.FootStepPitch.a,self.FootStepPitch.b)) if self.HasWorldShakeOnMove == true then util.ScreenShake(self:GetPos(), self.WorldShakeOnMoveAmplitude, self.WorldShakeOnMoveFrequency, self.WorldShakeOnMoveDuration, self.WorldShakeOnMoveRadius) end self.FootStepT = CurTime() + self.FootStepTimeWalk return end end end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:StopAllCommonSpeechSounds() VJ_STOPSOUND(self.CurrentGeneralSpeechSound) VJ_STOPSOUND(self.CurrentIdleSound) VJ_STOPSOUND(self.CurrentIdleDialogueAnswerSound) VJ_STOPSOUND(self.CurrentInvestigateSound) VJ_STOPSOUND(self.CurrentLostEnemySound) VJ_STOPSOUND(self.CurrentAlertSound) VJ_STOPSOUND(self.CurrentFollowPlayerSound) VJ_STOPSOUND(self.CurrentUnFollowPlayerSound) VJ_STOPSOUND(self.CurrentMoveOutOfPlayersWaySound) VJ_STOPSOUND(self.CurrentBecomeEnemyToPlayerSound) VJ_STOPSOUND(self.CurrentOnPlayerSightSound) VJ_STOPSOUND(self.CurrentDamageByPlayerSound) VJ_STOPSOUND(self.CurrentOnGrenadeSightSound) VJ_STOPSOUND(self.CurrentOnDangerSightSound) VJ_STOPSOUND(self.CurrentWeaponReloadSound) VJ_STOPSOUND(self.CurrentMedicBeforeHealSound) VJ_STOPSOUND(self.CurrentMedicAfterHealSound) VJ_STOPSOUND(self.CurrentMedicReceiveHealSound) VJ_STOPSOUND(self.CurrentCallForHelpSound) VJ_STOPSOUND(self.CurrentOnReceiveOrderSound) VJ_STOPSOUND(self.CurrentOnKilledEnemySound) VJ_STOPSOUND(self.CurrentAllyDeathSound) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:StopAllCommonSounds() VJ_STOPSOUND(self.CurrentGeneralSpeechSound) VJ_STOPSOUND(self.CurrentBreathSound) VJ_STOPSOUND(self.CurrentIdleSound) VJ_STOPSOUND(self.CurrentIdleDialogueAnswerSound) VJ_STOPSOUND(self.CurrentInvestigateSound) VJ_STOPSOUND(self.CurrentLostEnemySound) VJ_STOPSOUND(self.CurrentAlertSound) VJ_STOPSOUND(self.CurrentBeforeMeleeAttackSound) //VJ_STOPSOUND(self.CurrentMeleeAttackSound) //VJ_STOPSOUND(self.CurrentExtraMeleeAttackSound) //VJ_STOPSOUND(self.CurrentMeleeAttackMissSound) VJ_STOPSOUND(self.CurrentPainSound) VJ_STOPSOUND(self.CurrentFollowPlayerSound) VJ_STOPSOUND(self.CurrentUnFollowPlayerSound) VJ_STOPSOUND(self.CurrentMoveOutOfPlayersWaySound) VJ_STOPSOUND(self.CurrentBecomeEnemyToPlayerSound) VJ_STOPSOUND(self.CurrentOnPlayerSightSound) VJ_STOPSOUND(self.CurrentDamageByPlayerSound) VJ_STOPSOUND(self.CurrentGrenadeAttackSound) VJ_STOPSOUND(self.CurrentOnGrenadeSightSound) VJ_STOPSOUND(self.CurrentOnDangerSightSound) VJ_STOPSOUND(self.CurrentSuppressingSound) VJ_STOPSOUND(self.CurrentWeaponReloadSound) VJ_STOPSOUND(self.CurrentMedicBeforeHealSound) VJ_STOPSOUND(self.CurrentMedicAfterHealSound) VJ_STOPSOUND(self.CurrentMedicReceiveHealSound) VJ_STOPSOUND(self.CurrentCallForHelpSound) VJ_STOPSOUND(self.CurrentOnReceiveOrderSound) VJ_STOPSOUND(self.CurrentOnKilledEnemySound) VJ_STOPSOUND(self.CurrentAllyDeathSound) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:GetAttackSpread(wep, target) return end