Advertisement
Guest User

Weeping Angel lua

a guest
Jan 5th, 2013
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.65 KB | None | 0 0
  1. -- Weeping Angel
  2. -- Original stalking entity by that Tetris guy.
  3. -- All credit to TheSniper9 for the models & textures. Keep up the great work! :D
  4. -- Credit to Darth Telac for helping me out with the code.
  5. --So yeah, very minor code change to make this thing silent.
  6. -- Now in addon form... muahahahaha
  7. AddCSLuaFile( 'cl_init.lua' )
  8. AddCSLuaFile( 'shared.lua' )
  9. include('shared.lua')
  10.  
  11. local COOLDOWN_TIME = 1
  12. local THINK_DELAY = 0.2
  13.  
  14. local TELEPORT_PROB = 0.09
  15. local TELEPORT_COOLDOWN = 1
  16. local TELEPORT_MAX_DIST = 3000
  17. local TELEPORT_MAX_DIST_FROM_PLR = 450
  18. local TELEPORT_MIN_DIST_FROM_PLR = 100
  19. local TELEPORT_MAX_TRIES = 20
  20.  
  21. local CREEP_PROB = 0.09
  22. local CREEP_COOLDOWN = 0.5
  23. local CREEP_DISTANCE_FRACTION = 0.5
  24.  
  25. local STAB_MAX_DIST = 80
  26. local STAB_PROB = 0.1
  27. local STAB_COOLDOWN = 2
  28. local STAB_FORCE = 12000
  29. local STAB_DAMAGE = 500
  30.  
  31. local EMITSOUND_MAX_DIST = 2200
  32. local EMITSOUND_PROB = 0.08
  33. local EMITSOUND_COOLDOWN = 4
  34.  
  35. local CREEPY_SOUNDS =
  36. {
  37.    
  38.     {
  39.         Snd = Sound( "silentangel.mp3" ),
  40.         Dur = 11
  41.     },
  42.    
  43.     {
  44.         Snd = Sound( "silentangel.mp3" ),
  45.         Dur = 2
  46.     },
  47.    
  48.     {
  49.         Snd = Sound( "silentangel.mp3" ),
  50.         Dur = 2
  51.     },
  52.    
  53.     {
  54.         Snd = Sound( "silentangel.mp3" ),
  55.         Dur = 3
  56.     },
  57.    
  58.     {
  59.         Snd = Sound( "silentangel.mp3" ),
  60.         Dur = 7
  61.     },
  62.    
  63.     {
  64.         Snd = Sound( "silentangel.mp3" ),
  65.         Dur = 2
  66.     },
  67.  
  68.     {
  69.         Snd = Sound( "silentangel.mp3" ),
  70.         Dur = 2
  71.     },
  72.    
  73.     {
  74.         Snd = Sound( "silentangel.mp3" ),
  75.         Dur = 3
  76.     },
  77.    
  78.     {
  79.         Snd = Sound( "silentangel.mp3" ),
  80.         Dur = 2
  81.     },
  82.    
  83.     {
  84.         Snd = Sound( "silentangel.mp3" ),
  85.         Dur = 1
  86.     },
  87.    
  88.     {
  89.         Snd = Sound( "silentangel.mp3" ),
  90.         Dur = 5
  91.     },
  92.    
  93.     {
  94.         Snd = Sound( "silentangel.mp3" ),
  95.         Dur = 4
  96.     },
  97.    
  98.     {
  99.         Snd = Sound( "silentangel.mp3" ),
  100.         Dur = 3
  101.     },
  102.    
  103.     {
  104.         Snd = Sound( "silentangel.mp3" ),
  105.         Dur = 3
  106.     }
  107.  
  108. }
  109.  
  110. local sndDrawKnife = Sound( "" )
  111. local sndStab = Sound( "silentangel.mp3" )
  112.  
  113.  
  114. function ENT:SpawnFunction( plr, tr )
  115.    
  116.     if not tr.Hit then return end
  117.    
  118.     local ent = ents.Create( ClassName )
  119.     ent:SetPos( tr.HitPos + tr.HitNormal * 24 )
  120.     ent:Spawn()
  121.     ent:Activate()    
  122.     ent:SetVictim( plr )
  123.     ent:DropToFloor()  
  124.  
  125.     return ent
  126.    
  127. end
  128.  
  129.  
  130. function ENT:Initialize()    
  131.    
  132.    
  133.     self:SetModel( "models/The_Sniper_9/DoctorWho/Extras/Angels/angelidle.mdl " )
  134.  
  135.    
  136.    
  137.     self:PhysicsInit( SOLID_VPHYSICS )
  138.    
  139.     local phys = self:GetPhysicsObject()      
  140.     if phys:IsValid() then          
  141.         phys:Wake()      
  142.     end
  143.  
  144.     self.Width = self:BoundingRadius() * 0.5
  145.    
  146.     self.CurSound = ""
  147.    
  148.     self.NextTeleport = 0
  149.     self.NextCreep = 0
  150.     self.NextEmit = 0
  151.     self.NextStab = 0
  152.    
  153.     self.Knife = NULL
  154.    
  155.     self.IsBeingCreepy = false
  156.    
  157.     self:SetMoveType(MOVETYPE_NONE)
  158.  
  159. end
  160.  
  161.  
  162. function ENT:SetVictim( plr )
  163.  
  164.     self.Victim = plr
  165.  
  166. end
  167.  
  168.  
  169. function ENT:HasVictimLOS()
  170.    
  171.     local tr = util.TraceLine(
  172.         {
  173.             start     = self:GetPos(),
  174.         endpos     = self.Victim:LocalToWorld( self.Victim:OBBCenter() ),
  175.             filter     = { self, self.Kinfe },
  176.             mask     = CONTENTS_SOLID | CONTENTS_OPAQUE | CONTENTS_MOVEABLE
  177.         } )
  178.    
  179.     if tr.Fraction > 0.98 then return true end
  180.    
  181.     return false
  182.    
  183. end
  184.  
  185.  
  186. function ENT:CanVictimSeeUs()
  187.  
  188.     local ViewEnt = self.Victim:GetViewEntity()
  189.  
  190.     if ViewEnt == self.Victim and not self:HasVictimLOS() then return false end
  191.  
  192.     local fov = self.Victim:GetFOV()
  193.     local Disp = self:GetPos() - ViewEnt:GetPos()
  194.     local Dist = Disp:Length()
  195.    
  196.     local MaxCos = math.abs( math.cos( math.acos( Dist / math.sqrt( Dist * Dist + self.Width * self.Width ) ) + fov * ( math.pi / 180 ) ) )
  197.     Disp:Normalize()
  198.    
  199.     if Disp:Dot( ViewEnt:EyeAngles():Forward() ) > MaxCos then
  200.         return true
  201.     end
  202.    
  203.     return false
  204.    
  205.    
  206. end
  207.  
  208.  
  209. function ENT:DrawKnife( vec )
  210.     self:SetModel( "models/The_Sniper_9/DoctorWho/Extras/Angels/angelattack.mdl" )
  211.     vec.z = 0
  212.     vec:Normalize()
  213.     local knifepos = self:GetPos() + vec * self.Width + Vector( 0, 0, 0.5 * self.Width )
  214.  
  215.     self.Knife = ents.Create( "prop_physics" )
  216.     self.Knife:SetPos( knifepos )
  217.     self.Knife:SetModel( "models/weapons/w_knife_t.mdl" )
  218.     self.Knife:SetAngles( vec:Angle() )
  219.     self.Knife:Spawn()
  220.     self.Knife:SetColor(0, 0 ,0 ,0)
  221.     self.Knife:SetParent( self )
  222.    
  223.     self:EmitSound( sndDrawKnife, 300, 100 )
  224.  
  225. end
  226.  
  227.  
  228. function ENT:TeleportToPos( pos )
  229.     self:SetModel( "models/The_Sniper_9/DoctorWho/Extras/Angels/angelidle.mdl " )
  230.  
  231.  
  232.     for i=1, TELEPORT_MAX_TRIES do
  233.        
  234.         local tr = util.TraceLine(
  235.             {
  236.                 start     = pos,
  237.             endpos     = pos - Vector( 0, 0, 64),
  238.                 filter     = { self, self.Kinfe },
  239.                 mask     = MASK_NPCSOLID
  240.             } )
  241.        
  242.         local spawnpos = tr.HitPos + Vector( 0, 0, self.Width + 8 )
  243.        
  244.         if util.PointContents( spawnpos ) & MASK_SOLID == 0 then
  245.            
  246.             self:SetPos( spawnpos )
  247.            
  248.             -- Jostle it a bit in case it's stuck
  249.             local phys = self:GetPhysicsObject()
  250.             phys:ApplyForceCenter( VectorRand() * 2 )
  251.             break
  252.            
  253.         end
  254.        
  255.         pos = pos + Vector( math.Rand( -20, 20 ), math.Rand( -20, 20 ), math.Rand( -5, 5 ) )
  256.        
  257.     end
  258.        
  259. end
  260.  
  261.  
  262. function ENT:TeleportBehindVictim()
  263.     self:SetModel( "models/The_Sniper_9/DoctorWho/Extras/Angels/angelpoint.mdl" )
  264.     if CurTime() < self.NextTeleport then return end
  265.    
  266.     local plraim = self.Victim:GetAimVector()
  267.     plraim.z = 0
  268.     plraim:Normalize()
  269.    
  270.    
  271.     local plrpos = self.Victim:GetShootPos()
  272.     local tr = util.TraceLine(
  273.         {
  274.             start     = plrpos - plraim * TELEPORT_MIN_DIST_FROM_PLR,
  275.         endpos     = plrpos - plraim * TELEPORT_MAX_DIST_FROM_PLR,
  276.             filter     = { self, self.Kinfe, self.Victim },
  277.             mask     = MASK_NPCSOLID
  278.         } )
  279.    
  280.    
  281.     self:TeleportToPos( tr.HitPos + tr.HitNormal * self.Width )
  282.    
  283.     self.NextTeleport = CurTime() + TELEPORT_COOLDOWN
  284.    
  285. end
  286.  
  287.  
  288. function ENT:CreepForward( disp )
  289.    
  290.     if CurTime() < self.NextCreep then return end
  291.    
  292.     self:TeleportToPos( self:GetPos() + disp * CREEP_DISTANCE_FRACTION )
  293.    
  294.     self.NextCreep = CurTime() + CREEP_COOLDOWN
  295.    
  296. end
  297.  
  298.  
  299. function ENT:EmitCreepySounds()
  300.    
  301.     if CurTime() < self.NextEmit then return end
  302.    
  303.     local tSnd = CREEPY_SOUNDS[ math.random( 1, #CREEPY_SOUNDS ) ]
  304.    
  305.     self:EmitSound( tSnd.Snd, 500, 100 )
  306.     self.CurSound = tSnd.Snd
  307.    
  308.     self.NextEmit = CurTime() + EMITSOUND_COOLDOWN + tSnd.Dur
  309.    
  310. end
  311.  
  312.  
  313. function ENT:StabbyLunge( vec )
  314.    
  315.     if CurTime() < self.NextStab then return end
  316.    
  317.     local phys = self:GetPhysicsObject()
  318.     local stabvec = vec * STAB_FORCE + Vector( 0, 0, 0.4 * STAB_FORCE )
  319.     phys:ApplyForceCenter( stabvec )
  320.    
  321.     local vicpos = self.Victim:GetShootPos()
  322.    
  323.    
  324.     self.Victim:TakeDamage( STAB_DAMAGE, self, self.Knife )
  325.    
  326.     self:EmitSound( sndStab, 500, 100 )
  327.    
  328.     self.NextStab = CurTime() + STAB_COOLDOWN
  329.  
  330. end
  331.  
  332.  
  333. function ENT:KillSounds()
  334.  
  335.     self:StopSound( self.CurSound )
  336.  
  337. end
  338.  
  339.  
  340. function ENT:FaceVictim()
  341.    
  342.     local x = self:GetPos().x - self.Victim:GetPos().x
  343.     local y = self:GetPos().y - self.Victim:GetPos().y
  344.     local fullAng = (90/(math.abs(x)+math.abs(y)))*x
  345.     if y > 0 then
  346.         fullAng = -(fullAng) -180
  347.     end  
  348.    
  349.     self:SetAngles(Angle(0,fullAng+90,0) )
  350.    
  351. end
  352.  
  353. function ENT:PlayDead()
  354.  
  355.     if not self.IsBeingCreepy then return end
  356.    
  357.     -- Be on ground!
  358.     self:DropToFloor()
  359.  
  360.     -- Face the victim!
  361.     self:FaceVictim()
  362.    
  363.     -- Act normal!
  364.     self.IsBeingCreepy = false
  365.  
  366.     -- Be quiet!
  367.     self:KillSounds()
  368.        
  369.     -- Hide your knife!
  370.     if self.Knife:IsValid() then self.Knife:Remove() end
  371.    
  372.     -- Reset everything since we stopped doing them
  373.     self.NextTeleport = 0
  374.     self.NextCreep = 0
  375.     self.NextEmit = 0
  376.     self.NextStab = 0
  377.  
  378. end
  379.  
  380.  
  381. function ENT:BeCreepy()
  382.  
  383.     self.IsBeingCreepy = true
  384.  
  385.     -- Oh no, I already calculated these this frame.  I guess that makes my code innefficient.  Woe is me.
  386.     local Disp = self.Victim:GetShootPos() - self:GetPos()
  387.     local Dist = Disp:Length()
  388.     local Vec = Disp:GetNormalized()
  389.    
  390.     -- Randomly decide what creepy things we should do
  391.     local randnum = math.random()
  392.    
  393.     if Dist > TELEPORT_MAX_DIST or not self:HasVictimLOS() then -- We're too far away or we don't have line of sight. Teleport behind our victim.
  394.        
  395.         if TELEPORT_PROB > randnum then
  396.            
  397.             self:TeleportBehindVictim()
  398.            
  399.         end
  400.        
  401.     elseif Dist > EMITSOUND_MAX_DIST then -- We're too far away.  Start creeping towards our victim...
  402.        
  403.         if CREEP_PROB > randnum then
  404.            
  405.             self:CreepForward( Disp )
  406.            
  407.         end
  408.        
  409.     elseif Dist > STAB_MAX_DIST then -- Creep the fuck out of them now.
  410.        
  411.         if CREEP_PROB > randnum then
  412.            
  413.             self:CreepForward( Disp )
  414.            
  415.         elseif CREEP_PROB + EMITSOUND_PROB > randnum then
  416.            
  417.             self:EmitCreepySounds()
  418.            
  419.         end
  420.        
  421.     else -- We're close enough to attack! mwahahahaha!
  422.        
  423.         if not self.Knife:IsValid() then
  424.             self:DrawKnife( Vec )
  425.         end
  426.        
  427.         if EMITSOUND_PROB > randnum then
  428.            
  429.             self:EmitCreepySounds()
  430.            
  431.         elseif EMITSOUND_PROB + STAB_PROB > randnum then
  432.            
  433.             self:StabbyLunge( Vec )
  434.            
  435.         end
  436.        
  437.     end
  438.    
  439.       self:DropToFloor()
  440.     self:FaceVictim()
  441.  
  442. end
  443.  
  444.  
  445. function ENT:Think()
  446.  
  447.     if not ValidEntity( self.Victim ) or not self.Victim:Alive() then return end
  448.  
  449.     -- OHSHI.. he sees us!
  450.     if self:CanVictimSeeUs() then
  451.        
  452.         -- Pretend like nothing happened
  453.         self:PlayDead()
  454.         self:NextThink( CurTime() + COOLDOWN_TIME )
  455.        
  456.     else
  457.        
  458.         self:BeCreepy()
  459.         self:NextThink( CurTime() + THINK_DELAY )
  460.        
  461.     end
  462.    
  463.     return true
  464.    
  465. end
  466.  
  467.  
  468. function ENT:OnRemove()
  469.    
  470.     self:KillSounds()
  471.        
  472. end
  473.  
  474. function ENT:Draw()
  475.    
  476.     self:DrawModel()
  477.    
  478.    
  479.    
  480. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement