--[[ | 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/ --]] AddCSLuaFile("shared.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. -----------------------------------------------*/ ENT.Model = {"models/vj_hlr/hla/prdroid.mdl"} -- The game will pick a random model from the table when the SNPC is spawned | Add as many as you want ENT.StartHealth = 100 ENT.HullType = HULL_HUMAN ENT.MovementType = VJ_MOVETYPE_AERIAL -- How does the SNPC move? ENT.Aerial_FlyingSpeed_Calm = 100 -- The speed it should fly with, when it's wandering, moving slowly, etc. | Basically walking compared to ground SNPCs ENT.Aerial_FlyingSpeed_Alerted = 200 -- The speed it should fly with, when it's chasing an enemy, moving away quickly, etc. | Basically running compared to ground SNPCs ENT.Aerial_AnimTbl_Calm = {ACT_IDLE} -- Animations it plays when it's wandering around while idle ENT.Aerial_AnimTbl_Alerted = {ACT_IDLE} -- Animations it plays when it's moving while alerted ENT.VJC_Data = { FirstP_Bone = "sphere01", -- If left empty, the base will attempt to calculate a position for first person FirstP_Offset = Vector(15, 0, -3), -- The offset for the controller when the camera is in first person FirstP_ShrinkBone = false, -- Should the bone shrink? Useful if the bone is obscuring the player's view } --------------------------------------------------------------------------------------------------------------------------------------------- ENT.VJ_NPC_Class = {"CLASS_PLAYER_ALLY"} -- NPCs with the same class with be allied to each other ENT.FriendsWithAllPlayerAllies = true -- Should this SNPC be friends with all other player allies that are running on VJ Base? ENT.ConstantlyFaceEnemy = true -- Should it face the enemy constantly? ENT.HasMeleeAttack = true -- Should the SNPC have a melee attack? ENT.MeleeAttackDamage = 20 ENT.MeleeAttackDistance = 55 -- How close does it have to be until it attacks? ENT.MeleeAttackDamageDistance = 80 -- How far does the damage go? ENT.TimeUntilMeleeAttackDamage = false -- This counted in seconds | This calculates the time until it hits something ENT.HasRangeAttack = true -- Should the SNPC have a range attack? ENT.RangeAttackEntityToSpawn = "obj_vj_hlr1_probed_needle" -- The entity that is spawned when range attacking ENT.RangeDistance = 1500 -- This is how far away it can shoot ENT.RangeToMeleeDistance = 60 -- How close does it have to be until it uses melee? ENT.TimeUntilRangeAttackProjectileRelease = false -- How much time until the needle code is ran? ENT.NextRangeAttackTime = 3 -- How much time until it can use a range attack? ENT.NextRangeAttackTime_DoRand = 4 -- False = Don't use random time | Number = Picks a random number between the regular timer and this timer ENT.RangeUseAttachmentForPos = true -- Should the needle spawn on a attachment? ENT.RangeUseAttachmentForPosID = "0" -- The attachment used on the range attack if RangeUseAttachmentForPos is set to true ENT.DisableRangeAttackAnimation = true -- if true, it will disable the animation code ENT.NoChaseAfterCertainRange = true -- Should the SNPC not be able to chase when it's between number x and y? ENT.NoChaseAfterCertainRange_FarDistance = "UseRangeDistance" -- How far until it can chase again? | "UseRangeDistance" = Use the number provided by the range attack instead ENT.NoChaseAfterCertainRange_CloseDistance = "UseRangeDistance" -- How near until it can chase again? | "UseRangeDistance" = Use the number provided by the range attack instead ENT.NoChaseAfterCertainRange_Type = "OnlyRange" -- "Regular" = Default behavior | "OnlyRange" = Only does it if it's able to range attack ENT.IsMedicSNPC = true -- Is this SNPC a medic? Does it heal other friendly friendly SNPCs, and players(If friendly) ENT.AnimTbl_Medic_GiveHealth = {ACT_ARM} -- Animations is plays when giving health to an ally ENT.Medic_CheckDistance = 1000 -- How far does it check for allies that are hurt? | World units ENT.Medic_HealDistance = 600 -- How close does it have to be until it stops moving and heals its ally? ENT.Medic_NextHealTime = VJ_Set(5, 8) -- How much time until it can give health to an ally again ENT.Medic_SpawnPropOnHeal = false -- Should it spawn a prop, such as small health vial at a attachment when healing an ally? ENT.Medic_CanBeHealed = false -- If set to false, this SNPC can't be healed! ENT.HasDeathAnimation = true -- Does it play an animation when it dies? ENT.AnimTbl_Death = {ACT_DIESIMPLE} -- Death Animations ENT.DeathAnimationTime = 0.6 -- Time until the SNPC spawns its corpse and gets removed ENT.HasDeathRagdoll = false -- If set to false, it will not spawn the regular ragdoll of the SNPC ENT.HasExtraMeleeAttackSounds = true -- Set to true to use the extra melee attack sounds -- ====== Sound File Paths ====== -- -- Leave blank if you don't want any sounds to play ENT.SoundTbl_Breath = {"vj_hlr/hla_npc/prdroid/engine.wav"} ENT.SoundTbl_MedicAfterHeal = {"vj_hlr/hla_npc/prdroid/shoot_heal.wav"} ENT.SoundTbl_Alert = {"vj_hlr/hla_npc/prdroid/alert.wav"} ENT.SoundTbl_MeleeAttackMiss = {"vj_hlr/hl1_npc/zombie/claw_miss1.wav","vj_hlr/hl1_npc/zombie/claw_miss2.wav"} ENT.SoundTbl_BeforeRangeAttack = {"vj_hlr/hla_npc/prdroid/readytoattack.wav"} ENT.SoundTbl_RangeAttack = {"vj_hlr/hla_npc/prdroid/shoot.wav"} ENT.SoundTbl_Death = {"vj_hlr/hla_npc/prdroid/die.wav"} ENT.GeneralSoundPitch1 = 100 --------------------------------------------------------------------------------------------------------------------------------------------- local spawnPos = Vector(0, 0, 80) -- function ENT:CustomOnInitialize() self:SetCollisionBounds(Vector(35, 35, 15), Vector(-35, -35, -50)) self:SetPos(self:GetPos() + spawnPos) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:Controller_IntMsg(ply, controlEnt) ply:ChatPrint("Hold-SPACE: Fires healing needle while range attacking") end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnAcceptInput(key, activator, caller, data) //print(key) if key == "melee" then self:MeleeAttackCode() elseif key == "shoot" then self:RangeAttackCode() end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnMedic_OnHeal(ent) self:VJ_ACT_PLAYACTIVITY(ACT_RANGE_ATTACK1, true, false) local needle = ents.Create("obj_vj_hlr1_probed_needle") needle:SetPos(self:GetAttachment(self:LookupAttachment("0")).Pos) needle:SetAngles((ent:GetPos() - needle:GetPos()):Angle()) needle:SetOwner(self) needle:SetPhysicsAttacker(self) needle.Needle_Heal = true needle:Spawn() needle:Activate() local phys = needle:GetPhysicsObject() if IsValid(phys) then phys:Wake() phys:SetVelocity(self:CalculateProjectile("Line", self:GetAttachment(self:LookupAttachment("0")).Pos, ent:GetPos() + ent:OBBCenter(), 1500)) end return false end --------------------------------------------------------------------------------------------------------------------------------------------- local anim1 = ACT_ARM local anim2 = ACT_RANGE_ATTACK1 //local anim3 = ACT_RANGE_ATTACK2 -- Rapid firing (3-shot burst) range attack animation (Currently unused) -- function ENT:CustomOnRangeAttack_BeforeStartTimer() self.CurrentAttackAnimation = anim1 self:VJ_ACT_PLAYACTIVITY(self.CurrentAttackAnimation, false, 0, true) local firstAct = self:DecideAnimationLength(self.CurrentAttackAnimation, false) self.CurrentAttackAnimationDuration = firstAct + VJ_GetSequenceDuration(self, anim2) self.PlayingAttackAnimation = true timer.Create("timer_act_playingattack"..self:EntIndex(), self.CurrentAttackAnimationDuration, 1, function() self.PlayingAttackAnimation = false self:VJ_ACT_PLAYACTIVITY(ACT_RELOAD, true, false, true) VJ_EmitSound(self, "vj_hlr/hla_npc/prdroid/reload.wav", 90, 100) -- Reload sound end) timer.Simple(firstAct, function() if IsValid(self) then self:VJ_ACT_PLAYACTIVITY(anim2, false, 0, true) end end) end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomRangeAttackCode_BeforeProjectileSpawn(projectile) if self.VJ_IsBeingControlled && self.VJ_TheController:KeyDown(IN_JUMP) then projectile.Needle_Heal = true end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:RangeAttackCode_GetShootPos(projectile) return self:CalculateProjectile("Line", self:GetAttachment(self:LookupAttachment("0")).Pos, self:GetEnemy():GetPos() + self:GetEnemy():OBBCenter(), 1500) end --------------------------------------------------------------------------------------------------------------------------------------------- local vec = Vector(0, 0, 0) -- function ENT:CustomOnTakeDamage_BeforeImmuneChecks(dmginfo, hitgroup) if dmginfo:GetDamagePosition() != vec then local rico = EffectData() rico:SetOrigin(dmginfo:GetDamagePosition()) rico:SetScale(5) -- Size rico:SetMagnitude(math.random(1, 2)) -- Effect type | 1 = Animated | 2 = Basic util.Effect("VJ_HLR_Rico",rico) end end --------------------------------------------------------------------------------------------------------------------------------------------- function ENT:CustomOnPriorToKilled(dmginfo, hitgroup) if dmginfo:IsDamageType(DMG_BLAST) then self.HasDeathAnimation = false end end --------------------------------------------------------------------------------------------------------------------------------------------- local collideSds = {"vj_hlr/fx/metal1.wav","vj_hlr/fx/metal2.wav","vj_hlr/fx/metal3.wav","vj_hlr/fx/metal4.wav","vj_hlr/fx/metal5.wav"} -- function ENT:CustomOnKilled(dmginfo, hitgroup) util.VJ_SphereDamage(self, self, self:GetPos(), 75, 25, DMG_BLAST, false, true) VJ_EmitSound(self, "vj_hlr/hla_npc/prdroid/explode.wav", 90, 100) local applyForce = self.HasDeathAnimation and false or true self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_cap.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("sphere01")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_armpiece.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed011")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_armpiece.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed007")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_claw.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed012")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_claw.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed008")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_dshooter.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed005")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_tail.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed014")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_upperarm.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed011")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_upperarm.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed007")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_body.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed003")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_forearm.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed011")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) self:CreateGibEntity("obj_vj_gib","models/vj_hlr/gibs/pb_forearm.mdl",{BloodDecal="",Ang=self:GetAngles(),Pos=self:GetBonePosition(self:LookupBone("unnamed007")),CollideSound=collideSds,Vel_ApplyDmgForce=applyForce}) local spr = ents.Create("env_sprite") spr:SetKeyValue("model","vj_hl/sprites/zerogxplode.vmt") spr:SetKeyValue("GlowProxySize","2.0") spr:SetKeyValue("HDRColorScale","1.0") spr:SetKeyValue("renderfx","14") spr:SetKeyValue("rendermode","5") spr:SetKeyValue("renderamt","255") spr:SetKeyValue("disablereceiveshadows","0") spr:SetKeyValue("mindxlevel","0") spr:SetKeyValue("maxdxlevel","0") spr:SetKeyValue("framerate","15.0") spr:SetKeyValue("spawnflags","0") spr:SetKeyValue("scale","2") spr:SetPos(self:GetPos()) spr:Spawn() spr:Fire("Kill","",0.9) timer.Simple(0.9,function() if IsValid(spr) then spr:Remove() end end) end