Залив
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 17 MiB |
@@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Returns the right shoot start position for a tracer - based on 'data'.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function EFFECT:GetTracerShootPos( Position, Ent, Attachment )
|
||||||
|
|
||||||
|
self.ViewModelTracer = false
|
||||||
|
|
||||||
|
if ( !IsValid( Ent ) ) then return Position end
|
||||||
|
if ( !Ent:IsWeapon() ) then return Position end
|
||||||
|
|
||||||
|
-- Shoot from the viewmodel
|
||||||
|
if ( Ent:IsCarriedByLocalPlayer() && !LocalPlayer():ShouldDrawLocalPlayer() ) then
|
||||||
|
|
||||||
|
local ViewModel = LocalPlayer():GetViewModel()
|
||||||
|
|
||||||
|
if ( ViewModel:IsValid() ) then
|
||||||
|
|
||||||
|
local att = ViewModel:GetAttachment( Attachment )
|
||||||
|
if ( att ) then
|
||||||
|
Position = att.Pos
|
||||||
|
self.ViewModelTracer = true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Shoot from the world model
|
||||||
|
else
|
||||||
|
|
||||||
|
local att = Ent:GetAttachment( Attachment )
|
||||||
|
if ( att ) then
|
||||||
|
Position = att.Pos
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return Position
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
EFFECT.Mat = Material( "pp/dof" )
|
||||||
|
|
||||||
|
function EFFECT:Init( data )
|
||||||
|
|
||||||
|
table.insert( DOF_Ents, self.Entity )
|
||||||
|
self.Scale = data:GetScale()
|
||||||
|
|
||||||
|
local size = 32
|
||||||
|
self:SetCollisionBounds( Vector( -size, -size, -size ), Vector( size, size, size ) )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function EFFECT:Think( )
|
||||||
|
|
||||||
|
-- If the spacing or offset has changed we need to reconfigure our positions
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
|
||||||
|
self.spacing = DOF_SPACING * self.Scale
|
||||||
|
self.offset = DOF_OFFSET
|
||||||
|
|
||||||
|
-- Just return if it hasn't
|
||||||
|
--if ( spacing == self.spacing && offset == self.offset ) then return true end
|
||||||
|
|
||||||
|
local pos = ply:EyePos()
|
||||||
|
local fwd = ply:EyeAngles():Forward()
|
||||||
|
|
||||||
|
if ( ply:GetViewEntity() != ply ) then
|
||||||
|
pos = ply:GetViewEntity():GetPos()
|
||||||
|
fwd = ply:GetViewEntity():GetForward()
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = pos + ( fwd * self.spacing ) + ( fwd * self.offset )
|
||||||
|
|
||||||
|
self:SetParent( nil )
|
||||||
|
self:SetPos( pos )
|
||||||
|
self:SetParent( ply )
|
||||||
|
|
||||||
|
-- We don't kill this, the pp effect should
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function EFFECT:Render()
|
||||||
|
|
||||||
|
-- Note: UpdateScreenEffectTexture fucks up the water, RefractTexture is lower quality
|
||||||
|
render.UpdateRefractTexture()
|
||||||
|
//render.UpdateScreenEffectTexture()
|
||||||
|
|
||||||
|
local SpriteSize = ( self.spacing + self.offset ) * 8
|
||||||
|
|
||||||
|
render.SetMaterial( self.Mat )
|
||||||
|
render.DrawSprite( self:GetPos(), SpriteSize, SpriteSize, color_white )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
EFFECT.Mat = Material( "effects/tool_tracer" )
|
||||||
|
|
||||||
|
function EFFECT:Init( data )
|
||||||
|
|
||||||
|
self.Position = data:GetStart()
|
||||||
|
self.WeaponEnt = data:GetEntity()
|
||||||
|
self.Attachment = data:GetAttachment()
|
||||||
|
|
||||||
|
-- Keep the start and end pos - we're going to interpolate between them
|
||||||
|
self.StartPos = self:GetTracerShootPos( self.Position, self.WeaponEnt, self.Attachment )
|
||||||
|
self.EndPos = data:GetOrigin()
|
||||||
|
|
||||||
|
self.Alpha = 255
|
||||||
|
self.Life = 0
|
||||||
|
|
||||||
|
self:SetRenderBoundsWS( self.StartPos, self.EndPos )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function EFFECT:Think()
|
||||||
|
|
||||||
|
self.Life = self.Life + FrameTime() * 4
|
||||||
|
self.Alpha = 255 * ( 1 - self.Life )
|
||||||
|
|
||||||
|
return ( self.Life < 1 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function EFFECT:Render()
|
||||||
|
|
||||||
|
if ( self.Alpha < 1 ) then return end
|
||||||
|
|
||||||
|
render.SetMaterial( self.Mat )
|
||||||
|
local texcoord = math.Rand( 0, 1 )
|
||||||
|
|
||||||
|
local norm = (self.StartPos - self.EndPos) * self.Life
|
||||||
|
|
||||||
|
self.Length = norm:Length()
|
||||||
|
|
||||||
|
for i = 1, 3 do
|
||||||
|
|
||||||
|
render.DrawBeam( self.StartPos - norm, -- Start
|
||||||
|
self.EndPos, -- End
|
||||||
|
8, -- Width
|
||||||
|
texcoord, -- Start tex coord
|
||||||
|
texcoord + self.Length / 128, -- End tex coord
|
||||||
|
color_white ) -- Color (optional)
|
||||||
|
end
|
||||||
|
|
||||||
|
render.DrawBeam( self.StartPos,
|
||||||
|
self.EndPos,
|
||||||
|
8,
|
||||||
|
texcoord,
|
||||||
|
texcoord + ( ( self.StartPos - self.EndPos ):Length() / 128 ),
|
||||||
|
Color( 255, 255, 255, 128 * ( 1 - self.Life ) ) )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
include( "shared.lua" )
|
||||||
|
|
||||||
|
ENT.RenderGroup = RENDERGROUP_OPAQUE
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Draw
|
||||||
|
Desc: Draw it!
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Draw()
|
||||||
|
self:DrawModel()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DrawTranslucent
|
||||||
|
Desc: Draw translucent
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:DrawTranslucent()
|
||||||
|
|
||||||
|
-- This is here just to make it backwards compatible.
|
||||||
|
-- You shouldn't really be drawing your model here unless it's translucent
|
||||||
|
|
||||||
|
self:Draw()
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile( "cl_init.lua" )
|
||||||
|
AddCSLuaFile( "shared.lua" )
|
||||||
|
|
||||||
|
include( "shared.lua" )
|
||||||
|
include( "schedules.lua" )
|
||||||
|
include( "tasks.lua" )
|
||||||
|
|
||||||
|
-- Variables
|
||||||
|
|
||||||
|
ENT.m_fMaxYawSpeed = 200 -- Max turning speed
|
||||||
|
ENT.m_iClass = CLASS_CITIZEN_REBEL -- NPC Class
|
||||||
|
|
||||||
|
AccessorFunc( ENT, "m_iClass", "NPCClass" )
|
||||||
|
AccessorFunc( ENT, "m_fMaxYawSpeed", "MaxYawSpeed" )
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
-- Some default calls to make the NPC function
|
||||||
|
self:SetModel( "models/alyx.mdl" )
|
||||||
|
self:SetHullType( HULL_HUMAN )
|
||||||
|
self:SetHullSizeNormal()
|
||||||
|
self:SetSolid( SOLID_BBOX )
|
||||||
|
self:SetMoveType( MOVETYPE_STEP )
|
||||||
|
self:CapabilitiesAdd( bit.bor( CAP_MOVE_GROUND, CAP_OPEN_DOORS, CAP_ANIMATEDFACE, CAP_SQUAD, CAP_USE_WEAPONS, CAP_DUCK, CAP_MOVE_SHOOT, CAP_TURN_HEAD, CAP_USE_SHOT_REGULATOR, CAP_AIM_GUN ) )
|
||||||
|
|
||||||
|
self:SetHealth( 100 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnTakeDamage
|
||||||
|
Desc: Called when the NPC takes damage
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnTakeDamage( dmginfo )
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Msg( tostring(dmginfo) .. "\n" )
|
||||||
|
Msg( "Inflictor:\t" .. tostring(dmginfo:GetInflictor()) .. "\n" )
|
||||||
|
Msg( "Attacker:\t" .. tostring(dmginfo:GetAttacker()) .. "\n" )
|
||||||
|
Msg( "Damage:\t" .. tostring(dmginfo:GetDamage()) .. "\n" )
|
||||||
|
Msg( "Base Damage:\t" .. tostring(dmginfo:GetBaseDamage()) .. "\n" )
|
||||||
|
Msg( "Force:\t" .. tostring(dmginfo:GetDamageForce()) .. "\n" )
|
||||||
|
Msg( "Position:\t" .. tostring(dmginfo:GetDamagePosition()) .. "\n" )
|
||||||
|
Msg( "Reported Pos:\t" .. tostring(dmginfo:GetReportedPosition()) .. "\n" ) -- ??
|
||||||
|
--]]
|
||||||
|
|
||||||
|
-- return 1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Use
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Use( activator, caller, type, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: StartTouch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: EndTouch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:EndTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Touch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Touch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: GetRelationship
|
||||||
|
Return the relationship between this NPC and the
|
||||||
|
passed entity. If you don't return anything then
|
||||||
|
the default disposition will be used.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:GetRelationship( entity )
|
||||||
|
|
||||||
|
--return D_NU;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: ExpressionFinished
|
||||||
|
Called when an expression has finished. Duh.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:ExpressionFinished( strExp )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnChangeActivity
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnChangeActivity( act )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when NPC's movement fails
|
||||||
|
function ENT:OnMovementFailed()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when NPC's movement succeeds
|
||||||
|
function ENT:OnMovementComplete()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when the NPC's active weapon changes
|
||||||
|
function ENT:OnActiveWeaponChanged( old, new )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: GetAttackSpread
|
||||||
|
How good is the NPC with this weapon? Return the number
|
||||||
|
of degrees of inaccuracy for the NPC to use.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:GetAttackSpread( Weapon, Target )
|
||||||
|
return 0.1
|
||||||
|
end
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: RunAI - Called from the engine every 0.1 seconds
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:RunAI( strExp )
|
||||||
|
|
||||||
|
-- If we're running an Engine Side behaviour
|
||||||
|
-- then return true and let it get on with it.
|
||||||
|
if ( self:IsRunningBehavior() ) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're doing an engine schedule then return true
|
||||||
|
-- This makes it do the normal AI stuff.
|
||||||
|
if ( self:DoingEngineSchedule() ) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're currently running a schedule then run it.
|
||||||
|
if ( self.CurrentSchedule ) then
|
||||||
|
self:DoSchedule( self.CurrentSchedule )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we have no schedule (schedule is finished etc)
|
||||||
|
-- Then get the derived NPC to select what we should be doing
|
||||||
|
if ( !self.CurrentSchedule ) then
|
||||||
|
self:SelectSchedule()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Do animation system
|
||||||
|
self:MaintainActivity()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SelectSchedule - Set the schedule we should be
|
||||||
|
playing right now.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:SelectSchedule( iNPCState )
|
||||||
|
|
||||||
|
self:SetSchedule( SCHED_IDLE_WANDER )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: StartSchedule - Start a Lua schedule. Not to be
|
||||||
|
confused with SetSchedule which starts an Engine based
|
||||||
|
schedule.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartSchedule( schedule )
|
||||||
|
|
||||||
|
self.CurrentSchedule = schedule
|
||||||
|
self.CurrentTaskID = 1
|
||||||
|
self:SetTask( schedule:GetTask( 1 ) )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DoSchedule - Runs a Lua schedule.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:DoSchedule( schedule )
|
||||||
|
|
||||||
|
if ( self.CurrentTask ) then
|
||||||
|
self:RunTask( self.CurrentTask )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( self:TaskFinished() ) then
|
||||||
|
self:NextTask( schedule )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: ScheduleFinished
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:ScheduleFinished()
|
||||||
|
|
||||||
|
self.CurrentSchedule = nil
|
||||||
|
self.CurrentTask = nil
|
||||||
|
self.CurrentTaskID = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DoSchedule - Set the current task.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:SetTask( task )
|
||||||
|
|
||||||
|
self.CurrentTask = task
|
||||||
|
self.bTaskComplete = false
|
||||||
|
self.TaskStartTime = CurTime()
|
||||||
|
|
||||||
|
self:StartTask( self.CurrentTask )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: NextTask - Start the next task in specific schedule.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:NextTask( schedule )
|
||||||
|
|
||||||
|
-- Increment task id
|
||||||
|
self.CurrentTaskID = self.CurrentTaskID + 1
|
||||||
|
|
||||||
|
-- If this was the last task then finish up.
|
||||||
|
if ( self.CurrentTaskID > schedule:NumTasks() ) then
|
||||||
|
|
||||||
|
self:ScheduleFinished( schedule )
|
||||||
|
return
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Switch to next task
|
||||||
|
self:SetTask( schedule:GetTask( self.CurrentTaskID ) )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: StartTask - called once on starting task
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartTask( task )
|
||||||
|
task:Start( self.Entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: RunTask - called every think on running task.
|
||||||
|
The actual task function should tell us when
|
||||||
|
the task is finished.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:RunTask( task )
|
||||||
|
task:Run( self.Entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: TaskTime - Returns how many seconds we've been
|
||||||
|
doing this current task
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:TaskTime()
|
||||||
|
return CurTime() - self.TaskStartTime
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnTaskComplete - Called from the engine when
|
||||||
|
TaskComplete is called. This allows us to move
|
||||||
|
onto the next task - even when TaskComplete was
|
||||||
|
called from an engine side task.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnTaskComplete()
|
||||||
|
|
||||||
|
self.bTaskComplete = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: TaskFinished - Returns true if the current
|
||||||
|
running Task is finished.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:TaskFinished()
|
||||||
|
return self.bTaskComplete
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: StartTask
|
||||||
|
Start the task. You can use this to override engine
|
||||||
|
side tasks. Return true to not run default stuff.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartEngineTask( iTaskID, TaskData )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: RunTask
|
||||||
|
Run the task. You can use this to override engine
|
||||||
|
side tasks. Return true to not run default stuff.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:RunEngineTask( iTaskID, TaskData )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
These functions handle the engine schedules
|
||||||
|
When an engine schedule is set the engine calls StartEngineSchedule
|
||||||
|
Then when it's finished it calls EngineScheduleFinishHelp me decide
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartEngineSchedule( scheduleID ) self:ScheduleFinished() self.bDoingEngineSchedule = true end
|
||||||
|
function ENT:EngineScheduleFinish() self.bDoingEngineSchedule = nil end
|
||||||
|
function ENT:DoingEngineSchedule() return self.bDoingEngineSchedule end
|
||||||
|
|
||||||
|
function ENT:OnCondition( iCondition )
|
||||||
|
|
||||||
|
--Msg( self, " Condition: ", iCondition, " - ", self:ConditionName(iCondition), "\n" )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "ai"
|
||||||
|
|
||||||
|
ENT.PrintName = "Base SNPC"
|
||||||
|
ENT.Author = ""
|
||||||
|
ENT.Contact = ""
|
||||||
|
ENT.Purpose = ""
|
||||||
|
ENT.Instructions = ""
|
||||||
|
|
||||||
|
ENT.AutomaticFrameAdvance = false
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRemove
|
||||||
|
Desc: Called just before entity is deleted
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnRemove()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: PhysicsCollide
|
||||||
|
Desc: Called when physics collides. The table contains
|
||||||
|
data on the collision
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PhysicsCollide( data, physobj )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: PhysicsUpdate
|
||||||
|
Desc: Called to update the physics .. or something.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PhysicsUpdate( physobj )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SetAutomaticFrameAdvance
|
||||||
|
Desc: If you're not using animation you should turn this
|
||||||
|
off - it will save lots of bandwidth.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:SetAutomaticFrameAdvance( bUsingAnim )
|
||||||
|
|
||||||
|
self.AutomaticFrameAdvance = bUsingAnim
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Task: PlaySequence
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
|
||||||
|
data.ID - sequence id
|
||||||
|
data.Name - sequence name (Must provide either id or name)
|
||||||
|
data.Wait - Optional. Should we wait for sequence to finish
|
||||||
|
data.Speed - Optional. Playback speed of sequence
|
||||||
|
data.Loop - Optional. Should the sequence be looped
|
||||||
|
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:TaskStart_PlaySequence( data )
|
||||||
|
|
||||||
|
local SequenceID = data.ID
|
||||||
|
|
||||||
|
if ( data.Name ) then SequenceID = self:LookupSequence( data.Name ) end
|
||||||
|
|
||||||
|
self:ResetSequence( SequenceID )
|
||||||
|
self:SetNPCState( NPC_STATE_SCRIPT )
|
||||||
|
|
||||||
|
local Duration = self:SequenceDuration()
|
||||||
|
|
||||||
|
if ( data.Speed && data.Speed > 0 ) then
|
||||||
|
|
||||||
|
SequenceID = self:SetPlaybackRate( data.Speed )
|
||||||
|
Duration = Duration / data.Speed
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self.TaskSequenceEnd = CurTime() + Duration
|
||||||
|
self.Loop = data.Loop or false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Task_PlaySequence( data )
|
||||||
|
|
||||||
|
-- Wait until sequence is finished
|
||||||
|
if ( CurTime() < self.TaskSequenceEnd or self.Loop ) then return end
|
||||||
|
|
||||||
|
self:TaskComplete()
|
||||||
|
self:SetNPCState( NPC_STATE_NONE )
|
||||||
|
|
||||||
|
-- Clean up
|
||||||
|
self.TaskSequenceEnd = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Task: FindEnemy
|
||||||
|
|
||||||
|
Accepts:
|
||||||
|
|
||||||
|
data.ID - sequence id
|
||||||
|
data.Name - sequence name (Must provide either id or name)
|
||||||
|
data.Wait - Optional. Should we wait for sequence to finish
|
||||||
|
data.Speed - Optional. Playback speed of sequence
|
||||||
|
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:TaskStart_FindEnemy( data )
|
||||||
|
|
||||||
|
local et = ents.FindInSphere( self:GetPos(), data.Radius or 512 )
|
||||||
|
for k, v in ipairs( et ) do
|
||||||
|
|
||||||
|
if ( v:IsValid() && v != self && v:GetClass() == data.Class ) then
|
||||||
|
|
||||||
|
self:SetEnemy( v, true )
|
||||||
|
self:UpdateEnemyMemory( v, v:GetPos() )
|
||||||
|
self:TaskComplete()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetEnemy( NULL )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Task_FindEnemy( data )
|
||||||
|
end
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
|
||||||
|
ENT.PrintName = ""
|
||||||
|
ENT.Author = ""
|
||||||
|
ENT.Contact = ""
|
||||||
|
ENT.Purpose = ""
|
||||||
|
ENT.Instructions = ""
|
||||||
|
|
||||||
|
-- Defaulting this to OFF. This will automatically save bandwidth
|
||||||
|
-- on stuff that is already out there, but might break a few things
|
||||||
|
-- that are out there. I'm choosing to break those things because
|
||||||
|
-- there are a lot less of them that are actually using the animtime
|
||||||
|
|
||||||
|
ENT.AutomaticFrameAdvance = false
|
||||||
|
|
||||||
|
function ENT:SetAutomaticFrameAdvance( bUsingAnim )
|
||||||
|
self.AutomaticFrameAdvance = bUsingAnim
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:OnRemove()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:PhysicsCollide( data, physobj )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:PhysicsUpdate( physobj )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
|
||||||
|
function ENT:Draw( flags )
|
||||||
|
|
||||||
|
self:DrawModel( flags )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:DrawTranslucent( flags )
|
||||||
|
|
||||||
|
-- This is here just to make it backwards compatible.
|
||||||
|
-- You shouldn't really be drawing your model here unless it's translucent
|
||||||
|
|
||||||
|
self:Draw( flags )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
function ENT:OnTakeDamage( dmginfo )
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Msg( tostring(dmginfo) .. "\n" )
|
||||||
|
Msg( "Inflictor:\t" .. tostring(dmginfo:GetInflictor()) .. "\n" )
|
||||||
|
Msg( "Attacker:\t" .. tostring(dmginfo:GetAttacker()) .. "\n" )
|
||||||
|
Msg( "Damage:\t" .. tostring(dmginfo:GetDamage()) .. "\n" )
|
||||||
|
Msg( "Base Damage:\t" .. tostring(dmginfo:GetBaseDamage()) .. "\n" )
|
||||||
|
Msg( "Force:\t" .. tostring(dmginfo:GetDamageForce()) .. "\n" )
|
||||||
|
Msg( "Position:\t" .. tostring(dmginfo:GetDamagePosition()) .. "\n" )
|
||||||
|
Msg( "Reported Pos:\t" .. tostring(dmginfo:GetReportedPosition()) .. "\n" ) -- ??
|
||||||
|
--]]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:Use( activator, caller, type, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:StartTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:EndTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:Touch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Simulate
|
||||||
|
Desc: Controls/simulates the physics on the entity.
|
||||||
|
Officially the most complicated callback in the whole mod.
|
||||||
|
Returns 3 variables..
|
||||||
|
1. A SIM_ enum
|
||||||
|
2. A vector representing the linear acceleration/force
|
||||||
|
3. A vector represending the angular acceleration/force
|
||||||
|
If you're doing nothing you can return SIM_NOTHING
|
||||||
|
Note that you need to call ent:StartMotionController to tell the entity
|
||||||
|
to start calling this function..
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PhysicsSimulate( phys, deltatime )
|
||||||
|
return SIM_NOTHING
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "brush"
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Initialize
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: StartTouch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:StartTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: EndTouch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:EndTouch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Touch
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Touch( entity )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: PassesTriggerFilters
|
||||||
|
Desc: Return true if this object should trigger us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PassesTriggerFilters( entity )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: KeyValue
|
||||||
|
Desc: Called when a keyvalue is added to us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
Desc: Entity's think function.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRemove
|
||||||
|
Desc: Called just before entity is deleted
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnRemove()
|
||||||
|
end
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
include( "shared.lua" )
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Initialize
|
||||||
|
Desc: First function called. Use to set up your entity
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
Desc: Client Think - called every frame
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRestore
|
||||||
|
Desc: Called immediately after a "load"
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnRestore()
|
||||||
|
end
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile( "cl_init.lua" )
|
||||||
|
AddCSLuaFile( "shared.lua" )
|
||||||
|
|
||||||
|
include( "shared.lua" )
|
||||||
|
include( "outputs.lua" )
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Initialize
|
||||||
|
Desc: First function called. Use to set up your entity
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: KeyValue
|
||||||
|
Desc: Called when a keyvalue is added to us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRestore
|
||||||
|
Desc: The game has just been reloaded. This is usually the right place
|
||||||
|
to call the GetNW* functions to restore the script's values.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnRestore()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: AcceptInput
|
||||||
|
Desc: Accepts input, return true to override/accept input
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:AcceptInput( name, activator, caller, data )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: UpdateTransmitState
|
||||||
|
Desc: Set the transmit state
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:UpdateTransmitState()
|
||||||
|
return TRANSMIT_PVS
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
Desc: Entity's think function.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Default generic spawn function
|
||||||
|
-- So you don't have to add one your entitie unless you want to.
|
||||||
|
--
|
||||||
|
function ENT:SpawnFunction( ply, tr, ClassName )
|
||||||
|
|
||||||
|
if ( !tr.Hit ) then return end
|
||||||
|
|
||||||
|
local SpawnPos = tr.HitPos + tr.HitNormal * 10
|
||||||
|
local SpawnAng = ply:EyeAngles()
|
||||||
|
SpawnAng.p = 0
|
||||||
|
SpawnAng.y = SpawnAng.y + 180
|
||||||
|
|
||||||
|
local ent = ents.Create( ClassName )
|
||||||
|
ent:SetCreator( ply )
|
||||||
|
ent:SetPos( SpawnPos )
|
||||||
|
ent:SetAngles( SpawnAng )
|
||||||
|
ent:Spawn()
|
||||||
|
ent:Activate()
|
||||||
|
|
||||||
|
ent:DropToFloor()
|
||||||
|
|
||||||
|
return ent
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
|
||||||
|
-- This is called from ENT:KeyValue(key,value) to store the output from
|
||||||
|
-- the map, it could also be called from ENT:AcceptInput I think, so if
|
||||||
|
-- ent_fire addoutput is used, we can store that too (that hasn't been
|
||||||
|
-- tested though).
|
||||||
|
-- Usage: self:StoreOutput("<name of output>","<entities to fire>,<input name>,<param>,<delay>,<times to be used>")
|
||||||
|
-- If called from ENT:KeyValue, then the first parameter is the key, and
|
||||||
|
-- the second is value.
|
||||||
|
function ENT:StoreOutput( name, info )
|
||||||
|
|
||||||
|
-- Newer Source Engine games use this symbol as a delimiter
|
||||||
|
local rawData = string.Explode( "\x1B", info )
|
||||||
|
if ( #rawData < 2 ) then
|
||||||
|
rawData = string.Explode( ",", info )
|
||||||
|
end
|
||||||
|
|
||||||
|
local Output = {}
|
||||||
|
Output.entities = rawData[1] or ""
|
||||||
|
Output.input = rawData[2] or ""
|
||||||
|
Output.param = rawData[3] or ""
|
||||||
|
Output.delay = tonumber( rawData[4] ) or 0
|
||||||
|
Output.times = tonumber( rawData[5] ) or -1
|
||||||
|
|
||||||
|
self.m_tOutputs = self.m_tOutputs or {}
|
||||||
|
self.m_tOutputs[ name ] = self.m_tOutputs[ name ] or {}
|
||||||
|
|
||||||
|
table.insert( self.m_tOutputs[ name ], Output )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Nice helper function, this does all the work. Returns false if the
|
||||||
|
-- output should be removed from the list.
|
||||||
|
local function FireSingleOutput( output, this, activator, data )
|
||||||
|
|
||||||
|
if ( output.times == 0 ) then return false end
|
||||||
|
|
||||||
|
local entitiesToFire = {}
|
||||||
|
|
||||||
|
if ( output.entities == "!activator" ) then
|
||||||
|
entitiesToFire = { activator }
|
||||||
|
elseif ( output.entities == "!self" ) then
|
||||||
|
entitiesToFire = { this }
|
||||||
|
elseif ( output.entities == "!player" ) then
|
||||||
|
entitiesToFire = player.GetAll()
|
||||||
|
else
|
||||||
|
entitiesToFire = ents.FindByName( output.entities )
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, ent in pairs( entitiesToFire ) do
|
||||||
|
ent:Fire( output.input, data or output.param, output.delay, activator, this )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( output.times ~= -1 ) then
|
||||||
|
output.times = output.times - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return ( output.times > 0 ) || ( output.times == -1 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This function is used to trigger an output.
|
||||||
|
function ENT:TriggerOutput( name, activator, data )
|
||||||
|
|
||||||
|
if ( !self.m_tOutputs ) then return end
|
||||||
|
if ( !self.m_tOutputs[ name ] ) then return end
|
||||||
|
|
||||||
|
local OutputList = self.m_tOutputs[ name ]
|
||||||
|
|
||||||
|
for idx = #OutputList, 1, -1 do
|
||||||
|
|
||||||
|
if ( OutputList[ idx ] and !FireSingleOutput( OutputList[ idx ], self.Entity, activator, data ) ) then
|
||||||
|
|
||||||
|
-- Shift the indexes so this loop doesn't fail later
|
||||||
|
table.remove( self.m_tOutputs[ name ], idx )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
|
||||||
|
ENT.Spawnable = false
|
||||||
|
ENT.AdminOnly = false
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "filter"
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Initialize
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: KeyValue
|
||||||
|
Desc: Called when a keyvalue is added to us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
Desc: Entity's think function.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRemove
|
||||||
|
Desc: Called just before entity is deleted
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:OnRemove()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: PassesFilter
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PassesFilter( trigger, ent )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: PassesDamageFilter
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:PassesDamageFilter( dmg )
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
DEFINE_BASECLASS( "base_anim" )
|
||||||
|
|
||||||
|
ENT.Spawnable = false
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
ENT.MaxWorldTipDistance = 256
|
||||||
|
|
||||||
|
function ENT:BeingLookedAtByLocalPlayer()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
if ( !IsValid( ply ) ) then return false end
|
||||||
|
|
||||||
|
local view = ply:GetViewEntity()
|
||||||
|
local dist = self.MaxWorldTipDistance
|
||||||
|
dist = dist * dist
|
||||||
|
|
||||||
|
-- If we're spectating a player, perform an eye trace
|
||||||
|
if ( view:IsPlayer() ) then
|
||||||
|
return view:EyePos():DistToSqr( self:GetPos() ) <= dist && view:GetEyeTrace().Entity == self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're not spectating a player, perform a manual trace from the entity's position
|
||||||
|
local pos = view:GetPos()
|
||||||
|
|
||||||
|
if ( pos:DistToSqr( self:GetPos() ) <= dist ) then
|
||||||
|
return util.TraceLine( {
|
||||||
|
start = pos,
|
||||||
|
endpos = pos + ( view:GetAngles():Forward() * dist ),
|
||||||
|
filter = view
|
||||||
|
} ).Entity == self
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local text = self:GetOverlayText()
|
||||||
|
|
||||||
|
if ( text != "" && self:BeingLookedAtByLocalPlayer() && !self:GetNoDraw() ) then
|
||||||
|
AddWorldTip( self:EntIndex(), text, 0.5, self:GetPos(), self )
|
||||||
|
|
||||||
|
halo.Add( { self }, color_white, 1, 1, 1, true, true )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:SetOverlayText( text )
|
||||||
|
self:SetNWString( "GModOverlayText", text )
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetOverlayText()
|
||||||
|
|
||||||
|
local txt = self:GetNWString( "GModOverlayText" )
|
||||||
|
|
||||||
|
if ( txt == "" ) then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( game.SinglePlayer() ) then
|
||||||
|
return txt
|
||||||
|
end
|
||||||
|
|
||||||
|
local PlayerName = self:GetPlayerName()
|
||||||
|
|
||||||
|
return txt .. "\n(" .. PlayerName .. ")"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:SetPlayer( ply )
|
||||||
|
|
||||||
|
self.Founder = ply
|
||||||
|
|
||||||
|
if ( IsValid( ply ) ) then
|
||||||
|
|
||||||
|
self:SetNWString( "FounderName", ply:Nick() )
|
||||||
|
self.FounderSID = ply:SteamID64()
|
||||||
|
self.FounderIndex = ply:UniqueID()
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
self:SetNWString( "FounderName", "" )
|
||||||
|
self.FounderSID = nil
|
||||||
|
self.FounderIndex = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayer()
|
||||||
|
|
||||||
|
if ( self.Founder == nil ) then
|
||||||
|
|
||||||
|
-- SetPlayer has not been called
|
||||||
|
return NULL
|
||||||
|
|
||||||
|
elseif ( IsValid( self.Founder ) ) then
|
||||||
|
|
||||||
|
-- Normal operations
|
||||||
|
return self.Founder
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- See if the player has left the server then rejoined
|
||||||
|
local ply = player.GetBySteamID64( self.FounderSID )
|
||||||
|
if ( not IsValid( ply ) ) then
|
||||||
|
|
||||||
|
-- Oh well
|
||||||
|
return NULL
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Save us the check next time
|
||||||
|
self:SetPlayer( ply )
|
||||||
|
return ply
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayerIndex()
|
||||||
|
|
||||||
|
return self.FounderIndex or 0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayerSteamID()
|
||||||
|
|
||||||
|
return self.FounderSID or ""
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayerName()
|
||||||
|
|
||||||
|
local ply = self:GetPlayer()
|
||||||
|
if ( IsValid( ply ) ) then
|
||||||
|
return ply:Nick()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self:GetNWString( "FounderName" )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.PrintName = ""
|
||||||
|
ENT.Author = ""
|
||||||
|
ENT.Contact = ""
|
||||||
|
ENT.Purpose = ""
|
||||||
|
ENT.Instructions = ""
|
||||||
|
ENT.RenderGroup = RENDERGROUP_OPAQUE
|
||||||
|
|
||||||
|
ENT.Type = "nextbot"
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
--
|
||||||
|
-- All of the AI logic is serverside - so we derive it from a
|
||||||
|
-- specialized class on the server.
|
||||||
|
--
|
||||||
|
include( "sv_nextbot.lua" )
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Draw
|
||||||
|
Desc: Draw it!
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Draw()
|
||||||
|
self:DrawModel()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DrawTranslucent
|
||||||
|
Desc: Draw translucent
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:DrawTranslucent()
|
||||||
|
|
||||||
|
-- This is here just to make it backwards compatible.
|
||||||
|
-- You shouldn't really be drawing your model here unless it's translucent
|
||||||
|
|
||||||
|
self:Draw()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: FireAnimationEvent
|
||||||
|
Desc: Called when an animation event is fired. Return true to suppress
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:FireAnimationEvent( pos, ang, event, options )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,403 @@
|
|||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:BehaveStart
|
||||||
|
-- Desc: Called to initialize the behaviour.\n\n You shouldn't override this - it's used to kick off the coroutine that runs the bot's behaviour. \n\nThis is called automatically when the NPC is created, there should be no need to call it manually.
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:BehaveStart()
|
||||||
|
|
||||||
|
self.BehaveThread = coroutine.create( function() self:RunBehaviour() end )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:RunBehaviour()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:BehaveUpdate
|
||||||
|
-- Desc: Called to update the bot's behaviour
|
||||||
|
-- Arg1: number|interval|How long since the last update
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:BehaveUpdate( fInterval )
|
||||||
|
|
||||||
|
if ( !self.BehaveThread ) then return end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Give a silent warning to developers if RunBehaviour has returned
|
||||||
|
--
|
||||||
|
if ( coroutine.status( self.BehaveThread ) == "dead" ) then
|
||||||
|
|
||||||
|
self.BehaveThread = nil
|
||||||
|
Msg( self, " Warning: ENT:RunBehaviour() has finished executing\n" )
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Continue RunBehaviour's execution
|
||||||
|
--
|
||||||
|
local ok, message = coroutine.resume( self.BehaveThread )
|
||||||
|
if ( ok == false ) then
|
||||||
|
|
||||||
|
self.BehaveThread = nil
|
||||||
|
ErrorNoHalt( self, " Error: ", message, "\n" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:BodyUpdate
|
||||||
|
-- Desc: Called to update the bot's animation
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:BodyUpdate()
|
||||||
|
|
||||||
|
local act = self:GetActivity()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- This helper function does a lot of useful stuff for us.
|
||||||
|
-- It sets the bot's move_x move_y pose parameters, sets their animation speed relative to the ground speed, and calls FrameAdvance.
|
||||||
|
--
|
||||||
|
if ( act == ACT_RUN || act == ACT_WALK ) then
|
||||||
|
|
||||||
|
self:BodyMoveXY()
|
||||||
|
|
||||||
|
-- BodyMoveXY() already calls FrameAdvance, calling it twice will affect animation playback, specifically on layers
|
||||||
|
return
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If we're not walking or running we probably just want to update the anim system
|
||||||
|
--
|
||||||
|
self:FrameAdvance()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnLeaveGround
|
||||||
|
-- Desc: Called when the bot's feet leave the ground - for whatever reason
|
||||||
|
-- Arg1: Entity|ent|Entity that the NextBot "jumped" from
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnLeaveGround( ent )
|
||||||
|
|
||||||
|
--MsgN( "OnLeaveGround", ent )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnLeaveGround
|
||||||
|
-- Desc: Called when the bot's feet return to the ground
|
||||||
|
-- Arg1: Entity|ent|Entity that the NextBot landed on
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnLandOnGround( ent )
|
||||||
|
|
||||||
|
--MsgN( "OnLandOnGround", ent )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnStuck
|
||||||
|
-- Desc: Called when the bot thinks it is stuck
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnStuck()
|
||||||
|
|
||||||
|
--MsgN( "OnStuck" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnUnStuck
|
||||||
|
-- Desc: Called when the bot thinks it is un-stuck
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnUnStuck()
|
||||||
|
|
||||||
|
--MsgN( "OnUnStuck" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnInjured
|
||||||
|
-- Desc: Called when the bot gets hurt
|
||||||
|
-- Arg1: CTakeDamageInfo|info|damage info
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnInjured( damageinfo )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnKilled
|
||||||
|
-- Desc: Called when the bot gets killed
|
||||||
|
-- Arg1: CTakeDamageInfo|info|damage info
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnKilled( dmginfo )
|
||||||
|
|
||||||
|
hook.Run( "OnNPCKilled", self, dmginfo:GetAttacker(), dmginfo:GetInflictor() )
|
||||||
|
|
||||||
|
self:BecomeRagdoll( dmginfo )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnOtherKilled
|
||||||
|
-- Desc: Called when someone else or something else has been killed
|
||||||
|
-- Arg1: Entity|victim|entity that was killed
|
||||||
|
-- Arg2: CTakeDamageInfo|info|damage info
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:OnOtherKilled( victim, info )
|
||||||
|
|
||||||
|
--MsgN( "OnOtherKilled", victim, info )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnContact( ent )
|
||||||
|
|
||||||
|
--MsgN( "OnContact", ent )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnIgnite()
|
||||||
|
|
||||||
|
--MsgN( "OnIgnite" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnNavAreaChanged( old, new )
|
||||||
|
|
||||||
|
--MsgN( "OnNavAreaChanged", old, new )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NextBot:FindSpots
|
||||||
|
-- Desc: Returns a table of hiding spots.
|
||||||
|
-- Arg1: table|specs|This table should contain the search info.\n\n * 'type' - the type (either 'hiding')\n * 'pos' - the position to search.\n * 'radius' - the radius to search.\n * 'stepup' - the highest step to step up.\n * 'stepdown' - the highest we can step down without being hurt.
|
||||||
|
-- Ret1: table|An unsorted table of tables containing\n * 'vector' - the position of the hiding spot\n * 'distance' - the distance to that position
|
||||||
|
--
|
||||||
|
function ENT:FindSpots( tbl )
|
||||||
|
|
||||||
|
local tbl = tbl or {}
|
||||||
|
|
||||||
|
tbl.pos = tbl.pos or self:WorldSpaceCenter()
|
||||||
|
tbl.radius = tbl.radius or 1000
|
||||||
|
tbl.stepdown = tbl.stepdown or 20
|
||||||
|
tbl.stepup = tbl.stepup or 20
|
||||||
|
tbl.type = tbl.type or 'hiding'
|
||||||
|
|
||||||
|
-- Use a path to find the length
|
||||||
|
local path = Path( "Follow" )
|
||||||
|
|
||||||
|
-- Find a bunch of areas within this distance
|
||||||
|
local areas = navmesh.Find( tbl.pos, tbl.radius, tbl.stepdown, tbl.stepup )
|
||||||
|
|
||||||
|
local found = {}
|
||||||
|
|
||||||
|
-- In each area
|
||||||
|
for _, area in pairs( areas ) do
|
||||||
|
|
||||||
|
-- get the spots
|
||||||
|
local spots
|
||||||
|
|
||||||
|
if ( tbl.type == 'hiding' ) then spots = area:GetHidingSpots() end
|
||||||
|
|
||||||
|
for k, vec in pairs( spots ) do
|
||||||
|
|
||||||
|
-- Work out the length, and add them to a table
|
||||||
|
path:Invalidate()
|
||||||
|
|
||||||
|
path:Compute( self, vec, 1 ) -- TODO: This is bullshit - it's using 'self.pos' not tbl.pos
|
||||||
|
|
||||||
|
table.insert( found, { vector = vec, distance = path:GetLength() } )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NextBot:FindSpot
|
||||||
|
-- Desc: Like FindSpots but only returns a vector
|
||||||
|
-- Arg1: string|type|Either "random", "near", "far"
|
||||||
|
-- Arg2: table|options|A table containing a bunch of tweakable options. See the function definition for more details
|
||||||
|
-- Ret1: vector|If it finds a spot it will return a vector. If not it will return nil.
|
||||||
|
--
|
||||||
|
function ENT:FindSpot( type, options )
|
||||||
|
|
||||||
|
local spots = self:FindSpots( options )
|
||||||
|
if ( !spots || #spots == 0 ) then return end
|
||||||
|
|
||||||
|
if ( type == "near" ) then
|
||||||
|
|
||||||
|
table.SortByMember( spots, "distance", true )
|
||||||
|
return spots[1].vector
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( type == "far" ) then
|
||||||
|
|
||||||
|
table.SortByMember( spots, "distance", false )
|
||||||
|
return spots[1].vector
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- random
|
||||||
|
return spots[ math.random( 1, #spots ) ].vector
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NextBot:HandleStuck
|
||||||
|
-- Desc: Called from Lua when the NPC is stuck. This should only be called from the behaviour coroutine - so if you want to override this function and do something special that yields - then go for it.\n\nYou should always call self.loco:ClearStuck() in this function to reset the stuck status - so it knows it's unstuck.
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:HandleStuck()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Clear the stuck status
|
||||||
|
--
|
||||||
|
self.loco:ClearStuck()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NextBot:MoveToPos
|
||||||
|
-- Desc: To be called in the behaviour coroutine only! Will yield until the bot has reached the goal or is stuck
|
||||||
|
-- Arg1: Vector|pos|The position we want to get to
|
||||||
|
-- Arg2: table|options|A table containing a bunch of tweakable options. See the function definition for more details
|
||||||
|
-- Ret1: string|Either "failed", "stuck", "timeout" or "ok" - depending on how the NPC got on
|
||||||
|
--
|
||||||
|
function ENT:MoveToPos( pos, options )
|
||||||
|
|
||||||
|
local options = options or {}
|
||||||
|
|
||||||
|
local path = Path( "Follow" )
|
||||||
|
path:SetMinLookAheadDistance( options.lookahead or 300 )
|
||||||
|
path:SetGoalTolerance( options.tolerance or 20 )
|
||||||
|
path:Compute( self, pos )
|
||||||
|
|
||||||
|
if ( !path:IsValid() ) then return "failed" end
|
||||||
|
|
||||||
|
while ( path:IsValid() ) do
|
||||||
|
|
||||||
|
path:Update( self )
|
||||||
|
|
||||||
|
-- Draw the path (only visible on listen servers or single player)
|
||||||
|
if ( options.draw ) then
|
||||||
|
path:Draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're stuck then call the HandleStuck function and abandon
|
||||||
|
if ( self.loco:IsStuck() ) then
|
||||||
|
|
||||||
|
self:HandleStuck()
|
||||||
|
|
||||||
|
return "stuck"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If they set maxage on options then make sure the path is younger than it
|
||||||
|
--
|
||||||
|
if ( options.maxage ) then
|
||||||
|
if ( path:GetAge() > options.maxage ) then return "timeout" end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If they set repath then rebuild the path every x seconds
|
||||||
|
--
|
||||||
|
if ( options.repath ) then
|
||||||
|
if ( path:GetAge() > options.repath ) then path:Compute( self, pos ) end
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NextBot:PlaySequenceAndWait
|
||||||
|
-- Desc: To be called in the behaviour coroutine only! Plays an animation sequence and waits for it to end before returning.
|
||||||
|
-- Arg1: string|name|The sequence name
|
||||||
|
-- Arg2: number|the speed (default 1)
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:PlaySequenceAndWait( name, speed )
|
||||||
|
|
||||||
|
local len = self:SetSequence( name )
|
||||||
|
speed = speed or 1
|
||||||
|
|
||||||
|
self:ResetSequenceInfo()
|
||||||
|
self:SetCycle( 0 )
|
||||||
|
self:SetPlaybackRate( speed )
|
||||||
|
|
||||||
|
-- wait for it to finish
|
||||||
|
coroutine.wait( len / speed )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:Use
|
||||||
|
-- Desc: Called when a player 'uses' the entity
|
||||||
|
-- Arg1: entity|activator|The entity that activated the use
|
||||||
|
-- Arg2: entity|called|The entity that called the use
|
||||||
|
-- Arg3: number|type|The type of use (USE_ON, USE_OFF, USE_TOGGLE, USE_SET)
|
||||||
|
-- Arg4: number|value|Any passed value
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:Use( activator, caller, type, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:Think
|
||||||
|
-- Desc: Called periodically
|
||||||
|
-- Arg1:
|
||||||
|
-- Ret1:
|
||||||
|
--
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:HandleAnimEvent
|
||||||
|
-- Desc: Called for serverside events
|
||||||
|
--
|
||||||
|
function ENT:HandleAnimEvent( event, eventtime, cycle, typee, options )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: NEXTBOT:OnTraceAttack
|
||||||
|
-- Desc: Called serverside when the nextbot is attacked
|
||||||
|
--
|
||||||
|
function ENT:OnTraceAttack( dmginfo, dir, trace )
|
||||||
|
|
||||||
|
hook.Run( "ScaleNPCDamage", self, trace.HitGroup, dmginfo )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when we see a player or another nextbot
|
||||||
|
function ENT:OnEntitySight( subject )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when we see lose sight of a player or a nextbot we saw earlier
|
||||||
|
function ENT:OnEntitySightLost( subject )
|
||||||
|
end
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
ENT.Base = "base_entity"
|
||||||
|
ENT.Type = "point"
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Initialize
|
||||||
|
Desc: First function called. Use to set up your entity
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: KeyValue
|
||||||
|
Desc: Called when a keyvalue is added to us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Think
|
||||||
|
Desc: Entity's think function.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function ENT:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: OnRemove
|
||||||
|
-- Desc: Called just before entity is deleted
|
||||||
|
--
|
||||||
|
function ENT:OnRemove()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- UpdateTransmitState
|
||||||
|
--
|
||||||
|
function ENT:UpdateTransmitState()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- The default behaviour for point entities is to not be networked.
|
||||||
|
-- If you're deriving an entity and want it to appear clientside, override this
|
||||||
|
-- TRANSMIT_ALWAYS = always send, TRANSMIT_PVS = send if in PVS
|
||||||
|
--
|
||||||
|
return TRANSMIT_NEVER
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
|
ENT.DisableDuplicator = true
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Make this entity always networked
|
||||||
|
--
|
||||||
|
function ENT:UpdateTransmitState() return TRANSMIT_ALWAYS end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Networked / Saved Data
|
||||||
|
--
|
||||||
|
function ENT:SetupDataTables()
|
||||||
|
|
||||||
|
self:NetworkVar( "Vector", 0, "TopColor", { KeyName = "topcolor", Edit = { type = "VectorColor", category = "Main", order = 1 } } )
|
||||||
|
self:NetworkVar( "Vector", 1, "BottomColor", { KeyName = "bottomcolor", Edit = { type = "VectorColor", category = "Main", title = "Color Bottom", order = 2 } } )
|
||||||
|
self:NetworkVar( "Float", 0, "FadeBias", { KeyName = "fadebias", Edit = { type = "Float", category = "Main", min = 0, max = 1, order = 3 } } )
|
||||||
|
|
||||||
|
self:NetworkVar( "Float", 4, "SunSize", { KeyName = "sunsize", Edit = { type = "Float", min = 0, max = 10, category = "Sun" } } )
|
||||||
|
self:NetworkVar( "Vector", 2, "SunNormal", { KeyName = "sunnormal" } ) -- No editing this - it's for coders only
|
||||||
|
self:NetworkVar( "Vector", 3, "SunColor", { KeyName = "suncolor", Edit = { type = "VectorColor", category = "Sun" } } )
|
||||||
|
|
||||||
|
self:NetworkVar( "Float", 2, "DuskScale", { KeyName = "duskscale", Edit = { type = "Float", min = 0, max = 1, category = "Dusk" } } )
|
||||||
|
self:NetworkVar( "Float", 3, "DuskIntensity", { KeyName = "duskintensity", Edit = { type = "Float", min = 0, max = 10, category = "Dusk" } } )
|
||||||
|
self:NetworkVar( "Vector", 4, "DuskColor", { KeyName = "duskcolor", Edit = { type = "VectorColor", category = "Dusk" } } )
|
||||||
|
|
||||||
|
self:NetworkVar( "Bool", 0, "DrawStars", { KeyName = "drawstars", Edit = { type = "Boolean", category = "Stars", order = 10 } } )
|
||||||
|
self:NetworkVar( "String", 0, "StarTexture", { KeyName = "startexture", Edit = { type = "Texture", group = "Stars", category = "Stars", order = 11 } } )
|
||||||
|
|
||||||
|
self:NetworkVar( "Int", 0, "StarLayers", { KeyName = "starlayers", Edit = { type = "Int", min = 1, max = 3, category = "Stars", order = 12 } } )
|
||||||
|
self:NetworkVarElement( "Angle", 0, 'p', "StarScale", { KeyName = "starscale", Edit = { type = "Float", min = 0, max = 5, category = "Stars", order = 13 } } )
|
||||||
|
self:NetworkVarElement( "Angle", 0, 'y', "StarFade", { KeyName = "starfade", Edit = { type = "Float", min = 0, max = 5, category = "Stars", order = 14 } } )
|
||||||
|
self:NetworkVarElement( "Angle", 0, 'r', "StarSpeed", { KeyName = "starspeed", Edit = { type = "Float", min = 0, max = 2, category = "Stars", order = 15 } } )
|
||||||
|
|
||||||
|
self:NetworkVar( "Float", 1, "HDRScale", { KeyName = "hdrscale", Edit = { type = "Float", category = "Main", min = 0, max = 1, order = 4 } } )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Entity defaults
|
||||||
|
--
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
self:SetTopColor( Vector( 0.2, 0.5, 1.0 ) )
|
||||||
|
self:SetBottomColor( Vector( 0.8, 1.0, 1.0 ) )
|
||||||
|
self:SetFadeBias( 1 )
|
||||||
|
|
||||||
|
|
||||||
|
self:SetSunNormal( Vector( 0.4, 0.0, 0.01 ) )
|
||||||
|
self:SetSunColor( Vector( 0.2, 0.1, 0.0 ) )
|
||||||
|
self:SetSunSize( 2.0 )
|
||||||
|
|
||||||
|
self:SetDuskColor( Vector( 1.0, 0.2, 0.0 ) )
|
||||||
|
self:SetDuskScale( 1 )
|
||||||
|
self:SetDuskIntensity( 1 )
|
||||||
|
|
||||||
|
self:SetDrawStars( true )
|
||||||
|
self:SetStarLayers( 1 )
|
||||||
|
self:SetStarSpeed( 0.01 )
|
||||||
|
self:SetStarScale( 0.5 )
|
||||||
|
self:SetStarFade( 1.5 )
|
||||||
|
self:SetStarTexture( "skybox/starfield" )
|
||||||
|
|
||||||
|
self:SetHDRScale( 0.66 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
|
||||||
|
if ( self:SetNetworkKeyValue( key, value ) ) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO: sunposmethod
|
||||||
|
-- 0 : "Custom - Use the Sun Normal to position the sun"
|
||||||
|
-- 1 : "Automatic - Find a env_sun entity and use that"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Find an env_sun - if we don't already have one.
|
||||||
|
--
|
||||||
|
if ( SERVER && self.EnvSun == nil ) then
|
||||||
|
|
||||||
|
-- so this closure only gets called once - even if it fails
|
||||||
|
self.EnvSun = false
|
||||||
|
|
||||||
|
local list = ents.FindByClass( "env_sun" )
|
||||||
|
if ( #list > 0 ) then
|
||||||
|
self.EnvSun = list[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If we have a sun - force our sun normal to its value
|
||||||
|
--
|
||||||
|
if ( SERVER && IsValid( self.EnvSun ) ) then
|
||||||
|
|
||||||
|
local vec = self.EnvSun:GetInternalVariable( "m_vDirection" )
|
||||||
|
|
||||||
|
if ( isvector( vec ) ) then
|
||||||
|
self:SetSunNormal( vec )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Become the active sky again if we're not already
|
||||||
|
--
|
||||||
|
if ( CLIENT && g_SkyPaint != self ) then
|
||||||
|
|
||||||
|
if ( !IsValid( g_SkyPaint ) ) then
|
||||||
|
g_SkyPaint = self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- To prevent server insanity - only let admins edit the sky.
|
||||||
|
--
|
||||||
|
function ENT:CanEditVariables( ply )
|
||||||
|
|
||||||
|
return ply:IsAdmin()
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.RenderGroup = RENDERGROUP_OTHER
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
hook.Add( "OnViewModelChanged", self, self.ViewModelChanged )
|
||||||
|
|
||||||
|
self:SetNotSolid( true )
|
||||||
|
self:DrawShadow( false )
|
||||||
|
self:SetTransmitWithParent( true ) -- Transmit only when the viewmodel does!
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:DoSetup( ply, spec )
|
||||||
|
|
||||||
|
-- Set these hands to the player
|
||||||
|
ply:SetHands( self )
|
||||||
|
self:SetOwner( ply )
|
||||||
|
|
||||||
|
-- Which hands should we use? Let the gamemode decide
|
||||||
|
hook.Call( "PlayerSetHandsModel", GAMEMODE, spec or ply, self )
|
||||||
|
|
||||||
|
-- Attach them to the viewmodel
|
||||||
|
local vm = ( spec or ply ):GetViewModel( 0 )
|
||||||
|
self:AttachToViewmodel( vm )
|
||||||
|
|
||||||
|
vm:DeleteOnRemove( self )
|
||||||
|
ply:DeleteOnRemove( self )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayerColor()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Make sure there's an owner and they have this function
|
||||||
|
-- before trying to call it!
|
||||||
|
--
|
||||||
|
local owner = self:GetOwner()
|
||||||
|
if ( !IsValid( owner ) ) then return end
|
||||||
|
if ( !owner.GetPlayerColor ) then return end
|
||||||
|
|
||||||
|
return owner:GetPlayerColor()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:ViewModelChanged( vm, old, new )
|
||||||
|
|
||||||
|
-- Ignore other peoples viewmodel changes!
|
||||||
|
if ( vm:GetOwner() != self:GetOwner() ) then return end
|
||||||
|
|
||||||
|
self:AttachToViewmodel( vm )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:AttachToViewmodel( vm )
|
||||||
|
|
||||||
|
self:AddEffects( EF_BONEMERGE )
|
||||||
|
self:SetParent( vm )
|
||||||
|
self:SetMoveType( MOVETYPE_NONE )
|
||||||
|
|
||||||
|
self:SetPos( vector_origin )
|
||||||
|
self:SetAngles( angle_zero )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
if ( self.RedTeam or self.GreenTeam or self.YellowTeam or self.BlueTeam ) then
|
||||||
|
|
||||||
|
-- If any of these are set to true then
|
||||||
|
-- make sure that any that aren't setup are
|
||||||
|
-- set to false.
|
||||||
|
|
||||||
|
self.BlueTeam = self.BlueTeam or false
|
||||||
|
self.GreenTeam = self.GreenTeam or false
|
||||||
|
self.YellowTeam = self.YellowTeam or false
|
||||||
|
self.RedTeam = self.RedTeam or false
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- If none are set then make it so that they all
|
||||||
|
-- are set to true since any team can spawn here.
|
||||||
|
-- This will also happen if we don't have the "spawnflags"
|
||||||
|
-- keyvalue setup.
|
||||||
|
|
||||||
|
self.BlueTeam = true
|
||||||
|
self.GreenTeam = true
|
||||||
|
self.YellowTeam = true
|
||||||
|
self.RedTeam = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
|
||||||
|
if ( key == "spawnflags" ) then
|
||||||
|
|
||||||
|
local sf = tonumber( value )
|
||||||
|
|
||||||
|
for i = 15, 0, -1 do
|
||||||
|
|
||||||
|
local bit = math.pow( 2, i )
|
||||||
|
|
||||||
|
-- Quick bit if bitwise math to figure out if the spawnflags
|
||||||
|
-- represent red/blue/green or yellow.
|
||||||
|
-- We have to use booleans since the TEAM_ identifiers
|
||||||
|
-- aren't setup at this point.
|
||||||
|
-- (this would be easier if we had bitwise operators in Lua)
|
||||||
|
|
||||||
|
if ( ( sf - bit ) >= 0 ) then
|
||||||
|
|
||||||
|
if ( bit == 8 ) then self.RedTeam = true
|
||||||
|
elseif ( bit == 4 ) then self.GreenTeam = true
|
||||||
|
elseif ( bit == 2 ) then self.YellowTeam = true
|
||||||
|
elseif ( bit == 1 ) then self.BlueTeam = true
|
||||||
|
end
|
||||||
|
|
||||||
|
sf = sf - bit
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
if ( bit == 8 ) then self.RedTeam = false
|
||||||
|
elseif ( bit == 4 ) then self.GreenTeam = false
|
||||||
|
elseif ( bit == 2 ) then self.YellowTeam = false
|
||||||
|
elseif ( bit == 1 ) then self.BlueTeam = false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
-- This is just a simple point entity.
|
||||||
|
|
||||||
|
-- We only use it to represent the position and angle of a spawn point
|
||||||
|
-- So we don't have to do anything here because the baseclass will
|
||||||
|
-- take care of the basics
|
||||||
|
|
||||||
|
-- This file only exists so that the entity is created
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
-- A spawnflag constant for addons
|
||||||
|
SF_LUA_RUN_ON_SPAWN = 1
|
||||||
|
|
||||||
|
ENT.Type = "point"
|
||||||
|
ENT.DisableDuplicator = true
|
||||||
|
|
||||||
|
AccessorFunc( ENT, "m_bDefaultCode", "DefaultCode" )
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
-- If the entity has its first spawnflag set, run the code automatically
|
||||||
|
if ( self:HasSpawnFlags( SF_LUA_RUN_ON_SPAWN ) ) then
|
||||||
|
self:RunCode( self, self, self:GetDefaultCode() )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:KeyValue( key, value )
|
||||||
|
|
||||||
|
if ( key == "Code" ) then
|
||||||
|
self:SetDefaultCode( value )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:SetupGlobals( activator, caller )
|
||||||
|
|
||||||
|
ACTIVATOR = activator
|
||||||
|
CALLER = caller
|
||||||
|
|
||||||
|
if ( IsValid( activator ) && activator:IsPlayer() ) then
|
||||||
|
TRIGGER_PLAYER = activator
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:KillGlobals()
|
||||||
|
|
||||||
|
ACTIVATOR = nil
|
||||||
|
CALLER = nil
|
||||||
|
TRIGGER_PLAYER = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:RunCode( activator, caller, code )
|
||||||
|
|
||||||
|
self:SetupGlobals( activator, caller )
|
||||||
|
|
||||||
|
RunString( code, "lua_run#" .. self:EntIndex() )
|
||||||
|
|
||||||
|
self:KillGlobals()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:AcceptInput( name, activator, caller, data )
|
||||||
|
|
||||||
|
if ( name == "RunCode" ) then self:RunCode( activator, caller, self:GetDefaultCode() ) return true end
|
||||||
|
if ( name == "RunPassedCode" ) then self:RunCode( activator, caller, data ) return true end
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_nextbot"
|
||||||
|
ENT.Spawnable = false
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
--self:SetModel( "models/props_halloween/ghost_no_hat.mdl" )
|
||||||
|
--self:SetModel( "models/props_wasteland/controlroom_filecabinet002a.mdl" )
|
||||||
|
self:SetModel( "models/mossman.mdl" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:RunBehaviour()
|
||||||
|
|
||||||
|
while ( true ) do
|
||||||
|
|
||||||
|
self:StartActivity( ACT_WALK ) -- walk anims
|
||||||
|
self.loco:SetDesiredSpeed( 100 ) -- walk speeds
|
||||||
|
|
||||||
|
-- Choose a random location within 400 units of our position
|
||||||
|
local targetPos = self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 400
|
||||||
|
|
||||||
|
-- Search for walkable space there, or nearby
|
||||||
|
local area = navmesh.GetNearestNavArea( targetPos )
|
||||||
|
|
||||||
|
-- We found walkable space, get the closest point on that area to where we want to be
|
||||||
|
if ( IsValid( area ) ) then targetPos = area:GetClosestPointOnArea( targetPos ) end
|
||||||
|
|
||||||
|
-- walk to the target place (yielding)
|
||||||
|
self:MoveToPos( targetPos )
|
||||||
|
|
||||||
|
self:StartActivity( ACT_IDLE ) -- revert to idle activity
|
||||||
|
|
||||||
|
self:PlaySequenceAndWait( "idle_to_sit_ground" ) -- Sit on the floor
|
||||||
|
self:SetSequence( "sit_ground" ) -- Stay sitting
|
||||||
|
coroutine.wait( self:PlayScene( "scenes/eli_lab/mo_gowithalyx01.vcd" ) ) -- play a scene and wait for it to finish before progressing
|
||||||
|
self:PlaySequenceAndWait( "sit_ground_to_idle" ) -- Get up
|
||||||
|
|
||||||
|
-- find the furthest away hiding spot
|
||||||
|
local pos = self:FindSpot( "random", { type = 'hiding', radius = 5000 } )
|
||||||
|
|
||||||
|
-- if the position is valid
|
||||||
|
if ( pos ) then
|
||||||
|
self:StartActivity( ACT_RUN ) -- run anim
|
||||||
|
self.loco:SetDesiredSpeed( 200 ) -- run speed
|
||||||
|
self:PlayScene( "scenes/npc/female01/watchout.vcd" ) -- shout something while we run just for a laugh
|
||||||
|
self:MoveToPos( pos ) -- move to position (yielding)
|
||||||
|
self:PlaySequenceAndWait( "fear_reaction" ) -- play a fear animation
|
||||||
|
self:StartActivity( ACT_IDLE ) -- when we finished, go into the idle anim
|
||||||
|
else
|
||||||
|
|
||||||
|
-- some activity to signify that we didn't find shit
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- List the NPC as spawnable
|
||||||
|
--
|
||||||
|
list.Set( "NPC", "npc_tf2_ghost", {
|
||||||
|
Name = "Example NPC",
|
||||||
|
Class = "npc_tf2_ghost",
|
||||||
|
Category = "Nextbot"
|
||||||
|
} )
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*--------------------------------------------------
|
||||||
|
*** Copyright (c) 2012-2024 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.
|
||||||
|
--------------------------------------------------*/
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.Base = "obj_vj_projectile_base"
|
||||||
|
ENT.PrintName = "Grenade"
|
||||||
|
ENT.Author = "DrVrej"
|
||||||
|
ENT.Contact = "http://steamcommunity.com/groups/vrejgaming"
|
||||||
|
ENT.Information = "Projectiles for my addons"
|
||||||
|
ENT.Category = "VJ Base"
|
||||||
|
|
||||||
|
ENT.Spawnable = true
|
||||||
|
ENT.AdminOnly = false
|
||||||
|
|
||||||
|
ENT.VJTag_ID_Grenade = true
|
||||||
|
ENT.VJTag_IsPickupable = true
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
if CLIENT then
|
||||||
|
local Name = "Grenade"
|
||||||
|
local LangName = "obj_vj_grenade"
|
||||||
|
language.Add(LangName, Name)
|
||||||
|
killicon.Add(LangName,"HUD/killicons/default",Color(255,80,0,255))
|
||||||
|
language.Add("#"..LangName, Name)
|
||||||
|
killicon.Add("#"..LangName,"HUD/killicons/default",Color(255,80,0,255))
|
||||||
|
end
|
||||||
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
if !SERVER then return end
|
||||||
|
|
||||||
|
ENT.Model = {"models/vj_weapons/w_grenade.mdl"} -- The models it should spawn with | Picks a random one from the table
|
||||||
|
ENT.MoveCollideType = nil
|
||||||
|
ENT.CollisionGroupType = nil
|
||||||
|
ENT.SolidType = SOLID_VPHYSICS
|
||||||
|
ENT.RemoveOnHit = false -- Should it remove itself when it touches something? | It will run the hit sound, place a decal, etc.
|
||||||
|
ENT.DoesRadiusDamage = true -- Should it do a blast damage when it hits something?
|
||||||
|
ENT.RadiusDamageRadius = 256 -- How far the damage go? The farther away it's from its enemy, the less damage it will do | Counted in world units
|
||||||
|
ENT.RadiusDamage = 256 -- How much damage should it deal? Remember this is a radius damage, therefore it will do less damage the farther away the entity is from its enemy
|
||||||
|
ENT.RadiusDamageUseRealisticRadius = true -- Should the damage decrease the farther away the enemy is from the position that the projectile hit?
|
||||||
|
ENT.RadiusDamageType = DMG_BLAST -- Damage type
|
||||||
|
ENT.RadiusDamageForce = 90 -- Put the force amount it should apply | false = Don't apply any force
|
||||||
|
ENT.DecalTbl_DeathDecals = {"Scorch"}
|
||||||
|
ENT.SoundTbl_OnCollide = {"weapons/hegrenade/he_bounce-1.wav"}
|
||||||
|
|
||||||
|
-- Custom
|
||||||
|
ENT.FuseTime = 3
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function ENT:CustomPhysicsObjectOnInitialize(phys)
|
||||||
|
phys:Wake()
|
||||||
|
phys:EnableGravity(true)
|
||||||
|
phys:SetBuoyancyRatio(0)
|
||||||
|
end
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function ENT:CustomOnInitialize()
|
||||||
|
timer.Simple(self.FuseTime, function()
|
||||||
|
if IsValid(self) then
|
||||||
|
self:DeathEffects()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function ENT:CustomOnTakeDamage(dmginfo)
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:AddVelocity(dmginfo:GetDamageForce() * 0.1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function ENT:CustomOnPhysicsCollide(data, phys)
|
||||||
|
local getVel = phys:GetVelocity()
|
||||||
|
local curVelSpeed = getVel:Length()
|
||||||
|
//print(curVelSpeed)
|
||||||
|
if curVelSpeed > 500 then -- Or else it will go flying!
|
||||||
|
phys:SetVelocity(getVel * 0.9)
|
||||||
|
end
|
||||||
|
|
||||||
|
if curVelSpeed > 100 then -- If the grenade is going faster than 100, then play the touch sound
|
||||||
|
self:OnCollideSoundCode()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
local defAngle = Angle(0, 0, 0)
|
||||||
|
local vecZ4 = Vector(0, 0, 4)
|
||||||
|
local vezZ100 = Vector(0, 0, 100)
|
||||||
|
--
|
||||||
|
function ENT:DeathEffects()
|
||||||
|
local selfPos = self:GetPos()
|
||||||
|
|
||||||
|
ParticleEffect("vj_explosion1", self:GetPos(), defAngle, nil)
|
||||||
|
|
||||||
|
local effectData = EffectData()
|
||||||
|
effectData:SetOrigin(self:GetPos())
|
||||||
|
//effectData:SetScale(500)
|
||||||
|
//util.Effect("HelicopterMegaBomb", effectData)
|
||||||
|
//util.Effect("ThumperDust", effectData)
|
||||||
|
util.Effect("Explosion", effectData)
|
||||||
|
//util.Effect("VJ_Small_Explosion1", effectData)
|
||||||
|
|
||||||
|
local expLight = ents.Create("light_dynamic")
|
||||||
|
expLight:SetKeyValue("brightness", "4")
|
||||||
|
expLight:SetKeyValue("distance", "300")
|
||||||
|
expLight:SetLocalPos(selfPos)
|
||||||
|
expLight:SetLocalAngles(self:GetAngles())
|
||||||
|
expLight:Fire("Color", "255 150 0")
|
||||||
|
expLight:SetParent(self)
|
||||||
|
expLight:Spawn()
|
||||||
|
expLight:Activate()
|
||||||
|
expLight:Fire("TurnOn", "", 0)
|
||||||
|
self:DeleteOnRemove(expLight)
|
||||||
|
util.ScreenShake(self:GetPos(), 100, 200, 1, 2500)
|
||||||
|
|
||||||
|
self:SetLocalPos(selfPos + vecZ4) -- Because the entity is too close to the ground
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = self:GetPos(),
|
||||||
|
endpos = self:GetPos() - vezZ100,
|
||||||
|
filter = self
|
||||||
|
})
|
||||||
|
util.Decal("Scorch", tr.HitPos + tr.HitNormal, tr.HitPos - tr.HitNormal)
|
||||||
|
|
||||||
|
self:DoDamageCode()
|
||||||
|
self:SetDeathVariablesTrue(nil, nil, false)
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
if ( CLIENT ) then
|
||||||
|
CreateConVar( "cl_draweffectrings", "1", 0, "Should the effect green rings be visible?" )
|
||||||
|
end
|
||||||
|
|
||||||
|
ENT.Type = "anim"
|
||||||
|
|
||||||
|
ENT.Spawnable = false
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
local Radius = 6
|
||||||
|
local mins = Vector( 1, 1, 1 ) * Radius * -0.5
|
||||||
|
local maxs = Vector( 1, 1, 1 ) * Radius * 0.5
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
self.AttachedEntity = ents.Create( "prop_dynamic" )
|
||||||
|
self.AttachedEntity:SetModel( self:GetModel() )
|
||||||
|
self.AttachedEntity:SetAngles( self:GetAngles() )
|
||||||
|
self.AttachedEntity:SetPos( self:GetPos() )
|
||||||
|
self.AttachedEntity:SetSkin( self:GetSkin() )
|
||||||
|
self.AttachedEntity:Spawn()
|
||||||
|
self.AttachedEntity:SetParent( self )
|
||||||
|
self.AttachedEntity:DrawShadow( false )
|
||||||
|
|
||||||
|
self:SetModel( "models/props_junk/watermelon01.mdl" )
|
||||||
|
|
||||||
|
self:DeleteOnRemove( self.AttachedEntity )
|
||||||
|
self.AttachedEntity:DeleteOnRemove( self )
|
||||||
|
|
||||||
|
-- Don't use the model's physics - create a box instead
|
||||||
|
self:PhysicsInitBox( mins, maxs )
|
||||||
|
self:SetSolid( SOLID_VPHYSICS )
|
||||||
|
|
||||||
|
-- Set up our physics object here
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if ( IsValid( phys ) ) then
|
||||||
|
phys:Wake()
|
||||||
|
phys:EnableGravity( false )
|
||||||
|
phys:EnableDrag( false )
|
||||||
|
end
|
||||||
|
|
||||||
|
self:DrawShadow( false )
|
||||||
|
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- So addons can override this
|
||||||
|
self.GripMaterial = Material( "sprites/grip" )
|
||||||
|
self.GripMaterialHover = Material( "sprites/grip_hover" )
|
||||||
|
|
||||||
|
-- Get the attached entity so that clientside functions like properties can interact with it
|
||||||
|
local tab = ents.FindByClassAndParent( "prop_dynamic", self )
|
||||||
|
if ( tab && IsValid( tab[ 1 ] ) ) then self.AttachedEntity = tab[ 1 ] end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set collision bounds exactly
|
||||||
|
self:SetCollisionBounds( mins, maxs )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Draw()
|
||||||
|
|
||||||
|
if ( halo.RenderedEntity() == self ) then
|
||||||
|
self.AttachedEntity:DrawModel()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( GetConVarNumber( "cl_draweffectrings" ) == 0 ) then return end
|
||||||
|
|
||||||
|
-- Don't draw the grip if there's no chance of us picking it up
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local wep = ply:GetActiveWeapon()
|
||||||
|
if ( !IsValid( wep ) ) then return end
|
||||||
|
|
||||||
|
local weapon_name = wep:GetClass()
|
||||||
|
|
||||||
|
if ( weapon_name != "weapon_physgun" && weapon_name != "weapon_physcannon" && weapon_name != "gmod_tool" ) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( self:BeingLookedAtByLocalPlayer() ) then
|
||||||
|
render.SetMaterial( self.GripMaterialHover )
|
||||||
|
else
|
||||||
|
render.SetMaterial( self.GripMaterial )
|
||||||
|
end
|
||||||
|
|
||||||
|
render.DrawSprite( self:GetPos(), 16, 16, color_white )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copied from base_gmodentity.lua
|
||||||
|
ENT.MaxWorldTipDistance = 256
|
||||||
|
function ENT:BeingLookedAtByLocalPlayer()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
if ( !IsValid( ply ) ) then return false end
|
||||||
|
|
||||||
|
local view = ply:GetViewEntity()
|
||||||
|
local dist = self.MaxWorldTipDistance
|
||||||
|
dist = dist * dist
|
||||||
|
|
||||||
|
-- If we're spectating a player, perform an eye trace
|
||||||
|
if ( view:IsPlayer() ) then
|
||||||
|
return view:EyePos():DistToSqr( self:GetPos() ) <= dist && view:GetEyeTrace().Entity == self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we're not spectating a player, perform a manual trace from the entity's position
|
||||||
|
local pos = view:GetPos()
|
||||||
|
|
||||||
|
if ( pos:DistToSqr( self:GetPos() ) <= dist ) then
|
||||||
|
return util.TraceLine( {
|
||||||
|
start = pos,
|
||||||
|
endpos = pos + ( view:GetAngles():Forward() * dist ),
|
||||||
|
filter = view
|
||||||
|
} ).Entity == self
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:PhysicsUpdate( physobj )
|
||||||
|
|
||||||
|
if ( CLIENT ) then return end
|
||||||
|
|
||||||
|
-- Don't do anything if the player isn't holding us
|
||||||
|
if ( !self:IsPlayerHolding() && !self:IsConstrained() ) then
|
||||||
|
|
||||||
|
physobj:SetVelocity( vector_origin )
|
||||||
|
physobj:Sleep()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnEntityCopyTableFinish( tab )
|
||||||
|
|
||||||
|
-- We need to store the model of the attached entity
|
||||||
|
-- Not the one we have here.
|
||||||
|
tab.Model = self.AttachedEntity:GetModel()
|
||||||
|
|
||||||
|
-- Store the attached entity's table so we can restore it after being pasted
|
||||||
|
tab.AttachedEntityInfo = table.Copy( duplicator.CopyEntTable( self.AttachedEntity ) )
|
||||||
|
tab.AttachedEntityInfo.Pos = nil -- Don't even save angles and position, we are a parented entity
|
||||||
|
tab.AttachedEntityInfo.Angle = nil
|
||||||
|
|
||||||
|
-- Do NOT store the attached entity itself in our table!
|
||||||
|
-- Otherwise, if we copy-paste the prop with the duplicator, its AttachedEntity value will point towards the original prop's attached entity instead, and that'll break stuff
|
||||||
|
tab.AttachedEntity = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:PostEntityPaste( ply )
|
||||||
|
|
||||||
|
-- Restore the attached entity using the information we've saved
|
||||||
|
if ( IsValid( self.AttachedEntity ) && self.AttachedEntityInfo ) then
|
||||||
|
|
||||||
|
-- Apply skin, bodygroups, bone manipulator, etc.
|
||||||
|
duplicator.DoGeneric( self.AttachedEntity, self.AttachedEntityInfo )
|
||||||
|
|
||||||
|
if ( self.AttachedEntityInfo.EntityMods ) then
|
||||||
|
self.AttachedEntity.EntityMods = table.Copy( self.AttachedEntityInfo.EntityMods )
|
||||||
|
duplicator.ApplyEntityModifiers( ply, self.AttachedEntity )
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( self.AttachedEntityInfo.BoneMods ) then
|
||||||
|
self.AttachedEntity.BoneMods = table.Copy( self.AttachedEntityInfo.BoneMods )
|
||||||
|
duplicator.ApplyBoneModifiers( ply, self.AttachedEntity )
|
||||||
|
end
|
||||||
|
|
||||||
|
self.AttachedEntityInfo = nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.Spawnable = false
|
||||||
|
ENT.AdminOnly = false
|
||||||
|
ENT.Editable = true
|
||||||
|
|
||||||
|
function ENT:SetupDataTables()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Scale - how far the ragdoll will move in the game world in relation to how far it moved in the real world
|
||||||
|
--
|
||||||
|
self:NetworkVar( "Float", 0, "Scale", { KeyName = "scale", Edit = { type = "Float", min=1, max=512, order = 1 } } )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Normalize - if enabled the limbs aren't stretched
|
||||||
|
--
|
||||||
|
self:NetworkVar( "Bool", 0, "Normalize", { KeyName = "normalize", Edit = { type = "Boolean", order = 2 } } )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Debug - Shows some debug info - only available on a listen server
|
||||||
|
--
|
||||||
|
self:NetworkVar( "Bool", 1, "Debug", { KeyName = "debug", Edit = { type = "Boolean", order = 100 } } )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Controller - the entity that is currently controlling the ragdoll
|
||||||
|
--
|
||||||
|
self:NetworkVar( "Entity", 0, "Controller" )
|
||||||
|
self:NetworkVar( "Entity", 1, "Target" )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Defaults
|
||||||
|
--
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
self:SetScale( 36 )
|
||||||
|
self:SetDebug( false )
|
||||||
|
self:SetNormalize( true )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
self:SetModel( "models/maxofs2d/motion_sensor.mdl" )
|
||||||
|
self:PhysicsInit( SOLID_VPHYSICS )
|
||||||
|
|
||||||
|
-- Don't collide with the player
|
||||||
|
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||||
|
|
||||||
|
self:DrawShadow( false )
|
||||||
|
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if ( IsValid( phys ) ) then
|
||||||
|
|
||||||
|
phys:Wake()
|
||||||
|
phys:EnableGravity( false )
|
||||||
|
phys:EnableDrag( false )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local colors = {
|
||||||
|
Color( 180, 255, 50 ),
|
||||||
|
Color( 0, 150, 255 ),
|
||||||
|
Color( 255, 255, 0 ),
|
||||||
|
Color( 255, 50, 255 )
|
||||||
|
}
|
||||||
|
|
||||||
|
self:SetColor( table.Random( colors ) )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- We don't want to move unless the player moves us or we're constrained to something.
|
||||||
|
--
|
||||||
|
function ENT:PhysicsUpdate( physobj )
|
||||||
|
|
||||||
|
if ( self:IsPlayerHolding() ) then return end
|
||||||
|
if ( self:IsConstrained() ) then return end
|
||||||
|
|
||||||
|
physobj:SetVelocity( vector_origin )
|
||||||
|
physobj:Sleep()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Clean up on remove
|
||||||
|
--
|
||||||
|
function ENT:OnRemove()
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
|
||||||
|
local ragdoll = self:GetTarget()
|
||||||
|
if ( IsValid( ragdoll ) ) then
|
||||||
|
ragdoll:SetRagdollBuildFunction( nil )
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Draw()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Don't draw if we're holding the camera
|
||||||
|
--
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local wep = ply:GetActiveWeapon()
|
||||||
|
if ( wep:IsValid() ) then
|
||||||
|
if ( wep:GetClass() == "gmod_camera" ) then return end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:DrawDebug( ragdoll, controller, pos, ang, rotation, scale, center, changed_sensor )
|
||||||
|
|
||||||
|
local UpdateTime = 0.1
|
||||||
|
local StayTime = 0.15
|
||||||
|
|
||||||
|
if ( self.LastDebugUpdate && CurTime() - self.LastDebugUpdate < UpdateTime ) then return end
|
||||||
|
|
||||||
|
self.LastDebugUpdate = CurTime()
|
||||||
|
|
||||||
|
center = center
|
||||||
|
|
||||||
|
local col_bone = color_white
|
||||||
|
local col_point = Color( 255, 0, 0, 255 )
|
||||||
|
local col_tran_bn = Color( 0, 255, 0, 255 )
|
||||||
|
|
||||||
|
local realbonepos = {}
|
||||||
|
local fixedbonepos = {}
|
||||||
|
local min = Vector( 1, 1, 1 ) * -0.5
|
||||||
|
local max = Vector( 1, 1, 1 ) * 0.5
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Draw Points
|
||||||
|
--
|
||||||
|
for i = 0, 19 do
|
||||||
|
|
||||||
|
realbonepos[i] = controller:MotionSensorPos( i ) * scale
|
||||||
|
realbonepos[i]:Rotate( rotation )
|
||||||
|
realbonepos[i] = realbonepos[i] + center
|
||||||
|
|
||||||
|
fixedbonepos[i] = changed_sensor[ i ] * scale
|
||||||
|
-- (already rotated)
|
||||||
|
fixedbonepos[i] = fixedbonepos[i] + center
|
||||||
|
|
||||||
|
|
||||||
|
debugoverlay.Box( realbonepos[i], min, max, StayTime, col_point, true )
|
||||||
|
debugoverlay.Box( fixedbonepos[i], min, max, StayTime, col_tran_bn, true )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Draw bones
|
||||||
|
--
|
||||||
|
for k, v in pairs( motionsensor.DebugBones ) do
|
||||||
|
|
||||||
|
debugoverlay.Line( realbonepos[ v[1] ], realbonepos[ v[2] ], StayTime, col_bone, true )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Draw translated sensor bones
|
||||||
|
--
|
||||||
|
for k, v in pairs( motionsensor.DebugBones ) do
|
||||||
|
|
||||||
|
debugoverlay.Line( fixedbonepos[ v[1] ], fixedbonepos[ v[2] ], StayTime, col_tran_bn, true )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Draw ragdoll physics bones
|
||||||
|
--
|
||||||
|
for i=0, ragdoll:GetPhysicsObjectCount() - 1 do
|
||||||
|
|
||||||
|
local phys = ragdoll:GetPhysicsObjectNum( i )
|
||||||
|
|
||||||
|
local pos = phys:GetPos()
|
||||||
|
local angle = phys:GetAngles()
|
||||||
|
local txt = i
|
||||||
|
|
||||||
|
if ( ang[i] == nil ) then
|
||||||
|
txt = i .. " (UNSET)"
|
||||||
|
end
|
||||||
|
|
||||||
|
debugoverlay.Text( pos, txt, StayTime )
|
||||||
|
debugoverlay.Axis( pos, angle, 5, StayTime, true )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:SetRagdoll( ragdoll )
|
||||||
|
|
||||||
|
self:SetTarget( ragdoll )
|
||||||
|
ragdoll:PhysWake()
|
||||||
|
|
||||||
|
local buildername = motionsensor.ChooseBuilderFromEntity( ragdoll )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Set the ragdoll build function.
|
||||||
|
-- This function is called whenever the ragdoll bones are built.
|
||||||
|
-- in this function is the one place you can successfully call ent:SetRagdollBone
|
||||||
|
--
|
||||||
|
ragdoll:SetRagdollBuildFunction( function( ragdoll )
|
||||||
|
|
||||||
|
local controller = self:GetController()
|
||||||
|
if ( !IsValid( controller ) ) then return end
|
||||||
|
|
||||||
|
local builder = list.Get( "SkeletonConvertor" )[ buildername ]
|
||||||
|
local scale = self:GetScale()
|
||||||
|
local rotation = self:GetAngles()
|
||||||
|
local center = self:GetPos()
|
||||||
|
local normalize = self:GetNormalize()
|
||||||
|
local debug = self:GetDebug()
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Call the build skeleton function.
|
||||||
|
-- This is thrown out to a pseudo class because we want to be
|
||||||
|
-- able to add new skeleton types nice and easily.
|
||||||
|
--
|
||||||
|
local pos, ang, changed_sensor = motionsensor.BuildSkeleton( builder, controller, rotation )
|
||||||
|
|
||||||
|
--
|
||||||
|
-- For development
|
||||||
|
--
|
||||||
|
if ( debug ) then
|
||||||
|
self:DrawDebug( ragdoll, controller, pos, ang, rotation, scale, center, changed_sensor )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- If we don't have 85% of the points, just drop dead
|
||||||
|
--
|
||||||
|
local iSkipped = 0
|
||||||
|
local iMaxSkip = table.Count( pos ) * 0.25
|
||||||
|
for k, v in pairs( pos ) do
|
||||||
|
|
||||||
|
if ( math.abs( v.x ) > 0.05 ) then continue end
|
||||||
|
if ( math.abs( v.y ) > 0.05 ) then continue end
|
||||||
|
|
||||||
|
pos[k] = nil -- don't use this point to control the ragdoll
|
||||||
|
ang[k] = nil -- (use the ragdoll point)
|
||||||
|
|
||||||
|
iSkipped = iSkipped + 1
|
||||||
|
|
||||||
|
if ( iSkipped > iMaxSkip ) then
|
||||||
|
|
||||||
|
ragdoll:RagdollStopControlling()
|
||||||
|
return
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Loop each returned position
|
||||||
|
--
|
||||||
|
for k, v in pairs( pos ) do
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Set the bone angle
|
||||||
|
--
|
||||||
|
if ( ang[ k ] != nil ) then
|
||||||
|
ragdoll:SetRagdollAng( k, ang[ k ] )
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- The root bone, we directly set the position of this one.
|
||||||
|
--
|
||||||
|
if ( k == 0 || !normalize ) then
|
||||||
|
|
||||||
|
local new_position = center + v * scale
|
||||||
|
ragdoll:SetRagdollPos( k, new_position )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Normalize the ragdoll
|
||||||
|
--
|
||||||
|
if ( normalize ) then
|
||||||
|
|
||||||
|
ragdoll:RagdollSolve()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Makes the physics objects follow the set bone positions
|
||||||
|
--
|
||||||
|
ragdoll:RagdollUpdatePhysics()
|
||||||
|
|
||||||
|
end )
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
include('shared.lua')
|
||||||
|
|
||||||
|
function ENT:Draw() self:DrawModel() end
|
||||||
|
function ENT:DrawTranslucent() self:Draw() end
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
AddCSLuaFile('shared.lua')
|
||||||
|
AddCSLuaFile('cl_init.lua')
|
||||||
|
include("shared.lua")
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
if self.enable_ent and (!IsValid(self.ent) or self.ent:Health() <= 0) then
|
||||||
|
self:Remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:GetCycle() >= 1 then
|
||||||
|
self:SetCycle(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ent = self.ent
|
||||||
|
if IsValid(ent) then
|
||||||
|
local bone = self:LookupBone("root") or self:LookupBone("ValveBiped.Bip01_Pelvis")
|
||||||
|
local att = self:GetBonePosition(bone)
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = att,
|
||||||
|
endpos = att - Vector(0,0,100),
|
||||||
|
filter = ent,
|
||||||
|
})
|
||||||
|
ent:SetPos(tr.HitPos)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.push or IsValid(ent) then
|
||||||
|
local bone = self:LookupBone("root") or self:LookupBone("ValveBiped.Bip01_Pelvis")
|
||||||
|
local att = self:GetBonePosition(bone)
|
||||||
|
for k, v in pairs(ents.FindInSphere(att, 100)) do
|
||||||
|
if v:IsNPC() and v != ent then
|
||||||
|
local pos1 = att
|
||||||
|
local pos2 = v:GetPos()
|
||||||
|
local dir = (pos1 - pos2):GetNormalized()
|
||||||
|
v:SetVelocity(-dir * 100)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ENT.Base = "base_anim"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
include("shared.lua")
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self.TableProp = {
|
||||||
|
{
|
||||||
|
prop = "models/props_fortifications/concrete_barrier001_96_reference.mdl",
|
||||||
|
health = 2500,
|
||||||
|
damage = 0,
|
||||||
|
breaksound = "physics/concrete/concrete_break"..math.random(2,3)..".wav",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop = "models/props_fortifications/barricade_razorwire001_128_reference.mdl",
|
||||||
|
health = 250,
|
||||||
|
damage = 10,
|
||||||
|
breaksound = "physics/metal/metal_chainlink_impact_hard"..math.random(1,3)..".wav",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop = "models/props_wasteland/dockplank01b.mdl",
|
||||||
|
health = 500,
|
||||||
|
damage = 0,
|
||||||
|
breaksound = "physics/wood/wood_plank_break"..math.random(1,4)..".wav",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop = "models/props_debris/metal_panel01a.mdl",
|
||||||
|
health = 1125,
|
||||||
|
damage = 0,
|
||||||
|
breaksound = "physics/metal/metal_chainlink_impact_hard"..math.random(1,3)..".wav",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop = "models/props_combine/combine_light001a.mdl",
|
||||||
|
health = 100,
|
||||||
|
damage = 0,
|
||||||
|
breaksound = "physics/glass/glass_bottle_impact_hard"..math.random(1,3)..".wav",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop = "",
|
||||||
|
health = self.healthmax,
|
||||||
|
damage = 0,
|
||||||
|
breaksound = "physics/concrete/concrete_break"..math.random(2,3)..".wav",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if not self.MapCade then
|
||||||
|
if not self.id then
|
||||||
|
self.id = 1
|
||||||
|
end
|
||||||
|
self.barricade = true
|
||||||
|
self:SetModel(self.TableProp[self.id].prop)
|
||||||
|
if self.id != 2 then
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
if self.id == 5 then
|
||||||
|
self:SetNWBool('lamp', true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.health = self.TableProp[self.id].health
|
||||||
|
else
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
end
|
||||||
|
self:SetNWFloat('healthmax', self.TableProp[self.id].health)
|
||||||
|
self:SetCustomCollisionCheck(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
self:SetColor(Color(255,255*(self.health/self.TableProp[self.id].health),255*(self.health/self.TableProp[self.id].health)))
|
||||||
|
self:SetHealth(self.health)
|
||||||
|
if self.TableProp[self.id].damage > 0 and not self.cantdamage then
|
||||||
|
self.cantdamage = true
|
||||||
|
for _, ent in ipairs(ents.FindInSphere(self:GetPos(), 40)) do
|
||||||
|
if (ent:IsPlayer() or ent:IsNextBot()) then
|
||||||
|
local d = DamageInfo()
|
||||||
|
if ent:IsNextBot() then
|
||||||
|
d:SetDamage(self.TableProp[self.id].damage)
|
||||||
|
end
|
||||||
|
d:SetAttacker(self)
|
||||||
|
d:SetDamageType(DMG_FALL)
|
||||||
|
|
||||||
|
if d:GetDamage() > 0 then
|
||||||
|
ent:TakeDamageInfo(d)
|
||||||
|
|
||||||
|
self:EmitSound('physics/metal/metal_barrel_impact_soft'..math.random(1,4)..'.wav')
|
||||||
|
self:TakeDamage(10)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
timer.Simple(0.5, function()
|
||||||
|
if IsValid(self) then
|
||||||
|
self.cantdamage = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnTakeDamage(dmg)
|
||||||
|
if dmg:GetAttacker():IsPlayer() and dmg:GetAttacker():IsSurvivor() then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
self.health = self.health - dmg:GetDamage()
|
||||||
|
if self.health <= 0 then
|
||||||
|
self:EmitSound(self.TableProp[self.id].breaksound)
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.Base = "base_anim"
|
||||||
|
ENT.PrintName = "Barricade"
|
||||||
|
ENT.Category = "BWA"
|
||||||
|
ENT.Spawnable = true
|
||||||
|
|
||||||
|
if CLIENT then
|
||||||
|
function ENT:Think()
|
||||||
|
if self:GetNWBool('lamp') then
|
||||||
|
local dlight = DynamicLight( self:EntIndex() )
|
||||||
|
if ( dlight ) then
|
||||||
|
dlight.pos = self:GetPos()+Vector(0,0,16)
|
||||||
|
dlight.r = 200
|
||||||
|
dlight.g = 200
|
||||||
|
dlight.b = 255
|
||||||
|
dlight.brightness = 0.01
|
||||||
|
dlight.Decay = 1000
|
||||||
|
dlight.Size = 64
|
||||||
|
dlight.DieTime = CurTime() + 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ( IsValid( self.lamp ) ) and self:GetNWBool('lamp') then
|
||||||
|
self.lamp:SetPos( self:GetPos()+Vector(0,0,16) )
|
||||||
|
self.lamp:SetAngles( self:GetAngles()+Angle(180,0,0) )
|
||||||
|
self.lamp:Update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function ENT:OnRemove()
|
||||||
|
if ( IsValid( self.lamp ) ) then
|
||||||
|
self.lamp:Remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function ENT:Initialize()
|
||||||
|
timer.Simple(1, function()
|
||||||
|
if self:GetNWBool('lamp') then
|
||||||
|
local lamp = ProjectedTexture()
|
||||||
|
self.lamp = lamp
|
||||||
|
|
||||||
|
lamp:SetTexture( "effects/flashlight001" )
|
||||||
|
lamp:SetFarZ( 1024 )
|
||||||
|
lamp:SetColor(Color(175,175,255,255))
|
||||||
|
lamp:SetEnableShadows(true)
|
||||||
|
lamp:SetPos( self:GetPos()+Vector(0,0,16)+self:GetForward()*32 )
|
||||||
|
lamp:SetAngles( self:GetAngles()+Angle(180,0,0) )
|
||||||
|
lamp:SetNearZ(8)
|
||||||
|
lamp:Update()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
hook.Add("HUDPaint", "HPBarricadeFS", function()
|
||||||
|
local ent = LocalPlayer():GetEyeTrace().Entity
|
||||||
|
if IsValid(ent) then
|
||||||
|
local bool = ent:GetClass() == "sur_barricade"
|
||||||
|
if bool then
|
||||||
|
local pos = ent:WorldSpaceCenter():ToScreen()
|
||||||
|
local tab = {
|
||||||
|
w = 200,
|
||||||
|
h = 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
surface.SetDrawColor(0,0,0,200)
|
||||||
|
surface.DrawRect(pos.x-tab.w/2, pos.y-tab.h/2, tab.w, tab.h)
|
||||||
|
|
||||||
|
surface.SetDrawColor(25,125,25)
|
||||||
|
surface.DrawRect(pos.x-tab.w/2+4, pos.y-tab.h/2+2, (tab.w-8)*(ent:Health('health')/ent:GetNWFloat('healthmax')), tab.h-4)
|
||||||
|
|
||||||
|
draw.SimpleText("Barricade", "SuR_SmallFont1", pos.x, pos.y-20, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText(math.floor(ent:Health()).."/"..math.floor(ent:GetNWFloat('healthmax')), "Trebuchet18", pos.x, pos.y, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,311 @@
|
|||||||
|
include("shared.lua")
|
||||||
|
|
||||||
|
AddCSLuaFile("shared.lua")
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/exfil/palfa.mdl")
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetBodygroup(1, 1)
|
||||||
|
self:SetBodygroup(2, 1)
|
||||||
|
self.DeltaTime = 0
|
||||||
|
self.PickingTime = 0
|
||||||
|
self.MaxSpeed = 10000
|
||||||
|
self.CurrentSpeed = 10000
|
||||||
|
self.Mayday = false
|
||||||
|
self.Heli = true
|
||||||
|
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
phys:Wake()
|
||||||
|
phys:EnableCollisions(false)
|
||||||
|
|
||||||
|
if !istable(self.Points) or #self.Points < 5 then
|
||||||
|
self:Remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
---CREW MODELS---
|
||||||
|
|
||||||
|
if self.Heli then
|
||||||
|
local crew = ents.Create("base_anim")
|
||||||
|
crew:SetModel("models/exfil/mw22_crew_pm.mdl")
|
||||||
|
crew:SetPos(self:GetPos()+self:GetForward()*234+self:GetRight()*28+self:GetUp()*-172)
|
||||||
|
crew:SetAngles(self:GetAngles())
|
||||||
|
crew:Spawn()
|
||||||
|
crew:SetParent(self)
|
||||||
|
crew:ResetSequence("sit")
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Upperarm"), Angle(20, -60, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Forearm"), Angle(-45, 30, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Hand"), Angle(-140, 90, -30), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Calf"), Angle(0, -55, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Calf"), Angle(0, -55, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Foot"), Angle(0, 20, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Foot"), Angle(0, 20, 0), true)
|
||||||
|
self:DeleteOnRemove(crew)
|
||||||
|
|
||||||
|
local crew = ents.Create("base_anim")
|
||||||
|
crew:SetModel("models/exfil/mw22_crew_pm.mdl")
|
||||||
|
crew:SetPos(self:GetPos()+self:GetForward()*234-self:GetRight()*28+self:GetUp()*-172)
|
||||||
|
crew:SetAngles(self:GetAngles())
|
||||||
|
crew:Spawn()
|
||||||
|
crew:SetParent(self)
|
||||||
|
crew:ResetSequence("sit")
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Upperarm"), Angle(20, -60, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Forearm"), Angle(-45, 30, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Hand"), Angle(-140, 90, -30), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Calf"), Angle(0, -55, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Calf"), Angle(0, -55, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_R_Foot"), Angle(0, 20, 0), true)
|
||||||
|
crew:ManipulateBoneAngles(crew:LookupBone("ValveBiped.Bip01_L_Foot"), Angle(0, 20, 0), true)
|
||||||
|
self:DeleteOnRemove(crew)
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
self:SetPos(self.Points[1].pos)
|
||||||
|
self:SetAngles(self.Points[1].ang)
|
||||||
|
self.CurrentPoint = 2
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetPlayersInHeli()
|
||||||
|
local tab = {}
|
||||||
|
for _, ent in pairs(ents.FindInSphere(self:GetPos(), 500)) do
|
||||||
|
if ent:IsPlayer() and ent:IsSurvivor() then
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = ent:GetPos()+Vector(0,0,4),
|
||||||
|
entpos = ent:GetPos()-Vector(0,0,32),
|
||||||
|
filter = ent,
|
||||||
|
})
|
||||||
|
if tr.Entity == self or ent:GetGroundEntity() == self then
|
||||||
|
tab[#tab+1] = ent
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return tab
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Exfil()
|
||||||
|
for _, ent in ipairs(self:GetPlayersInHeli()) do
|
||||||
|
ent:GodEnable()
|
||||||
|
end
|
||||||
|
self.Skipping = false
|
||||||
|
self.Exfilling = true
|
||||||
|
self.DamageLine = CurTime()+10
|
||||||
|
self.CurrentPoint = self.CurrentPoint+1
|
||||||
|
|
||||||
|
local num = #self:GetPlayersInHeli()
|
||||||
|
if num == 0 then
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/helinone_0"..math.random(1,3)..".mp3")
|
||||||
|
elseif num == SuR:CurrentFighters(true) then
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/helileave_0"..math.random(1,3)..".mp3")
|
||||||
|
else
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/helisome_0"..math.random(1,3)..".mp3")
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(0.01, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if !IsValid(phys) then return end
|
||||||
|
phys:EnableMotion(true)
|
||||||
|
phys:AddVelocity(Vector(0,0,1))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Complete()
|
||||||
|
self.Skipping = true
|
||||||
|
if #self:GetPlayersInHeli() > 0 then
|
||||||
|
SuR.ExfilSuccess = true
|
||||||
|
for _, ply in ipairs(self:GetPlayersInHeli()) do
|
||||||
|
ply.ExfilItems = {
|
||||||
|
main = ply:GetNWString('MainWeapon'),
|
||||||
|
sec = ply:GetNWString('SecWeapon'),
|
||||||
|
melee = ply:GetNWString('MeleeWeapon'),
|
||||||
|
extra = ply:GetNWString('OtherWeapon'),
|
||||||
|
bandages = ply:GetNWFloat('Bandages'),
|
||||||
|
sprays = ply:GetNWFloat('Sprays'),
|
||||||
|
}
|
||||||
|
ply:AddXP(SuR.Config.XP_Giving["evac_success"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, ply in ipairs(player.GetAll()) do
|
||||||
|
if table.HasValue(self:GetPlayersInHeli(), ply) then
|
||||||
|
ply:KillSilent()
|
||||||
|
ply:ScreenFade(SCREENFADE.IN, color_black, 1, 1)
|
||||||
|
else
|
||||||
|
ply:SuR_MakeZombie()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if IsValid(self.CallEnt) then
|
||||||
|
self.CallEnt:SetNWBool('Ready', true)
|
||||||
|
end
|
||||||
|
hook.Call("SuR.ExfilFinished", nil, SuR.ExfilSuccess)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:KillNPC()
|
||||||
|
for _, ent in pairs(ents.FindInSphere(self:GetPos(), 400)) do
|
||||||
|
if ent:IsNPC() or ent:IsPlayer() and ent:IsZombie() then
|
||||||
|
ent:TakeDamage(100)
|
||||||
|
self:EmitSound("physics/metal/metal_barrel_impact_soft"..math.random(1,4)..".wav", 70, math.random(80,120))
|
||||||
|
if not self.DamageLine or self.DamageLine < CurTime() then
|
||||||
|
self.DamageLine = CurTime()+9
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/helihurt_0"..math.random(1,3)..".mp3")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("SuR.Helo_Exfil_Reached", "SuR_FixExfil", function(heli, point)
|
||||||
|
if point == 2 then
|
||||||
|
heli:GetPhysicsObject():EnableCollisions(true)
|
||||||
|
heli.PickingTime = CurTime()+heli.WaitTime-4
|
||||||
|
heli.DamageLine = CurTime()+12
|
||||||
|
SuR:Countdown(heli.WaitTime)
|
||||||
|
if heli.LastExfil then
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/gashurry"..math.random(1,4)..".mp3")
|
||||||
|
else
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/helihere_0"..math.random(1,3)..".mp3")
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Create("HeliExfilVoice1"..heli:EntIndex(), 8, 1, function()
|
||||||
|
if !IsValid(heli) then return end
|
||||||
|
SuR:PlaySoundOnClient("surrounded/other/pilot1/heligather_0"..math.random(1,3)..".mp3")
|
||||||
|
end)
|
||||||
|
|
||||||
|
timer.Create("HeliExfil"..heli:EntIndex(), heli.WaitTime-4, 1, function()
|
||||||
|
if !IsValid(heli) then return end
|
||||||
|
if heli.Heli then
|
||||||
|
heli:EmitSound("surrounded/vehicles/palfa/engine_start.wav")
|
||||||
|
else
|
||||||
|
heli:EmitSound("surrounded/vehicles/van/engine_start.wav")
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(4, function()
|
||||||
|
if !IsValid(heli) then return end
|
||||||
|
heli:Exfil()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
elseif point == 4 then
|
||||||
|
heli:Complete()
|
||||||
|
heli:GetPhysicsObject():EnableCollisions(false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function ENT:PhysicsCollide(col, data)
|
||||||
|
if self.Mayday then
|
||||||
|
self.Disabled = true
|
||||||
|
if self.Heli then
|
||||||
|
self:StopSound("surrounded/vehicles/palfa/engine_idle.wav")
|
||||||
|
else
|
||||||
|
self:StopSound("surrounded/vehicles/van/engine_idle.wav")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local tar = col.HitEntity
|
||||||
|
if self.CurrentPoint == 3 and tar:IsWorld() then
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:EnableMotion(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
|
||||||
|
if self.Disabled then return end
|
||||||
|
|
||||||
|
---ROTOR PART---
|
||||||
|
|
||||||
|
local bone = 63
|
||||||
|
self:ManipulateBoneAngles(bone, self:GetManipulateBoneAngles(bone)+Angle(0,10,0))
|
||||||
|
|
||||||
|
local bone = self:LookupBone("tag_tail_rotor_rot")
|
||||||
|
self:ManipulateBoneAngles(bone, self:GetManipulateBoneAngles(bone)+Angle(0,10,0))
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
---MOVE PART---
|
||||||
|
|
||||||
|
local point = self.Points[self.CurrentPoint]
|
||||||
|
self.CurrentSpeed = math.min(self.CurrentSpeed+FrameTime()/0.01, self.MaxSpeed)
|
||||||
|
|
||||||
|
if point.pos:Distance(self:GetPos()) < point.dist and (not point.wait or self.Skipping) then
|
||||||
|
hook.Run("SuR.Helo_Exfil_Reached", self, self.CurrentPoint)
|
||||||
|
timer.Simple(0.01, function()
|
||||||
|
if !IsValid(phys) then return end
|
||||||
|
phys:EnableMotion(true)
|
||||||
|
phys:AddVelocity(Vector(0,0,1))
|
||||||
|
end)
|
||||||
|
self.CurrentPoint = self.CurrentPoint+1
|
||||||
|
if self.CurrentPoint > #self.Points then
|
||||||
|
self:Remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.Skipping = false
|
||||||
|
self.CurrentSpeed = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
self:KillNPC()
|
||||||
|
|
||||||
|
if phys:IsMotionEnabled() then
|
||||||
|
if self.Mayday then
|
||||||
|
local tab = {}
|
||||||
|
tab.secondstoarrive = 1
|
||||||
|
tab.pos = self:GetPos()-Vector(0,0,100)
|
||||||
|
tab.angle = self:GetAngles()+Angle(0.01,90,0)
|
||||||
|
tab.maxangular = 5000
|
||||||
|
tab.maxangulardamp = 10000
|
||||||
|
tab.maxspeed = 1000000
|
||||||
|
tab.maxspeeddamp = 10000
|
||||||
|
tab.dampfactor = 0.5
|
||||||
|
tab.teleportdistance = 0
|
||||||
|
tab.deltatime = CurTime()-self.DeltaTime
|
||||||
|
phys:ComputeShadowControl(tab)
|
||||||
|
else
|
||||||
|
local tab = {}
|
||||||
|
tab.secondstoarrive = point.sec
|
||||||
|
tab.pos = point.pos
|
||||||
|
tab.angle = self:GetAngles()
|
||||||
|
tab.maxangular = 500
|
||||||
|
tab.maxangulardamp = 10000
|
||||||
|
tab.maxspeed = 1000000
|
||||||
|
tab.maxspeeddamp = 10000
|
||||||
|
tab.dampfactor = point.damp
|
||||||
|
tab.teleportdistance = 0
|
||||||
|
tab.deltatime = CurTime()-self.DeltaTime
|
||||||
|
phys:ComputeShadowControl(tab)
|
||||||
|
|
||||||
|
local tab = {}
|
||||||
|
tab.secondstoarrive = point.sec/5
|
||||||
|
if point.smoothrotate then
|
||||||
|
tab.secondstoarrive = point.sec
|
||||||
|
end
|
||||||
|
tab.pos = self:GetPos()
|
||||||
|
tab.angle = point.ang
|
||||||
|
tab.maxangular = 5000
|
||||||
|
tab.maxangulardamp = 10000
|
||||||
|
tab.maxspeed = 0
|
||||||
|
tab.maxspeeddamp = 0
|
||||||
|
tab.dampfactor = point.damp
|
||||||
|
tab.teleportdistance = 0
|
||||||
|
tab.deltatime = CurTime()-self.DeltaTime
|
||||||
|
phys:ComputeShadowControl(tab)
|
||||||
|
|
||||||
|
local vel = phys:GetVelocity()
|
||||||
|
vel.x = math.Clamp(vel.x, -self.CurrentSpeed, self.CurrentSpeed)
|
||||||
|
vel.y = math.Clamp(vel.y, -self.CurrentSpeed, self.CurrentSpeed)
|
||||||
|
vel.z = math.Clamp(vel.z, -self.CurrentSpeed, self.CurrentSpeed)
|
||||||
|
phys:SetVelocity(vel)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------
|
||||||
|
|
||||||
|
self.DeltaTime = CurTime()
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Exfil Vehicle"
|
||||||
|
ENT.Spawnable = true
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
|
||||||
|
if CLIENT then
|
||||||
|
function ENT:OnRemove()
|
||||||
|
if self:GetModel() == "models/exfil/deliveryvan_armored_driveable.mdl" then
|
||||||
|
self:StopSound("surrounded/vehicles/van/engine_idle.wav")
|
||||||
|
else
|
||||||
|
self:StopSound("surrounded/vehicles/palfa/engine_idle.wav")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
if self:GetModel() == "models/exfil/deliveryvan_armored_driveable.mdl" then
|
||||||
|
self:EmitSound("surrounded/vehicles/van/engine_idle.wav", 100, 95, 1, CHAN_STATIC)
|
||||||
|
else
|
||||||
|
self:EmitSound("surrounded/vehicles/palfa/engine_idle.wav", 100, 95, 1, CHAN_STATIC)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local dlight = DynamicLight(self:EntIndex())
|
||||||
|
if dlight then
|
||||||
|
dlight.pos = self:GetPos()-Vector(0,0,128)
|
||||||
|
dlight.r = 255
|
||||||
|
dlight.g = 255
|
||||||
|
dlight.b = 200
|
||||||
|
dlight.brightness = 2
|
||||||
|
dlight.decay = 1000
|
||||||
|
dlight.size = 1000
|
||||||
|
dlight.dietime = CurTime() + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local exfil_icon = Material("surrounded/exfil.png")
|
||||||
|
local last_exfil_icon = Material("surrounded/lastexfil.png")
|
||||||
|
net.Receive("SuR.ExfilIcon", function()
|
||||||
|
local bool = net.ReadBool()
|
||||||
|
local alpha = 0
|
||||||
|
local hide = false
|
||||||
|
timer.Simple(8, function()
|
||||||
|
hide = true
|
||||||
|
end)
|
||||||
|
local text = SuR.Language["evac_start"]
|
||||||
|
local mat = exfil_icon
|
||||||
|
if bool then
|
||||||
|
text = SuR.Language["evac_last_start"]
|
||||||
|
mat = last_exfil_icon
|
||||||
|
end
|
||||||
|
hook.Add("HUDPaint", "SuR_Exfil_Info", function()
|
||||||
|
if hide then
|
||||||
|
alpha = math.Clamp(alpha-FrameTime()/0.002, 0, 255)
|
||||||
|
if alpha <= 0 then
|
||||||
|
hook.Remove("HUDPaint", "SuR_Exfil_Info")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
alpha = math.Clamp(alpha+FrameTime()/0.002, 0, 255)
|
||||||
|
end
|
||||||
|
|
||||||
|
surface.SetDrawColor(255,255,255,alpha)
|
||||||
|
surface.SetMaterial(mat)
|
||||||
|
surface.DrawTexturedRect(ScrW()/2-We(100), ScrH()/2-He(350), We(200), He(200))
|
||||||
|
|
||||||
|
draw.SimpleText(text, "SuR_SmallFont2", ScrW()/2, ScrH()/2-He(140), Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
include("shared.lua")
|
||||||
|
|
||||||
|
AddCSLuaFile("shared.lua")
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/hunter/blocks/cube025x025x025.mdl")
|
||||||
|
self:SetNoDraw(true)
|
||||||
|
self:DrawShadow(false)
|
||||||
|
self:SetNWBool('Ready', true)
|
||||||
|
if !istable(DMZ_ExfilPoints[game.GetMap()][self.ID]) then
|
||||||
|
self:Remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self:SetPos(DMZ_ExfilPoints[game.GetMap()][self.ID]["Main"])
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("PlayerButtonDown", "DMZ_Exfil", function(ply, but)
|
||||||
|
local ent = nil
|
||||||
|
for _, en in ipairs(ents.FindInSphere(ply:GetPos(), 500)) do
|
||||||
|
if en:GetClass() == "dmz_exfil_point" then
|
||||||
|
ent = en
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if IsValid(ply:GetActiveWeapon()) and ply:GetActiveWeapon():GetClass() == "agrp_flare_gun" then
|
||||||
|
if but == KEY_G and IsValid(ent) and ent:GetNWBool('Ready') then
|
||||||
|
ply:GetActiveWeapon():Remove()
|
||||||
|
CallExfil(ent, ply)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function CallExfil(ent, ply)
|
||||||
|
ent:EmitSound("weapons/flaregun/fire.wav")
|
||||||
|
ent:SetNWBool('Ready', false)
|
||||||
|
|
||||||
|
net.Start("DMZ_Exfil_Info")
|
||||||
|
net.Send(ply)
|
||||||
|
|
||||||
|
BroadcastLua([[
|
||||||
|
local part = EffectData()
|
||||||
|
part:SetOrigin(Entity(]]..ply:EntIndex()..[[):GetPos()+Vector(0,0,100))
|
||||||
|
util.Effect("dmz_signal_rocket", part)
|
||||||
|
]])
|
||||||
|
|
||||||
|
local he = ents.Create("dmz_exfil_helo")
|
||||||
|
he.Caller = ply
|
||||||
|
he.Points = DMZ_ExfilPoints[game.GetMap()][ent.ID]
|
||||||
|
he.CallEnt = ent
|
||||||
|
timer.Simple(30, function()
|
||||||
|
if !IsValid(he) then return end
|
||||||
|
he:Spawn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Exfil Point"
|
||||||
|
ENT.Spawnable = true
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
|
||||||
|
if CLIENT then
|
||||||
|
local exfil_icon = Material("dmz/exfil.png", "smooth")
|
||||||
|
|
||||||
|
hook.Add("HUDPaint", "DMZ_Exfil_Point", function()
|
||||||
|
if IsValid(LocalPlayer():GetActiveWeapon()) and LocalPlayer():GetActiveWeapon():GetClass() == "agrp_flare_gun" then
|
||||||
|
for _, ent in ipairs(ents.FindByClass("dmz_exfil_point")) do
|
||||||
|
if not ent.alpha then
|
||||||
|
ent.alpha = 0
|
||||||
|
end
|
||||||
|
if ent:GetNWBool('Ready') then
|
||||||
|
local pos = ent:GetPos():ToScreen()
|
||||||
|
|
||||||
|
surface.SetDrawColor(255,255,255,ent.alpha)
|
||||||
|
surface.SetMaterial(exfil_icon)
|
||||||
|
surface.DrawTexturedRect(pos.x-36, pos.y-48, 72, 72)
|
||||||
|
|
||||||
|
local num = math.Round(LocalPlayer():GetPos():Distance(ent:GetPos()) * 2/100)
|
||||||
|
if num < 10 or num > 500 then
|
||||||
|
ent.alpha = math.Clamp(ent.alpha-FrameTime()/0.005, 0, 255)
|
||||||
|
else
|
||||||
|
ent.alpha = math.Clamp(ent.alpha+FrameTime()/0.005, 0, 255)
|
||||||
|
end
|
||||||
|
if num < 10 then
|
||||||
|
draw.SimpleText("[G] Вызвать эвакуацию", "GModToolSubtitle", ScrW()/2-20, ScrH()/2+150, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
draw.SimpleText(num.."m", "Trebuchet24", pos.x, pos.y+12, Color(255,255,255,ent.alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("DMZ_Exfil_Info", function()
|
||||||
|
local alpha = 0
|
||||||
|
local hide = false
|
||||||
|
timer.Simple(5, function()
|
||||||
|
hide = true
|
||||||
|
end)
|
||||||
|
hook.Add("HUDPaint", "DMZ_Exfil_Info", function()
|
||||||
|
if hide then
|
||||||
|
alpha = math.Clamp(alpha-FrameTime()/0.001, 0, 255)
|
||||||
|
if alpha <= 0 then
|
||||||
|
hook.Remove("HUDPaint", "DMZ_Exfil_Info")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
alpha = math.Clamp(alpha+FrameTime()/0.001, 0, 255)
|
||||||
|
end
|
||||||
|
|
||||||
|
surface.SetDrawColor(255,255,255,alpha)
|
||||||
|
surface.SetMaterial(exfil_icon)
|
||||||
|
surface.DrawTexturedRect(ScrW()/2-64, ScrH()/2-270, 128, 128)
|
||||||
|
|
||||||
|
draw.SimpleText("ЭВАКУАЦИОННЫЙ ВЕРТОЛЕТ ВЫЛЕТЕЛ", "DermaLarge", ScrW()/2, ScrH()/2-150, Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.PrintName = "Gas Zone"
|
||||||
|
ENT.Base = "base_anim"
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/hunter/blocks/cube025x025x025.mdl")
|
||||||
|
self:SetNoDraw(true)
|
||||||
|
self:SetNWFloat('radius', 1)
|
||||||
|
self.DelayGasDamage = 0
|
||||||
|
self.Dist = self.Dist or 5000
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local newnum = self:GetNWFloat('radius')+(self.Dist/120/10)
|
||||||
|
self:SetNWFloat('radius', newnum)
|
||||||
|
if self.DelayGasDamage < CurTime() then
|
||||||
|
self.DelayGasDamage = CurTime()+1
|
||||||
|
local tab = player.GetAll()
|
||||||
|
for i=1,#tab do
|
||||||
|
local ply = tab[i]
|
||||||
|
if ply:GetPos():DistToSqr(self:GetPos()) > self:GetNWFloat('radius')^2 or !ply:Alive() then continue end
|
||||||
|
if ply:Health() > 5 then
|
||||||
|
ply:TakeDamage(5, self)
|
||||||
|
else
|
||||||
|
ply:SuR_MakeZombie()
|
||||||
|
end
|
||||||
|
ply:PlayVoiceLine("infected", 20)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self:NextThink(CurTime()+0.1)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
local function create_particle(self)
|
||||||
|
local size = math.Clamp(math.random(self:GetNWFloat('radius')/2,self:GetNWFloat('radius')), 10, self:GetNWFloat('radius')/2)
|
||||||
|
local rad = self:GetNWFloat('radius')-size/2
|
||||||
|
|
||||||
|
if not self.gasEmitter then
|
||||||
|
self.gasEmitter = ParticleEmitter(self:GetPos())
|
||||||
|
end
|
||||||
|
|
||||||
|
local particles = self.gasEmitter:Add("particle/particle_smokegrenade", self:GetPos() + VectorRand(-rad, rad))
|
||||||
|
particles:SetVelocity(Vector(0, 0, 0))
|
||||||
|
particles:SetDieTime(10)
|
||||||
|
particles:SetStartAlpha(200)
|
||||||
|
particles:SetEndAlpha(0)
|
||||||
|
particles:SetStartSize(size)
|
||||||
|
particles:SetEndSize(size)
|
||||||
|
particles:SetRoll(math.Rand(-180, 180))
|
||||||
|
particles:SetRollDelta(math.Rand(-0.5, 0.5))
|
||||||
|
particles:SetColor(0,50,0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local alpha = 0
|
||||||
|
local draw_gas_effect = false
|
||||||
|
hook.Add("PostDrawTranslucentRenderables", "SuR_Zone_Draw", function()
|
||||||
|
local tab = ents.FindByClass("sur_gas_zone")
|
||||||
|
for _, ent in ipairs(tab) do
|
||||||
|
render.SetColorMaterial()
|
||||||
|
render.CullMode(1)
|
||||||
|
render.DrawSphere(ent:GetPos(), ent:GetNWFloat('radius'), 50 , 50 , Color(0,120,0,20))
|
||||||
|
render.CullMode(0)
|
||||||
|
render.DrawSphere(ent:GetPos(), ent:GetNWFloat('radius'), 50 , 50 , Color(0,120,0,20))
|
||||||
|
render.BorderSphereUnit(Color(0,120,0,200), ent:GetPos(), ent:GetNWFloat('radius'), 64, 16)
|
||||||
|
if not ent.Gas or ent.Gas < CurTime() then
|
||||||
|
ent.Gas = CurTime()+0.01
|
||||||
|
create_particle(ent)
|
||||||
|
end
|
||||||
|
draw_gas_effect = ent:GetPos():DistToSqr(LocalPlayer():GetPos()) <= ent:GetNWFloat('radius')^2 and LocalPlayer():Alive()
|
||||||
|
end
|
||||||
|
if #tab == 0 then
|
||||||
|
draw_gas_effect = false
|
||||||
|
alpha = 0
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("HUDPaint", "SuR_Zone_Draw", function()
|
||||||
|
if draw_gas_effect then
|
||||||
|
alpha = math.min(alpha+FrameTime()/0.002, 200)
|
||||||
|
else
|
||||||
|
alpha = math.max(alpha-FrameTime()/0.002, 0)
|
||||||
|
end
|
||||||
|
surface.SetDrawColor(0,80,0,alpha)
|
||||||
|
surface.DrawRect(0,0,ScrW(),ScrH())
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Generator"
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/surrounded/obj/w_QuestGenerator.mdl")
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||||
|
self:SetUseType(SIMPLE_USE)
|
||||||
|
self.FuelAmount = 0
|
||||||
|
self:SetNWBool('HaveFuel', false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Fuel()
|
||||||
|
if self:GetNWBool('HaveFuel') then return end
|
||||||
|
|
||||||
|
self.FuelAmount = self.FuelAmount + 1
|
||||||
|
SuR.ObjectiveFuel = SuR.ObjectiveFuel + 1
|
||||||
|
|
||||||
|
if SuR.ObjectiveFuel >= SuR.ObjectiveFuelNeed then
|
||||||
|
SuR:MessageOnClient(20)
|
||||||
|
timer.Simple(15, function()
|
||||||
|
SuR:StartObjectiveExfil()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.FuelAmount >= self.ToFuel then
|
||||||
|
self:SetNWBool('HaveFuel', true)
|
||||||
|
self.loop = self:StartLoopingSound("ambient/machines/diesel_engine_idle1.wav")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnRemove()
|
||||||
|
if isnumber(self.loop) then
|
||||||
|
self:StopLoopingSound(self.loop)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:EnableMotion(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Landmine"
|
||||||
|
ENT.Spawnable = true
|
||||||
|
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/surrounded/equipment/fieldupgrade_proximitymine.mdl")
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
|
||||||
|
|
||||||
|
timer.Simple(2, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:SetAngles(Angle(0,self:GetAngles().y,0))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
if CLIENT then return end
|
||||||
|
|
||||||
|
if not self.Done then
|
||||||
|
for _, ent in ipairs(ents.FindInSphere(self:GetPos(), 72)) do
|
||||||
|
if ent:IsNPC() and ent.IsZombie then
|
||||||
|
self.Done = true
|
||||||
|
self:GetPhysicsObject():SetVelocity(Vector(0,0,256))
|
||||||
|
timer.Simple(0.7, function()
|
||||||
|
local effectData = EffectData()
|
||||||
|
effectData:SetOrigin(self:GetPos())
|
||||||
|
util.Effect("Explosion", effectData)
|
||||||
|
|
||||||
|
util.BlastDamage(self, self, self:GetPos(), 192, 512)
|
||||||
|
|
||||||
|
self:Remove()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Loot"
|
||||||
|
if SERVER then
|
||||||
|
function ENT:Initialize()
|
||||||
|
if not self.LootType and not self.Weapon then
|
||||||
|
self:Remove()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local type_set = 2
|
||||||
|
local tab = LootItems[self.LootType]
|
||||||
|
|
||||||
|
if istable(self.Weapon) then
|
||||||
|
tab = self.Weapon
|
||||||
|
self:SetNWBool('Weapon', true)
|
||||||
|
|
||||||
|
local cl = tab.class
|
||||||
|
if cl then
|
||||||
|
local t = SuR.Config.TierWeapons
|
||||||
|
if table.HasValue(t["Tier1"], cl) then
|
||||||
|
type_set = 1
|
||||||
|
elseif table.HasValue(t["Tier3"], cl) or table.HasValue(t["Other"], cl) then
|
||||||
|
type_set = 3
|
||||||
|
elseif table.HasValue(t["Tier4"], cl) then
|
||||||
|
type_set = 4
|
||||||
|
elseif table.HasValue(t["Tier5"], cl) then
|
||||||
|
type_set = 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if tab.tier then
|
||||||
|
type_set = tab.tier
|
||||||
|
end
|
||||||
|
|
||||||
|
self.FuncUse = tab.usefunc
|
||||||
|
|
||||||
|
self:SetNWFloat("Type", type_set)
|
||||||
|
self:SetNWString("LootName", tab.name)
|
||||||
|
self:SetModel(tab.model)
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||||
|
self:SetUseType(SIMPLE_USE)
|
||||||
|
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:EnableMotion(true)
|
||||||
|
phys:Wake()
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(SuR.Config.Loot_Remove_Delay, function()
|
||||||
|
if !IsValid(self) or self.NoRemove then return end
|
||||||
|
|
||||||
|
self:Remove()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Use(ply)
|
||||||
|
if not istable(self.Weapon) then
|
||||||
|
if !IsValid(ply.LastPickupWeapon) then
|
||||||
|
ply.LastPickupWeapon = ply:GetActiveWeapon()
|
||||||
|
end
|
||||||
|
ply:SetActiveWeapon(nil)
|
||||||
|
timer.Create("PlyTakeAnim"..ply:EntIndex(), 1.5, 1, function()
|
||||||
|
if !IsValid(ply) or !IsValid(ply.LastPickupWeapon) then return end
|
||||||
|
|
||||||
|
local class = ply.LastPickupWeapon:GetClass()
|
||||||
|
ply:SelectWeapon(class)
|
||||||
|
ply.LastPickupWeapon = nil
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
if istable(self.Weapon) then
|
||||||
|
if self.Weapon.class and ply:HasWeapon(self.Weapon.class) then return end
|
||||||
|
self.Weapon.usefunc(self, ply)
|
||||||
|
if self.Weapon.class then
|
||||||
|
ply:SelectWeapon(self.Weapon.class)
|
||||||
|
end
|
||||||
|
if self.Weapon.class == "sur_hammer" then
|
||||||
|
SuR:ShowTips("hammer", ply)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.FuncUse(self, ply)
|
||||||
|
SuR:ShowTips("items", ply)
|
||||||
|
end
|
||||||
|
|
||||||
|
local dif = self:GetPos().z-ply:GetPos().z
|
||||||
|
if dif > 30 then
|
||||||
|
ply:SetSVAnimation("sur_itemgrab_normal", true, true)
|
||||||
|
elseif dif > 15 then
|
||||||
|
ply:SetSVAnimation("sur_itemgrab_crouch", true, true)
|
||||||
|
else
|
||||||
|
ply:SetSVAnimation("sur_itemgrab_floor", true, true)
|
||||||
|
end
|
||||||
|
ply:DropButtons()
|
||||||
|
ply:EmitSound("items/ammo_pickup.wav", 70)
|
||||||
|
ply:PlayVoiceLine("pickup")
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local arrow = Material('surrounded/arrow.png')
|
||||||
|
hook.Add("PostDrawTranslucentRenderables", "LootShow", function()
|
||||||
|
for _, self in ipairs(ents.FindByClass("sur_loot")) do
|
||||||
|
local angle = EyeAngles()
|
||||||
|
angle = Angle(angle.x, angle.y, 0)
|
||||||
|
angle:RotateAroundAxis(angle:Up(), -90)
|
||||||
|
angle:RotateAroundAxis(angle:Forward(), 90)
|
||||||
|
|
||||||
|
cam.Start3D2D(self:GetPos()+Vector(0,0,24+(math.cos(CurTime())*2)), angle, 0.1)
|
||||||
|
surface.SetMaterial(arrow)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(-32,16,64,64)
|
||||||
|
|
||||||
|
local loot = self:GetNWString("LootName", "")
|
||||||
|
local type = self:GetNWFloat("Type")
|
||||||
|
local name = SuR.Language[loot]
|
||||||
|
if not name then
|
||||||
|
name = loot
|
||||||
|
end
|
||||||
|
draw.SimpleText(name, "SuR_SmallFont2", 0, 0, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
if type > 0 and SuR.Config.Tier_Colors[type] then
|
||||||
|
draw.SimpleText(SuR.Language["loot_tier"..type], "SuR_SmallFont1", 0, 20, SuR.Config.Tier_Colors[type], TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
cam.End3D2D()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "MI24"
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
ENT.Spawnable = true
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/surrounded/mi24d.mdl")
|
||||||
|
self:SetHealth(50000)
|
||||||
|
self.Velo = {x = 0, y = 0}
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self.MultSpeed = 100
|
||||||
|
self.MaxSpeed = 100
|
||||||
|
self.Height = SuR.Config.Height_Of_Air
|
||||||
|
self.Smoking = false
|
||||||
|
self.DisableThinkPart = false
|
||||||
|
self.CantBeDamaged = true
|
||||||
|
self.RocketDelay = CurTime() + 10
|
||||||
|
self.FireDelay = CurTime() + 1
|
||||||
|
self.SeekDelay = CurTime() + 2
|
||||||
|
self.ControlDelay = CurTime() + 1
|
||||||
|
self:SetNWFloat('RemoveTime', CurTime() + 120)
|
||||||
|
self.Removing = false
|
||||||
|
self.Target = nil
|
||||||
|
self.Team = 1
|
||||||
|
self.Actions = {
|
||||||
|
["MoveForward"] = false,
|
||||||
|
["MoveBack"] = false,
|
||||||
|
["MoveLeft"] = false,
|
||||||
|
["MoveRight"] = false,
|
||||||
|
}
|
||||||
|
self:SetBodygroup(3, 1)
|
||||||
|
self:SetBodygroup(4, 1)
|
||||||
|
self:ManipulateBoneScale(10, Vector(0,0,0))
|
||||||
|
self:ManipulateBoneScale(11, Vector(0,0,0))
|
||||||
|
self:ManipulateBoneScale(7, Vector(0,0,0))
|
||||||
|
self:ManipulateBoneAngles(5, Angle(0,40,0))
|
||||||
|
timer.Simple(1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:EmitSound("ambient/levels/streetwar/heli_distant1.wav", 90, 90, 1)
|
||||||
|
end)
|
||||||
|
self:PlaySeq("arrive", 5, function()
|
||||||
|
self:EmitSound(")npc/attack_helicopter/aheli_rotor_loop1.wav", 90, 90, 1)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:PlaySeq(name, long, onfinish)
|
||||||
|
self:SetCycle(0)
|
||||||
|
self:ResetSequence(name)
|
||||||
|
self.CantBeDamaged = true
|
||||||
|
self:SetNotSolid(true)
|
||||||
|
|
||||||
|
if !isfunction(onfinish) then
|
||||||
|
onfinish = function() end
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Create("MI24Anim"..self:EntIndex(), long, 1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
self:ResetSequence("idle")
|
||||||
|
self:SetNotSolid(false)
|
||||||
|
self.CantBeDamaged = false
|
||||||
|
onfinish()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnRemove()
|
||||||
|
self:StopSound(")npc/attack_helicopter/aheli_rotor_loop1.wav")
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:GetTurretPos()
|
||||||
|
local bone = self:GetBonePosition(8)
|
||||||
|
return bone
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Rockets(angle)
|
||||||
|
if self.RocketDelay > CurTime() then return end
|
||||||
|
self.RocketDelay = CurTime()+math.random(15,30)
|
||||||
|
for i=1,8 do
|
||||||
|
timer.Simple(i/4, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
self:EmitSound(")weapons/rpg/rocketfire1.wav", 90, 90, 1)
|
||||||
|
|
||||||
|
local pos1, pos2 = self:GetPos()+self:GetRight()*100, self:GetPos()-self:GetRight()*100
|
||||||
|
local r = ents.Create("sur_mi24_rocket")
|
||||||
|
if i%2 == 0 then
|
||||||
|
r:SetPos(pos1)
|
||||||
|
else
|
||||||
|
r:SetPos(pos2)
|
||||||
|
end
|
||||||
|
r:SetAngles(angle+AngleRand(-5,5))
|
||||||
|
r.Heli = self
|
||||||
|
r:Spawn()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Attack()
|
||||||
|
local tar = self.Target
|
||||||
|
|
||||||
|
if !IsValid(tar) then
|
||||||
|
local tab = ents.FindInSphere(self:GetPos(), 32000)
|
||||||
|
table.Shuffle(tab)
|
||||||
|
for _, ent in ipairs(tab) do
|
||||||
|
if self:VisibleVec(ent:GetPos()) then
|
||||||
|
if ent:IsNPC() and ent:GetClass() != "sur_support_npc" and ent:Health() > 0 then
|
||||||
|
self.Target = ent
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if IsValid(tar) and self.FireDelay < CurTime() then
|
||||||
|
self.FireDelay = CurTime() + 0.06
|
||||||
|
|
||||||
|
if self:AngleToEnemy(tar) < 45 and self.SeekDelay < CurTime() then
|
||||||
|
local dir = (tar:WorldSpaceCenter()-self:GetTurretPos()):GetNormalized()
|
||||||
|
local ang1 = (tar:WorldSpaceCenter()-self:GetPos()):GetNormalized():Angle()
|
||||||
|
|
||||||
|
self:Rockets(ang1)
|
||||||
|
self:EmitSound("weapons/ar2/fire1.wav", 90, 80, 1, CHAN_WEAPON)
|
||||||
|
self:FireBullets({
|
||||||
|
IgnoreEntity = self,
|
||||||
|
Spread = VectorRand(-0.06, 0.06),
|
||||||
|
Damage = 30,
|
||||||
|
Dir = dir,
|
||||||
|
Src = self:GetTurretPos(),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self:VisibleVec(tar:GetPos()) or tar:Health() <= 0 then
|
||||||
|
self.ControlDelay = CurTime() + 4
|
||||||
|
self.SeekDelay = CurTime() + 0.5
|
||||||
|
self.Target = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:AngleToEnemy(enemy)
|
||||||
|
local selfAngles = self:GetAngles()
|
||||||
|
local enemyPos = enemy:GetPos()
|
||||||
|
local angleToEnemy = (enemyPos - self:GetPos()):Angle()
|
||||||
|
angleToEnemy.x = 0
|
||||||
|
angleToEnemy.z = 0
|
||||||
|
local diff = math.AngleDifference(angleToEnemy.y, selfAngles.y)
|
||||||
|
return math.abs(diff)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:RotateToEntity(ent2, divisor)
|
||||||
|
local ent1Angles = self:GetAngles()
|
||||||
|
local targetAngles = (ent2:GetPos() - self:GetPos()):Angle()
|
||||||
|
local yawDiff = math.NormalizeAngle(targetAngles.y - ent1Angles.y)
|
||||||
|
|
||||||
|
self:SetAngles(Angle(0, ent1Angles.y + yawDiff / divisor, 0))
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Controls()
|
||||||
|
local tar = self.Target
|
||||||
|
if IsValid(tar) then
|
||||||
|
if self.ControlDelay < CurTime() then
|
||||||
|
self.ControlDelay = CurTime() + math.Rand(1,5)
|
||||||
|
self.Actions = {
|
||||||
|
["MoveForward"] = math.random(1,2) == 1,
|
||||||
|
["MoveBack"] = math.random(1,6) == 1,
|
||||||
|
["MoveLeft"] = math.random(1,4) == 1,
|
||||||
|
["MoveRight"] = math.random(1,4) == 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
self:RotateToEntity(tar, 75)
|
||||||
|
else
|
||||||
|
if self.ControlDelay < CurTime() then
|
||||||
|
self.Actions = {
|
||||||
|
["MoveForward"] = false,
|
||||||
|
["MoveBack"] = false,
|
||||||
|
["MoveLeft"] = false,
|
||||||
|
["MoveRight"] = false,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local mu = self.MultSpeed
|
||||||
|
local ms = self.MaxSpeed
|
||||||
|
local vel = self:GetPhysicsObject():GetVelocity()
|
||||||
|
vel.z = 0
|
||||||
|
|
||||||
|
if not self.DisableThinkPart then
|
||||||
|
if not self.CantBeDamaged then
|
||||||
|
self:Attack()
|
||||||
|
self:Controls()
|
||||||
|
self:GetPhysicsObject():SetVelocity(-vel+self:GetForward()*self.Velo.x+self:GetRight()*self.Velo.y)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = self:GetPos()
|
||||||
|
self:SetPos(Vector(pos.x, pos.y, self.Height))
|
||||||
|
local ang = self:GetAngles().y
|
||||||
|
self:SetAngles(Angle(0,ang,0))
|
||||||
|
|
||||||
|
if self.Actions["MoveRight"] then
|
||||||
|
self.Velo.x = math.Clamp(self.Velo.x+FrameTime()*mu, -ms, ms)
|
||||||
|
elseif self.Actions["MoveLeft"] then
|
||||||
|
self.Velo.x = math.Clamp(self.Velo.x-FrameTime()*mu, -ms, ms)
|
||||||
|
end
|
||||||
|
if self.Actions["MoveForward"] then
|
||||||
|
self.Velo.y = math.Clamp(self.Velo.y-FrameTime()*mu, -ms, ms)
|
||||||
|
elseif self.Actions["MoveBack"] then
|
||||||
|
self.Velo.y = math.Clamp(self.Velo.y+FrameTime()*mu, -ms, ms)
|
||||||
|
end
|
||||||
|
if not self.Actions["MoveLeft"] and not self.Actions["MoveRight"] then
|
||||||
|
if self.Velo.x > 5 or self.Velo.x < -5 then
|
||||||
|
if self.Velo.x > 0 then
|
||||||
|
self.Velo.x = math.Clamp(self.Velo.x-FrameTime()*mu, -ms, ms)
|
||||||
|
elseif self.Velo.x < 0 then
|
||||||
|
self.Velo.x = math.Clamp(self.Velo.x+FrameTime()*mu, -ms, ms)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.Velo.x = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not self.Actions["MoveForward"] and not self.Actions["MoveBack"] then
|
||||||
|
if self.Velo.y > 5 or self.Velo.y < -5 then
|
||||||
|
if self.Velo.y > 0 then
|
||||||
|
self.Velo.y = math.Clamp(self.Velo.y-FrameTime()*mu, -ms, ms)
|
||||||
|
elseif self.Velo.y < 0 then
|
||||||
|
self.Velo.y = math.Clamp(self.Velo.y+FrameTime()*mu, -ms, ms)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.Velo.y = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self:GetNWFloat('RemoveTime') < CurTime() and not self.Removing and not self.DisableThinkPart then
|
||||||
|
self.Removing = true
|
||||||
|
self:EmitSound("ambient/levels/streetwar/heli_distant1.wav", 90, 90, 1)
|
||||||
|
self:StopSound("npc/attack_helicopter/aheli_rotor_loop1.wav")
|
||||||
|
self:PlaySeq("finish", 8, function()
|
||||||
|
self:StopSound("npc/attack_helicopter/aheli_rotor_loop1.wav")
|
||||||
|
self:Remove()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
if self:Health() <= 1000 and not self.Smoking then
|
||||||
|
self.Smoking = true
|
||||||
|
ParticleEffectAttach("Rocket_Smoke_Trail", 4, self, 2)
|
||||||
|
end
|
||||||
|
if self:Health() <= 0 then
|
||||||
|
self:DestroyHeli()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:ManipulateBoneAngles(0, Angle(0,(math.sin(CurTime())*4),(math.sin(CurTime()*2)*4)))
|
||||||
|
self:ManipulateBonePosition(0, Vector(0,0,(math.sin(CurTime())*10)))
|
||||||
|
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:OnTakeDamage(dmgt)
|
||||||
|
if self.CantBeDamaged then return end
|
||||||
|
local dmg = dmgt:GetDamage()
|
||||||
|
local att = dmgt:GetAttacker()
|
||||||
|
if att != self or att:IsPlayer() and att:Team() != self.Team then
|
||||||
|
self:SetHealth(self:Health()-dmg)
|
||||||
|
if IsValid(self:GetCreator()) then
|
||||||
|
self:GetCreator():ViewPunch(AngleRand(-1,1))
|
||||||
|
self:EmitSound("physics/metal/metal_box_impact_bullet"..math.random(1,3)..".wav")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:DestroyHeli()
|
||||||
|
self.DisableThinkPart = true
|
||||||
|
self.DestroyVelocity = 2500
|
||||||
|
self:EmitSound("tdmg/mi24/spindown.wav")
|
||||||
|
self.PhysicsCollide = function(self)
|
||||||
|
ParticleEffect("explosion_huge_h", self:GetPos()+Vector(0,0,32), Angle(0,0,0))
|
||||||
|
self:EmitSound("tdmg/a10_explosion.wav", 0)
|
||||||
|
self:StopSound("tdmg/mi24/spindown.wav")
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
self.Think = function(self)
|
||||||
|
local RPM = self.DestroyVelocity
|
||||||
|
local p = self:GetPhysicsObject()
|
||||||
|
if IsValid(p) then
|
||||||
|
local angvel = p:GetAngleVelocity()
|
||||||
|
p:AddAngleVelocity(Vector(angvel.x > 100 and 0 or RPM*0.01,0,angvel.z > 200 and 0 or math.Clamp(RPM,0,4000)*0.04))
|
||||||
|
|
||||||
|
local vel = p:GetVelocity()
|
||||||
|
p:SetVelocity(-vel-Vector(0,0,750))
|
||||||
|
end
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "MI24 Rocket"
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
ENT.Spawnable = true
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/props_phx/amraam.mdl")
|
||||||
|
self:SetSolid(SOLID_VPHYSICS)
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetModelScale(0.5, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:PhysicsCollide(data, col)
|
||||||
|
self:Explode()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Explode()
|
||||||
|
if self.Exploded then return end
|
||||||
|
self.Exploded = true
|
||||||
|
if IsValid(self.Heli) then
|
||||||
|
util.BlastDamage(self.Heli, self.Heli, self:GetPos(), 200, 200)
|
||||||
|
else
|
||||||
|
util.BlastDamage(self, self, self:GetPos(), 200, 100)
|
||||||
|
end
|
||||||
|
self:EmitSound(")ambient/explosions/explode_4.wav", 100, math.random(60,90))
|
||||||
|
local eff = EffectData()
|
||||||
|
eff:SetFlags(4)
|
||||||
|
eff:SetOrigin(self:GetPos())
|
||||||
|
util.Effect("Explosion", eff)
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
phys:SetVelocity(-phys:GetVelocity()+self:GetForward()*4000)
|
||||||
|
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
include("shared.lua")
|
||||||
|
|
||||||
|
function ENT:DrawTranslucent(flags)
|
||||||
|
self:DrawModel(flags)
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
AddCSLuaFile("cl_init.lua")
|
||||||
|
AddCSLuaFile("shared.lua")
|
||||||
|
|
||||||
|
include("shared.lua")
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Helicoper"
|
||||||
|
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||||
|
ENT.Model = Model("models/tdmg/heli.mdl")
|
||||||
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel(self.Model)
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
self:SetHealth(1)
|
||||||
|
self:SetPos(self:GetPos() + Vector(0, 0, 10))
|
||||||
|
|
||||||
|
local tr = {
|
||||||
|
start = self:GetPos(),
|
||||||
|
endpos = self:GetPos() + Vector(0, 0, 512)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tr.HitSky then
|
||||||
|
self:SetAngles(Angle(0, math.Rand(0, 360), 0))
|
||||||
|
else
|
||||||
|
local testpos = self:GetPos() + Vector(0, 0, 512)
|
||||||
|
|
||||||
|
local amt = 15
|
||||||
|
|
||||||
|
local best = 0
|
||||||
|
local best_dist = math.huge
|
||||||
|
|
||||||
|
local offset = math.Rand(0, 360)
|
||||||
|
|
||||||
|
for i = 1, amt do
|
||||||
|
local angle = math.Rand(0, 360)
|
||||||
|
|
||||||
|
local str = util.TraceLine({
|
||||||
|
start = testpos,
|
||||||
|
endpos = testpos + Angle(0, angle + offset, 0):Forward() * 10000
|
||||||
|
})
|
||||||
|
|
||||||
|
if str.HitSky then
|
||||||
|
best = angle
|
||||||
|
break
|
||||||
|
elseif str.Fraction == 1 then
|
||||||
|
best = angle
|
||||||
|
break
|
||||||
|
elseif str.Fraction * 10000 > best_dist then
|
||||||
|
best = angle
|
||||||
|
best_dist = str.Fraction * 10000
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetAngles(Angle(0, best + offset + 180 - 10, 0))
|
||||||
|
self:SetPos(self:LocalToWorld(-Vector(107.472321, -70.542793, 0)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(14, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:Finish()
|
||||||
|
end)
|
||||||
|
|
||||||
|
timer.Simple(31.6, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
self:SetRenderFX(kRenderFxFadeSlow)
|
||||||
|
end)
|
||||||
|
|
||||||
|
timer.Simple(36.6, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if CLIENT then return end
|
||||||
|
self:ResetSequence("spawn")
|
||||||
|
|
||||||
|
self.mod1, self.mod1_1 = self:CreateSoldierModel(1)
|
||||||
|
self.mod2, self.mod2_1 = self:CreateSoldierModel(2)
|
||||||
|
self.mod3, self.mod3_1 = self:CreateSoldierModel(3)
|
||||||
|
self.mod4, self.mod4_1 = self:CreateSoldierModel(4)
|
||||||
|
|
||||||
|
timer.Simple(11.5, function()
|
||||||
|
if IsValid(self.mod1) then
|
||||||
|
self:CreateSoldierNPCFromModel(1)
|
||||||
|
self.mod1:Remove()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
timer.Simple(12.5, function()
|
||||||
|
if IsValid(self.mod2) then
|
||||||
|
self:CreateSoldierNPCFromModel(2)
|
||||||
|
self.mod2:Remove()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
timer.Simple(14, function()
|
||||||
|
if IsValid(self.mod3) then
|
||||||
|
self:CreateSoldierNPCFromModel(3)
|
||||||
|
self.mod3:Remove()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Finish()
|
||||||
|
if CLIENT then return end
|
||||||
|
self:SetBodygroup(3, 1)
|
||||||
|
if IsValid(self.mod4) then
|
||||||
|
self.mod4:Remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:CreateSoldierModel(type)
|
||||||
|
local friend = ents.Create("prop_dynamic")
|
||||||
|
local friend2 = ents.Create("base_anim")
|
||||||
|
if type == 1 then
|
||||||
|
friend:SetModel("models/tdmg/guy01.mdl")
|
||||||
|
elseif type == 2 then
|
||||||
|
friend:SetModel("models/tdmg/guy02.mdl")
|
||||||
|
elseif type == 3 then
|
||||||
|
friend:SetModel("models/tdmg/guy03.mdl")
|
||||||
|
elseif type == 4 then
|
||||||
|
friend:SetModel("models/tdmg/chiefl.mdl")
|
||||||
|
end
|
||||||
|
friend:SetPos(self:GetPos())
|
||||||
|
friend:SetAngles(self:GetAngles())
|
||||||
|
friend:SetParent(self)
|
||||||
|
friend:Spawn()
|
||||||
|
friend:ResetSequence('spawn')
|
||||||
|
friend2:SetModel("models/player/swat.mdl")
|
||||||
|
friend2:SetPos(self:GetPos())
|
||||||
|
friend2:SetAngles(self:GetAngles())
|
||||||
|
friend2:SetParent(friend)
|
||||||
|
friend2:AddEffects(1)
|
||||||
|
friend2:Spawn()
|
||||||
|
return friend, friend2
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:CreateSoldierNPCFromModel(type)
|
||||||
|
local pos = self:GetPos()
|
||||||
|
local ang = self:GetAngles()
|
||||||
|
local bgs = self
|
||||||
|
if type == 1 then
|
||||||
|
pos = self:LocalToWorld(Vector(112.3, -73.6, -10))
|
||||||
|
ang = self.mod1:GetAngles()+Angle(0,180,0)
|
||||||
|
bgs = self.mod1_1
|
||||||
|
elseif type == 2 then
|
||||||
|
pos = self:LocalToWorld(Vector(66.85, -115.5, -10))
|
||||||
|
ang = self.mod2:GetAngles()+Angle(0,180,0)
|
||||||
|
bgs = self.mod2_1
|
||||||
|
elseif type == 3 then
|
||||||
|
pos = self:LocalToWorld(Vector(73.1, -40.8, -10))
|
||||||
|
ang = self.mod3:GetAngles()+Angle(0,180,0)
|
||||||
|
bgs = self.mod3_1
|
||||||
|
end
|
||||||
|
local class = "sur_support_npc"
|
||||||
|
local friend = ents.Create(class)
|
||||||
|
friend:SetPos(pos)
|
||||||
|
friend:SetAngles(ang)
|
||||||
|
friend:Spawn()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
self:NextThink(CurTime())
|
||||||
|
return true
|
||||||
|
end
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.Base = "base_gmodentity"
|
||||||
|
ENT.Type = "anim"
|
||||||
|
ENT.PrintName = "Loot"
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/props_junk/wood_crate002a.mdl")
|
||||||
|
self:PhysicsInit(SOLID_VPHYSICS)
|
||||||
|
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||||
|
self:SetUseType(SIMPLE_USE)
|
||||||
|
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS_TRIGGER)
|
||||||
|
local phys = self:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:EnableMotion(true)
|
||||||
|
phys:Wake()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Use(ply)
|
||||||
|
self:EmitSound("items/ammocrate_open.wav", 70)
|
||||||
|
ply:PlayVoiceLine("pickup")
|
||||||
|
if SuR.ActiveMutator != 7 then
|
||||||
|
for i=1, math.random(4,8) do
|
||||||
|
local class = SuR:GetRandomClass("loot")
|
||||||
|
if class != 6 then
|
||||||
|
local ent = ents.Create("sur_loot")
|
||||||
|
ent.LootType = class
|
||||||
|
ent:SetPos(self:WorldSpaceCenter())
|
||||||
|
ent:SetAngles(AngleRand())
|
||||||
|
ent:Spawn()
|
||||||
|
if IsValid(ent:GetPhysicsObject()) then
|
||||||
|
ent:GetPhysicsObject():SetVelocity(VectorRand(-250,250))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i=1, math.random(1,2) do
|
||||||
|
local class = SuR:GetRandomClass("weapon")
|
||||||
|
local weapon = nil
|
||||||
|
|
||||||
|
local tab = weapons.Get(class)
|
||||||
|
if tab then
|
||||||
|
weapon = {
|
||||||
|
name = tab.PrintName,
|
||||||
|
model = tab.WorldModel,
|
||||||
|
usefunc = function(self, ply)
|
||||||
|
ply:Give(class)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local ent = ents.Create("sur_loot")
|
||||||
|
ent.Weapon = weapon
|
||||||
|
ent:SetPos(self:WorldSpaceCenter())
|
||||||
|
ent:SetAngles(AngleRand())
|
||||||
|
ent:Spawn()
|
||||||
|
if IsValid(ent:GetPhysicsObject()) then
|
||||||
|
ent:GetPhysicsObject():SetVelocity(VectorRand(-250,250))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
SuR:MessageOnClient(18, ply:Nick())
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
AddCSLuaFile("shared.lua")
|
||||||
|
include('shared.lua')
|
||||||
|
/*-----------------------------------------------
|
||||||
|
*** Copyright (c) 2012-2022 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.StartHealth = 200
|
||||||
|
ENT.UsePlayerModelMovement = true
|
||||||
|
ENT.Model = {"models/player/swat.mdl"}
|
||||||
|
ENT.IsHuman = true
|
||||||
|
|
||||||
|
ENT.BloodColor = "Red"
|
||||||
|
|
||||||
|
ENT.VJ_NPC_Class = {"VJ_PLAYER_ALLY"}
|
||||||
|
ENT.PlayerFriendly = true
|
||||||
|
|
||||||
|
ENT.HasMeleeAttack = true
|
||||||
|
ENT.AnimTbl_MeleeAttack = {"vjseq_seq_meleeattack01"}
|
||||||
|
ENT.HasCallForHelpAnimation = false
|
||||||
|
ENT.MeleeAttackDamage = 50
|
||||||
|
|
||||||
|
ENT.FootStepTimeRun = 0.3
|
||||||
|
ENT.FootStepTimeWalk = 0.5
|
||||||
|
ENT.DropWeaponOnDeath = false
|
||||||
|
|
||||||
|
ENT.SightDistance = 3000
|
||||||
|
|
||||||
|
ENT.SoundTbl_FootStep = {"npc/footsteps/hardboot_generic1.wav","npc/footsteps/hardboot_generic2.wav","npc/footsteps/hardboot_generic3.wav","npc/footsteps/hardboot_generic4.wav","npc/footsteps/hardboot_generic5.wav","npc/footsteps/hardboot_generic6.wav","npc/footsteps/hardboot_generic8.wav"}
|
||||||
|
|
||||||
|
ENT.HasItemDropsOnDeath = false
|
||||||
|
|
||||||
|
ENT.DeathCorpseFade = true
|
||||||
|
ENT.DeathCorpseFadeTime = 120
|
||||||
|
|
||||||
|
ENT.InvestigateSoundDistance = 20
|
||||||
|
|
||||||
|
ENT.HasItemDropsOnDeath = false
|
||||||
|
ENT.DropWeaponOnDeath = false
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function ENT:CustomOnPreInitialize()
|
||||||
|
local rnd = math.random(1,4)
|
||||||
|
if rnd == 1 then
|
||||||
|
self.WaitForEnemyToComeOutTime = VJ_Set(10, 30)
|
||||||
|
elseif rnd == 2 then
|
||||||
|
self.HasGrenadeAttack = true
|
||||||
|
self.ThrowGrenadeChance = 5
|
||||||
|
elseif rnd == 3 then
|
||||||
|
self.IsMedicSNPC = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:CustomOnInitialize()
|
||||||
|
self.SearchTime = 0
|
||||||
|
self.SearchWalkTime = 0
|
||||||
|
local rnd = math.random(1,3)
|
||||||
|
if rnd == 1 then
|
||||||
|
self:Give("weapon_vj_m16a1")
|
||||||
|
elseif rnd == 2 then
|
||||||
|
self:Give("weapon_vj_spas12")
|
||||||
|
else
|
||||||
|
self:Give("weapon_vj_ssg08")
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetCustomCollisionCheck(true)
|
||||||
|
end
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ENT.Base = "npc_vj_human_base"
|
||||||
|
ENT.Type = "ai"
|
||||||
|
ENT.PrintName = "Human"
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
ENT.PrintName = "Zone"
|
||||||
|
ENT.Base = "base_anim"
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
|
||||||
|
function ENT:Initialize()
|
||||||
|
self:SetModel("models/hunter/blocks/cube025x025x025.mdl")
|
||||||
|
self:SetNoDraw(true)
|
||||||
|
self:SetNWFloat('radius', SuR.Config.Zone_Radius)
|
||||||
|
self.DelayGasDamage = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
self:SetNWFloat('radius', SuR.Config.Zone_Radius)
|
||||||
|
if self.DelayGasDamage < CurTime() then
|
||||||
|
self.DelayGasDamage = CurTime()+1
|
||||||
|
local tab = player.GetAll()
|
||||||
|
for i=1,#tab do
|
||||||
|
local ply = tab[i]
|
||||||
|
if ply:GetPos():DistToSqr(self:GetPos()) < SuR.Config.Zone_Radius^2 or !ply:Alive() then continue end
|
||||||
|
if ply:Health() > 10 then
|
||||||
|
ply:TakeDamage(10, self)
|
||||||
|
else
|
||||||
|
ply:SuR_MakeZombie()
|
||||||
|
end
|
||||||
|
ply:PlayVoiceLine("lowhp", 10)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
function ENT:Think()
|
||||||
|
if not self.GasEffect then
|
||||||
|
self.GasEffect = 0
|
||||||
|
end
|
||||||
|
if self.GasEffect < CurTime() then
|
||||||
|
self.GasEffect = CurTime()+0.5
|
||||||
|
local gasEmitter = ParticleEmitter(self:GetPos())
|
||||||
|
local radius = self:GetNWFloat('radius', 0)
|
||||||
|
if IsValid(gasEmitter) and radius > 0 then
|
||||||
|
for i=0, 360 do
|
||||||
|
local rad = radius+100
|
||||||
|
local angle = math.rad(i)
|
||||||
|
local x = rad * math.cos(angle)
|
||||||
|
local y = rad * math.sin(angle)
|
||||||
|
|
||||||
|
local particles = gasEmitter:Add("particle/particle_smokegrenade", self:GetPos() + Vector(x, y, 100))
|
||||||
|
particles:SetVelocity(Vector(0, 0, 0))
|
||||||
|
particles:SetDieTime(5)
|
||||||
|
particles:SetStartAlpha(100)
|
||||||
|
particles:SetEndAlpha(0)
|
||||||
|
particles:SetStartSize(200)
|
||||||
|
particles:SetEndSize(200)
|
||||||
|
particles:SetRoll(math.Rand(-180, 180))
|
||||||
|
particles:SetRollDelta(math.Rand(-0.5, 0.5))
|
||||||
|
particles:SetColor(0,50,0)
|
||||||
|
end
|
||||||
|
for i=0, 360, 10 do
|
||||||
|
local rad = radius+1000
|
||||||
|
local angle = math.rad(i)
|
||||||
|
local x = rad * math.cos(angle)
|
||||||
|
local y = rad * math.sin(angle)
|
||||||
|
|
||||||
|
local particles = gasEmitter:Add("particle/particle_smokegrenade", self:GetPos() + Vector(x, y, 500))
|
||||||
|
particles:SetVelocity(Vector(0, 0, 0))
|
||||||
|
particles:SetDieTime(10)
|
||||||
|
particles:SetStartAlpha(175)
|
||||||
|
particles:SetEndAlpha(0)
|
||||||
|
particles:SetStartSize(1000)
|
||||||
|
particles:SetEndSize(1000)
|
||||||
|
particles:SetRoll(math.Rand(-180, 180))
|
||||||
|
particles:SetRollDelta(math.Rand(-0.5, 0.5))
|
||||||
|
particles:SetColor(0,50,0)
|
||||||
|
end
|
||||||
|
for i=0, 360, 25 do
|
||||||
|
local rad = radius+3000
|
||||||
|
local angle = math.rad(i)
|
||||||
|
local x = rad * math.cos(angle)
|
||||||
|
local y = rad * math.sin(angle)
|
||||||
|
|
||||||
|
local particles = gasEmitter:Add("particle/particle_smokegrenade", self:GetPos() + Vector(x, y, 1500))
|
||||||
|
particles:SetVelocity(Vector(0, 0, 0))
|
||||||
|
particles:SetDieTime(10)
|
||||||
|
particles:SetStartAlpha(200)
|
||||||
|
particles:SetEndAlpha(0)
|
||||||
|
particles:SetStartSize(2500)
|
||||||
|
particles:SetEndSize(2500)
|
||||||
|
particles:SetRoll(math.Rand(-180, 180))
|
||||||
|
particles:SetRollDelta(math.Rand(-0.5, 0.5))
|
||||||
|
particles:SetColor(0,50,0)
|
||||||
|
end
|
||||||
|
gasEmitter:Finish()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
SWEP.PrintName = "Claws"
|
||||||
|
SWEP.Slot = 0
|
||||||
|
SWEP.SlotPos = 4
|
||||||
|
|
||||||
|
SWEP.Spawnable = true
|
||||||
|
|
||||||
|
SWEP.ViewModel = Model( "models/weapons/c_zombieswep.mdl" )
|
||||||
|
SWEP.WorldModel = ""
|
||||||
|
SWEP.ViewModelFOV = 90
|
||||||
|
SWEP.UseHands = true
|
||||||
|
|
||||||
|
SWEP.Primary.ClipSize = -1
|
||||||
|
SWEP.Primary.DefaultClip = -1
|
||||||
|
SWEP.Primary.Automatic = false
|
||||||
|
SWEP.Primary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.Secondary.ClipSize = -1
|
||||||
|
SWEP.Secondary.DefaultClip = -1
|
||||||
|
SWEP.Secondary.Automatic = true
|
||||||
|
SWEP.Secondary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.DrawAmmo = false
|
||||||
|
|
||||||
|
SWEP.HitDistance = 48
|
||||||
|
|
||||||
|
local SwingSound = Sound( "npc/fast_zombie/claw_miss1.wav" )
|
||||||
|
local HitSound = Sound( "npc/fast_zombie/claw_strike1.wav" )
|
||||||
|
|
||||||
|
function SWEP:Initialize()
|
||||||
|
|
||||||
|
self:SetHoldType( "fist" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:SetupDataTables()
|
||||||
|
|
||||||
|
self:NetworkVar( "Float", 0, "NextMeleeAttack" )
|
||||||
|
self:NetworkVar( "Float", 1, "NextIdle" )
|
||||||
|
self:NetworkVar( "Int", 2, "Combo" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:UpdateNextIdle()
|
||||||
|
|
||||||
|
local vm = self:GetOwner():GetViewModel()
|
||||||
|
self:SetNextIdle( CurTime() + vm:SequenceDuration() / vm:GetPlaybackRate() )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:PrimaryAttack( right )
|
||||||
|
local anim = "anim_fire"..math.random(1,4)
|
||||||
|
local owner = self:GetOwner()
|
||||||
|
|
||||||
|
local vm = owner:GetViewModel()
|
||||||
|
vm:SendViewModelMatchingSequence( vm:LookupSequence( anim ) )
|
||||||
|
|
||||||
|
self:EmitSound(SwingSound, 60, math.random(110,130), 0.5)
|
||||||
|
|
||||||
|
self:UpdateNextIdle()
|
||||||
|
self:SetNextMeleeAttack( CurTime() + 0.4 )
|
||||||
|
|
||||||
|
self:SetNextPrimaryFire( CurTime() + 1 )
|
||||||
|
|
||||||
|
if SERVER then
|
||||||
|
if owner:Crouching() then
|
||||||
|
owner:PlayFastGesture(ACT_SPECIAL_ATTACK2, true)
|
||||||
|
else
|
||||||
|
owner:PlayFastGesture(ACT_GESTURE_MELEE_ATTACK1, true)
|
||||||
|
end
|
||||||
|
owner:PlayVoiceLine("zombie_attack", 50)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:SecondaryAttack()
|
||||||
|
|
||||||
|
if CLIENT then return end
|
||||||
|
|
||||||
|
local ent = self:GetOwner()
|
||||||
|
if ent.ZombieClass == "Spitter" then
|
||||||
|
self:SetNextSecondaryFire(CurTime()+8)
|
||||||
|
ent:SetSVAnimation("range_spit", true, true, true)
|
||||||
|
timer.Simple(0.2, function()
|
||||||
|
if !IsValid(ent) or !ent:Alive() then return end
|
||||||
|
|
||||||
|
local pr = ents.Create("obj_vj_lnr_spit")
|
||||||
|
pr:SetPos(ent:EyePos()+ent:GetForward()*32)
|
||||||
|
pr:Spawn()
|
||||||
|
pr:GetPhysicsObject():SetVelocity(ent:GetAimVector()*1000+Vector(0,0,100))
|
||||||
|
timer.Simple(0.4, function()
|
||||||
|
if !IsValid(ent) or !ent:Alive() then return end
|
||||||
|
|
||||||
|
local pr = ents.Create("obj_vj_lnr_spit")
|
||||||
|
pr:SetPos(ent:EyePos()+ent:GetForward()*32)
|
||||||
|
pr:Spawn()
|
||||||
|
pr:GetPhysicsObject():SetVelocity(ent:GetAimVector()*1000+Vector(0,0,100))
|
||||||
|
timer.Simple(0.6, function()
|
||||||
|
if !IsValid(ent) or !ent:Alive() then return end
|
||||||
|
|
||||||
|
local pr = ents.Create("obj_vj_lnr_spit")
|
||||||
|
pr:SetPos(ent:EyePos()+ent:GetForward()*32)
|
||||||
|
pr:Spawn()
|
||||||
|
pr:GetPhysicsObject():SetVelocity(ent:GetAimVector()*1000+Vector(0,0,100))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
elseif ent.ZombieClass == "Hazmat" then
|
||||||
|
self:SetNextSecondaryFire(CurTime()+999)
|
||||||
|
local anim = "nz_napalm_explode_"..math.random(1,3)
|
||||||
|
local _, time = ent:LookupSequence(anim)
|
||||||
|
ent:SetSVAnimation(anim, true, true, true)
|
||||||
|
ent:EmitSound("vj_lnrspecials/explosivegasleak.wav", 80)
|
||||||
|
timer.Simple(time, function()
|
||||||
|
if !IsValid(ent) or !ent:Alive() or !IsValid(self) then return end
|
||||||
|
ParticleEffect("vj_explosion2",ent:GetPos() + ent:GetUp()*48 + ent:GetForward()*1,Angle(0,0,0),nil)
|
||||||
|
ParticleEffect("vj_explosion1",ent:GetPos() + ent:GetUp()*15,Angle(0,0,0),nil)
|
||||||
|
ParticleEffect("vj_explosionfire2",ent:GetPos() + ent:GetUp()*20,Angle(0,0,0),nil)
|
||||||
|
ParticleEffect("vj_explosionfire1",ent:GetPos() + ent:GetUp()*20,Angle(0,0,0),nil)
|
||||||
|
util.ScreenShake(ent:GetPos(),100,200,1,2500)
|
||||||
|
util.VJ_SphereDamage(ent,ent,ent:GetPos(),250,75,DMG_BLAST,false,true,{Force=100})
|
||||||
|
ent:EmitSound("ambient/explosions/explode_"..math.random(1,9)..".wav", 90)
|
||||||
|
ent:Kill()
|
||||||
|
end)
|
||||||
|
elseif ent.ZombieClass == "Evo" then
|
||||||
|
self:SetNextSecondaryFire(CurTime()+6)
|
||||||
|
ent:SetSVAnimation("jump_attack", true, true, true)
|
||||||
|
ent:SetVelocity(ent:GetAimVector()*200+Vector(0,0,600))
|
||||||
|
elseif ent.ZombieClass == "Bomber" then
|
||||||
|
self:SetNextSecondaryFire(CurTime()+10)
|
||||||
|
ent:SetSVAnimation("range_throw", true, true, true)
|
||||||
|
timer.Simple(0.6, function()
|
||||||
|
if !IsValid(ent) or !ent:Alive() then return end
|
||||||
|
|
||||||
|
local pr = ents.Create("obj_vj_grenade")
|
||||||
|
pr:SetPos(ent:EyePos()+ent:GetForward()*32)
|
||||||
|
pr:Spawn()
|
||||||
|
pr:GetPhysicsObject():SetVelocity(ent:GetAimVector()*800+Vector(0,0,100))
|
||||||
|
ent:EmitSound("vj_lnrspecials/bomber/zombine_readygrenade"..math.random(1,2)..".wav", 60)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
self:SetNextSecondaryFire(CurTime()+10)
|
||||||
|
ent:PlayVoiceLine("zombie_idle")
|
||||||
|
ent:SetSVAnimation("nz_taunt_"..math.random(1,9), true, true, true)
|
||||||
|
ent:SetHealth(math.min(ent:GetMaxHealth(), ent:Health()+25))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local phys_pushscale = GetConVar( "phys_pushscale" )
|
||||||
|
|
||||||
|
function SWEP:DealDamage()
|
||||||
|
|
||||||
|
local owner = self:GetOwner()
|
||||||
|
|
||||||
|
local anim = self:GetSequenceName(owner:GetViewModel():GetSequence())
|
||||||
|
|
||||||
|
owner:LagCompensation( true )
|
||||||
|
|
||||||
|
local tr = util.TraceLine( {
|
||||||
|
start = owner:GetShootPos(),
|
||||||
|
endpos = owner:GetShootPos() + owner:GetAimVector() * self.HitDistance,
|
||||||
|
filter = owner,
|
||||||
|
mask = MASK_SHOT_HULL
|
||||||
|
} )
|
||||||
|
|
||||||
|
if ( !IsValid( tr.Entity ) ) then
|
||||||
|
tr = util.TraceHull( {
|
||||||
|
start = owner:GetShootPos(),
|
||||||
|
endpos = owner:GetShootPos() + owner:GetAimVector() * self.HitDistance,
|
||||||
|
filter = owner,
|
||||||
|
mins = Vector( -10, -10, -8 ),
|
||||||
|
maxs = Vector( 10, 10, 8 ),
|
||||||
|
mask = MASK_SHOT_HULL
|
||||||
|
} )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We need the second part for single player because SWEP:Think is ran shared in SP
|
||||||
|
if ( tr.Hit && !( game.SinglePlayer() && CLIENT ) ) then
|
||||||
|
self:EmitSound( HitSound )
|
||||||
|
end
|
||||||
|
|
||||||
|
local hit = false
|
||||||
|
local scale = phys_pushscale:GetFloat()
|
||||||
|
|
||||||
|
if ( SERVER && IsValid( tr.Entity ) && ( tr.Entity:IsNPC() || tr.Entity:IsPlayer() || tr.Entity:Health() > 0 ) ) then
|
||||||
|
local dmginfo = DamageInfo()
|
||||||
|
|
||||||
|
local attacker = owner
|
||||||
|
if ( !IsValid( attacker ) ) then attacker = self end
|
||||||
|
dmginfo:SetAttacker( attacker )
|
||||||
|
|
||||||
|
dmginfo:SetInflictor( self )
|
||||||
|
dmginfo:SetDamage( math.random( 10, 20 ) )
|
||||||
|
|
||||||
|
if ( anim == "fists_left" ) then
|
||||||
|
dmginfo:SetDamageForce( owner:GetRight() * 4912 * scale + owner:GetForward() * 9998 * scale ) -- Yes we need those specific numbers
|
||||||
|
elseif ( anim == "fists_right" ) then
|
||||||
|
dmginfo:SetDamageForce( owner:GetRight() * -4912 * scale + owner:GetForward() * 9989 * scale )
|
||||||
|
elseif ( anim == "fists_uppercut" ) then
|
||||||
|
dmginfo:SetDamageForce( owner:GetUp() * 5158 * scale + owner:GetForward() * 10012 * scale )
|
||||||
|
dmginfo:SetDamage( math.random( 12, 24 ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
SuppressHostEvents( NULL ) -- Let the breakable gibs spawn in multiplayer on client
|
||||||
|
tr.Entity:TakeDamageInfo( dmginfo )
|
||||||
|
SuppressHostEvents( owner )
|
||||||
|
|
||||||
|
hit = true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( IsValid( tr.Entity ) ) then
|
||||||
|
local phys = tr.Entity:GetPhysicsObject()
|
||||||
|
if ( IsValid( phys ) ) then
|
||||||
|
phys:ApplyForceOffset( owner:GetAimVector() * 80 * phys:GetMass() * scale, tr.HitPos )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
if ( hit && anim != "fists_uppercut" ) then
|
||||||
|
self:SetCombo( self:GetCombo() + 1 )
|
||||||
|
else
|
||||||
|
self:SetCombo( 0 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
owner:LagCompensation( false )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:OnDrop()
|
||||||
|
|
||||||
|
self:Remove() -- You can't drop fists
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Deploy()
|
||||||
|
|
||||||
|
local speed = GetConVarNumber( "sv_defaultdeployspeed" )
|
||||||
|
|
||||||
|
local vm = self:GetOwner():GetViewModel()
|
||||||
|
vm:SendViewModelMatchingSequence( vm:LookupSequence( "fists_draw" ) )
|
||||||
|
vm:SetPlaybackRate( speed )
|
||||||
|
|
||||||
|
self:SetNextPrimaryFire( CurTime() + vm:SequenceDuration() / speed )
|
||||||
|
self:SetNextSecondaryFire( CurTime() + vm:SequenceDuration() / speed )
|
||||||
|
self:UpdateNextIdle()
|
||||||
|
|
||||||
|
if ( SERVER ) then
|
||||||
|
self:SetCombo( 0 )
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Holster()
|
||||||
|
|
||||||
|
self:SetNextMeleeAttack( 0 )
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Think()
|
||||||
|
|
||||||
|
local vm = self:GetOwner():GetViewModel()
|
||||||
|
local curtime = CurTime()
|
||||||
|
local idletime = self:GetNextIdle()
|
||||||
|
|
||||||
|
if ( idletime > 0 && CurTime() > idletime ) then
|
||||||
|
|
||||||
|
vm:SendViewModelMatchingSequence( vm:LookupSequence( "fists_idle_0" .. math.random( 1, 2 ) ) )
|
||||||
|
|
||||||
|
self:UpdateNextIdle()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local meleetime = self:GetNextMeleeAttack()
|
||||||
|
|
||||||
|
if ( meleetime > 0 && CurTime() > meleetime ) then
|
||||||
|
|
||||||
|
self:DealDamage()
|
||||||
|
|
||||||
|
self:SetNextMeleeAttack( 0 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( SERVER && CurTime() > self:GetNextPrimaryFire() + 0.1 ) then
|
||||||
|
|
||||||
|
self:SetCombo( 0 )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
SWEP.PrintName = "Jerry Can"
|
||||||
|
|
||||||
|
SWEP.Slot = 0
|
||||||
|
SWEP.SlotPos = 4
|
||||||
|
SWEP.Instructions = ""
|
||||||
|
|
||||||
|
SWEP.Spawnable = true
|
||||||
|
|
||||||
|
SWEP.ViewModel = "models/surrounded/obj/v_JerryCan.mdl"
|
||||||
|
SWEP.WorldModel = "models/surrounded/obj/w_JerryCanBlue.mdl"
|
||||||
|
SWEP.ViewModelFOV = 90
|
||||||
|
SWEP.UseHands = true
|
||||||
|
|
||||||
|
SWEP.Primary.ClipSize = -1
|
||||||
|
SWEP.Primary.DefaultClip = -1
|
||||||
|
SWEP.Primary.Automatic = false
|
||||||
|
SWEP.Primary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.Secondary.ClipSize = -1
|
||||||
|
SWEP.Secondary.DefaultClip = -1
|
||||||
|
SWEP.Secondary.Automatic = false
|
||||||
|
SWEP.Secondary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.DrawAmmo = false
|
||||||
|
|
||||||
|
function SWEP:Initialize()
|
||||||
|
self:SetHoldType("slam")
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:PrimaryAttack()
|
||||||
|
if CLIENT then return end
|
||||||
|
|
||||||
|
local ply = self:GetOwner()
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = ply:EyePos(),
|
||||||
|
endpos = ply:EyePos() + ply:GetAimVector()*64,
|
||||||
|
filter = ply,
|
||||||
|
})
|
||||||
|
local ent = tr.Entity
|
||||||
|
if IsValid(ent) and ent:GetClass() == "sur_generator" and !ent:GetNWBool('HaveFuel') then
|
||||||
|
self:SetNextPrimaryFire(CurTime()+10)
|
||||||
|
|
||||||
|
local anim = "sur_fuel_up"
|
||||||
|
local time = select(2, ply:LookupSequence(anim))
|
||||||
|
ply:SetSVAnimation(anim, true, true, true)
|
||||||
|
ply:EmitSound("surrounded/weapons/fuel/sfx_sequence_fuel.wav", 60, math.random(80,110))
|
||||||
|
ply:Freeze(true)
|
||||||
|
timer.Simple(time-0.1, function()
|
||||||
|
if !IsValid(ply) or ply:GetSVAnim() != anim then return end
|
||||||
|
ply:Freeze(false)
|
||||||
|
|
||||||
|
if !IsValid(ent) then return end
|
||||||
|
ent:Fuel()
|
||||||
|
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:Remove()
|
||||||
|
ply:AddXP(SuR.Config.XP_Giving["fuel"])
|
||||||
|
SuR:MessageOnClient(19, ply:Nick())
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:SecondaryAttack()
|
||||||
|
if CLIENT then return end
|
||||||
|
|
||||||
|
local ply = self:GetOwner()
|
||||||
|
ply:ConCommand("sur_dropweapon sur_fuel")
|
||||||
|
self:SetNextSecondaryFire(CurTime()+2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Holster()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Reload() end
|
||||||
|
|
||||||
|
if CLIENT then
|
||||||
|
local wm = ClientsideModel(SWEP.WorldModel)
|
||||||
|
wm:SetNoDraw(true)
|
||||||
|
|
||||||
|
function SWEP:DrawWorldModel()
|
||||||
|
local owner = self:GetOwner()
|
||||||
|
|
||||||
|
if IsValid(owner) then
|
||||||
|
local offsetVec = Vector(5, -4, 16)
|
||||||
|
local offsetAng = Angle(180, 90, 10)
|
||||||
|
|
||||||
|
local boneid = owner:LookupBone("ValveBiped.Bip01_R_Hand")
|
||||||
|
if !boneid then return end
|
||||||
|
|
||||||
|
local matrix = owner:GetBoneMatrix(boneid)
|
||||||
|
if !matrix then return end
|
||||||
|
|
||||||
|
local newPos, newAng = LocalToWorld(offsetVec, offsetAng, matrix:GetTranslation(), matrix:GetAngles())
|
||||||
|
|
||||||
|
wm:SetPos(newPos)
|
||||||
|
wm:SetAngles(newAng)
|
||||||
|
|
||||||
|
wm:SetupBones()
|
||||||
|
else
|
||||||
|
wm:SetPos(self:GetPos())
|
||||||
|
wm:SetAngles(self:GetAngles())
|
||||||
|
end
|
||||||
|
|
||||||
|
wm:DrawModel()
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
SWEP.PrintName = "Cade Hammer"
|
||||||
|
|
||||||
|
SWEP.Slot = 0
|
||||||
|
SWEP.SlotPos = 4
|
||||||
|
SWEP.Instructions = "LMB - Build/Repair, RMB - Unbuild, R - Drag Prop"
|
||||||
|
|
||||||
|
SWEP.Spawnable = true
|
||||||
|
|
||||||
|
SWEP.ViewModel = Model( "models/weapons/c_arms.mdl" )
|
||||||
|
SWEP.WorldModel = "models/weapons/w_buzzhammer.mdl"
|
||||||
|
SWEP.ViewModelFOV = 54
|
||||||
|
SWEP.UseHands = true
|
||||||
|
|
||||||
|
SWEP.Primary.ClipSize = -1
|
||||||
|
SWEP.Primary.DefaultClip = -1
|
||||||
|
SWEP.Primary.Automatic = true
|
||||||
|
SWEP.Primary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.Secondary.ClipSize = -1
|
||||||
|
SWEP.Secondary.DefaultClip = -1
|
||||||
|
SWEP.Secondary.Automatic = false
|
||||||
|
SWEP.Secondary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.DrawAmmo = false
|
||||||
|
|
||||||
|
SWEP.Offset = {
|
||||||
|
Pos = {Up = -5, Right = 1, Forward = 3, },
|
||||||
|
Ang = {Up = 0, Right = 0, Forward = 90,}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SWEP:DrawWorldModel()
|
||||||
|
local hand, offset, rotate
|
||||||
|
local pl = self:GetOwner()
|
||||||
|
if IsValid( pl ) then
|
||||||
|
local boneIndex = pl:LookupBone( "ValveBiped.Bip01_R_Hand" )
|
||||||
|
if boneIndex then
|
||||||
|
local pos, ang = pl:GetBonePosition( boneIndex )
|
||||||
|
pos = pos + ang:Forward() * self.Offset.Pos.Forward + ang:Right() * self.Offset.Pos.Right + ang:Up() * self.Offset.Pos.Up
|
||||||
|
ang:RotateAroundAxis( ang:Up(), self.Offset.Ang.Up)
|
||||||
|
ang:RotateAroundAxis( ang:Right(), self.Offset.Ang.Right )
|
||||||
|
ang:RotateAroundAxis( ang:Forward(), self.Offset.Ang.Forward )
|
||||||
|
self:SetRenderOrigin( pos )
|
||||||
|
self:SetRenderAngles( ang )
|
||||||
|
self:DrawModel()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:SetRenderOrigin( nil )
|
||||||
|
self:SetRenderAngles( nil )
|
||||||
|
self:DrawModel()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Initialize()
|
||||||
|
self:SetHoldType("melee")
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:PrimaryAttack()
|
||||||
|
if SERVER then
|
||||||
|
local ply = self.Owner
|
||||||
|
local tr = ply:GetEyeTrace()
|
||||||
|
if tr.HitPos:DistToSqr(ply:EyePos()) < 128^2 and IsValid(tr.Entity) and tr.Entity:GetClass() == "prop_physics" and ply:GetNWFloat('buildercost') >= 1 then
|
||||||
|
local e = tr.Entity
|
||||||
|
local tr2 = util.TraceLine({
|
||||||
|
start = tr.HitPos,
|
||||||
|
endpos = tr.HitPos+ply:GetAimVector()*16,
|
||||||
|
filter = function(ent) if !ent:IsWorld() then return end end
|
||||||
|
})
|
||||||
|
if e:GetPhysicsObject():GetMass() < 1000 and tr.Hit and tr2.Hit then
|
||||||
|
local ent = ents.Create("sur_barricade")
|
||||||
|
ent.MapCade = true
|
||||||
|
ent.id = 6
|
||||||
|
ent:SetModel(e:GetModel())
|
||||||
|
ent:SetPos(e:GetPos())
|
||||||
|
ent:SetAngles(e:GetAngles())
|
||||||
|
ent:SetSkin(e:GetSkin())
|
||||||
|
ent:SetNWEntity('builder', ply)
|
||||||
|
local mult = 1
|
||||||
|
if ply:GetPlayerClass() == "engineer" and ply:GetLevelState() >= 4 then
|
||||||
|
mult = 2
|
||||||
|
elseif ply:GetPlayerClass() == "engineer" and ply:GetLevelState() >= 3 then
|
||||||
|
mult = 1.5
|
||||||
|
elseif ply:GetPlayerClass() == "engineer" and ply:GetLevelState() >= 1 then
|
||||||
|
mult = 1.1
|
||||||
|
end
|
||||||
|
ent.health = e.Healthbefore or e:GetPhysicsObject():GetMass()*5*mult
|
||||||
|
ent.healthmax = e:GetPhysicsObject():GetMass()*5*mult
|
||||||
|
ent:Spawn()
|
||||||
|
|
||||||
|
local bolt = ents.Create("prop_dynamic")
|
||||||
|
bolt:SetModel("models/crossbow_bolt.mdl")
|
||||||
|
bolt:SetAngles(ply:EyeAngles())
|
||||||
|
bolt:SetPos(tr.HitPos-ply:GetAimVector()*4)
|
||||||
|
bolt:Spawn()
|
||||||
|
|
||||||
|
ent:DeleteOnRemove(bolt)
|
||||||
|
|
||||||
|
e:EmitSound('weapons/crowbar/crowbar_impact1.wav')
|
||||||
|
e:Remove()
|
||||||
|
|
||||||
|
ply:SetNWFloat('buildercost', ply:GetNWFloat('buildercost')-1)
|
||||||
|
ply:ViewPunch(Angle(25,25,25))
|
||||||
|
BroadcastLua([[Entity(]]..ply:EntIndex()..[[):SetAnimation( PLAYER_ATTACK1 )]])
|
||||||
|
self:SetNextPrimaryFire( CurTime() + 1 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:SecondaryAttack()
|
||||||
|
if SERVER then
|
||||||
|
local ply = self.Owner
|
||||||
|
local tr = ply:GetEyeTrace()
|
||||||
|
local tr2 = util.TraceLine( {
|
||||||
|
start = tr.HitPos,
|
||||||
|
endpos = tr.HitPos-Vector(0,0,4)
|
||||||
|
} )
|
||||||
|
if tr.HitPos:DistToSqr(ply:EyePos()) < 72^2 and tr.Entity and tr.Entity.MapCade then
|
||||||
|
local e = tr.Entity
|
||||||
|
|
||||||
|
local ent = ents.Create("prop_physics")
|
||||||
|
ent:SetModel(e:GetModel())
|
||||||
|
ent:SetPos(e:GetPos())
|
||||||
|
ent:SetAngles(e:GetAngles())
|
||||||
|
ent:SetSkin(e:GetSkin())
|
||||||
|
ent.Healthbefore = tr.Entity.health
|
||||||
|
ent:Spawn()
|
||||||
|
ent:TakeDamage(0)
|
||||||
|
ent:GetPhysicsObject():EnableMotion(true)
|
||||||
|
|
||||||
|
e:EmitSound('weapons/crowbar/crowbar_impact2.wav')
|
||||||
|
e:Remove()
|
||||||
|
|
||||||
|
ply:ViewPunch(Angle(25,25,25))
|
||||||
|
ply:SetAnimation( PLAYER_ATTACK1 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Reload()
|
||||||
|
if SERVER then
|
||||||
|
local ply = self.Owner
|
||||||
|
local tr = ply:GetEyeTrace()
|
||||||
|
local center = ply:EyePos()+ply:GetAimVector()*128
|
||||||
|
if !IsValid(self.propt) and tr.Entity and tr.Entity:GetClass() == "prop_physics" and IsValid(tr.Entity:GetPhysicsObject()) and tr.HitPos:DistToSqr(ply:EyePos()) < 72^2 and tr.Entity:GetPhysicsObject():GetMass() < 500 then
|
||||||
|
self.propt = tr.Entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:OnDrop()
|
||||||
|
if SERVER then
|
||||||
|
self.propt = nil
|
||||||
|
end
|
||||||
|
self:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Deploy()
|
||||||
|
if SERVER then
|
||||||
|
self.propt = nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Holster()
|
||||||
|
if SERVER then
|
||||||
|
self.propt = nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function RotateProp(ply, prop, x, y)
|
||||||
|
local sense = 10/1
|
||||||
|
local ang = prop:GetAngles()
|
||||||
|
ang:RotateAroundAxis(Vector(0, 0, 1), x / sense)
|
||||||
|
ang:RotateAroundAxis(Vector(0, 1, 0), y / sense)
|
||||||
|
prop:SetAngles(ang)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Think()
|
||||||
|
if SERVER then
|
||||||
|
local ply = self.Owner
|
||||||
|
if not IsValid(ply) then return end
|
||||||
|
local tr = ply:GetEyeTrace()
|
||||||
|
self:SetNWEntity('drawthis', nil)
|
||||||
|
if tr.HitPos:DistToSqr(ply:EyePos()) < 128^2 and IsValid(tr.Entity) and tr.Entity:GetClass() == "prop_physics" then
|
||||||
|
local tr2 = util.TraceLine({
|
||||||
|
start = tr.HitPos,
|
||||||
|
endpos = tr.HitPos+ply:GetAimVector()*16,
|
||||||
|
filter = function(ent) if !ent:IsWorld() then return end end
|
||||||
|
})
|
||||||
|
self:SetNWFloat('colormode', 1)
|
||||||
|
if tr2.Hit then
|
||||||
|
self:SetNWFloat('colormode', 2)
|
||||||
|
end
|
||||||
|
if tr.Entity:GetPhysicsObject():GetMass() >= 1000 then
|
||||||
|
self:SetNWFloat('colormode', 0)
|
||||||
|
end
|
||||||
|
self:SetNWEntity('drawthis', tr.Entity)
|
||||||
|
else
|
||||||
|
self:SetNWEntity('drawthis', NULL)
|
||||||
|
end
|
||||||
|
|
||||||
|
if IsValid(self.propt) then
|
||||||
|
local tr = ply:GetEyeTrace()
|
||||||
|
local center = ply:EyePos()+ply:GetAimVector()*72
|
||||||
|
if not ply:KeyDown(IN_SPEED) then
|
||||||
|
self.propt:GetPhysicsObject():EnableMotion(true)
|
||||||
|
else
|
||||||
|
self.propt:GetPhysicsObject():EnableMotion(false)
|
||||||
|
end
|
||||||
|
self.propt:GetPhysicsObject():SetVelocity((center-self.propt:GetPos())*4)
|
||||||
|
self.propt:GetPhysicsObject():SetAngleVelocity(Vector())
|
||||||
|
local ucmd = ply:GetCurrentCommand()
|
||||||
|
|
||||||
|
if ply:KeyDown(IN_WALK) then
|
||||||
|
RotateProp(ply, self.propt, ucmd:GetMouseX(), ucmd:GetMouseY())
|
||||||
|
ply:SetEyeAngles(ply.RotatePropAngWep)
|
||||||
|
else
|
||||||
|
ply.RotatePropAngWep = ply:EyeAngles()
|
||||||
|
end
|
||||||
|
if center:Distance(self.propt:GetPos()) > 72 or not ply:KeyDown(IN_RELOAD) then
|
||||||
|
self.propt:GetPhysicsObject():EnableMotion(true)
|
||||||
|
self.propt:GetPhysicsObject():SetVelocity((center-self.propt:GetPos()))
|
||||||
|
self.propt = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:DrawHUD()
|
||||||
|
draw.SimpleText(SuR.Language["hammer_parts"]..LocalPlayer():GetNWFloat('buildercost'), "SuR_MediumFont1", ScrW()/2, ScrH()-He(250), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 3, color_black)
|
||||||
|
draw.SimpleText(SuR.Language["hammer_controls"], "SuR_SmallFont1", ScrW()/2, ScrH()-He(220), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 3, color_black)
|
||||||
|
local tr = self:GetNWEntity('drawthis')
|
||||||
|
local colors = Color(200,20,20)
|
||||||
|
if self:GetNWFloat('colormode') == 1 then
|
||||||
|
colors = Color(200,200,20)
|
||||||
|
elseif self:GetNWFloat('colormode') == 2 then
|
||||||
|
colors = Color(20,200,20)
|
||||||
|
end
|
||||||
|
if IsValid(tr) then
|
||||||
|
halo.Add( {tr}, colors, 5, 5, 2 )
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
AddCSLuaFile()
|
||||||
|
|
||||||
|
SWEP.PrintName = "Landmines"
|
||||||
|
|
||||||
|
SWEP.Slot = 0
|
||||||
|
SWEP.SlotPos = 4
|
||||||
|
SWEP.Instructions = "LMB - Build, RMB - Rotate, R - Menu"
|
||||||
|
|
||||||
|
SWEP.Spawnable = true
|
||||||
|
|
||||||
|
SWEP.ViewModel = "models/surrounded/equipment/fieldupgrade_proximitymine.mdl"
|
||||||
|
SWEP.WorldModel = "models/surrounded/equipment/fieldupgrade_proximitymine.mdl"
|
||||||
|
SWEP.ViewModelFOV = 54
|
||||||
|
SWEP.UseHands = true
|
||||||
|
|
||||||
|
SWEP.Primary.ClipSize = -1
|
||||||
|
SWEP.Primary.DefaultClip = -1
|
||||||
|
SWEP.Primary.Automatic = false
|
||||||
|
SWEP.Primary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.Secondary.ClipSize = -1
|
||||||
|
SWEP.Secondary.DefaultClip = -1
|
||||||
|
SWEP.Secondary.Automatic = false
|
||||||
|
SWEP.Secondary.Ammo = "none"
|
||||||
|
|
||||||
|
SWEP.DrawAmmo = false
|
||||||
|
|
||||||
|
function SWEP:Initialize()
|
||||||
|
self:SetHoldType("slam")
|
||||||
|
self:SetNWBool('Ready', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:ReloadMine()
|
||||||
|
self:SetNWBool('Ready', false)
|
||||||
|
self:SetHoldType("normal")
|
||||||
|
self.Owner:EmitSound("buttons/combine_button1.wav")
|
||||||
|
|
||||||
|
timer.Create("ReloadMineTime"..math.random(0,99999999), 15, 1, function()
|
||||||
|
if !IsValid(self) or !IsValid(self.Owner) then return end
|
||||||
|
|
||||||
|
self:SetNWBool('Ready', true)
|
||||||
|
self:SetHoldType("slam")
|
||||||
|
self.Owner:EmitSound("buttons/combine_button_locked.wav")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:PrimaryAttack()
|
||||||
|
if SERVER then
|
||||||
|
local ply = self.Owner
|
||||||
|
if !self:GetNWBool('Ready') then return end
|
||||||
|
|
||||||
|
local ent = ents.Create("sur_landmine")
|
||||||
|
ent:SetPos(ply:EyePos()+ply:GetForward()*32)
|
||||||
|
ent:Spawn()
|
||||||
|
ent:GetPhysicsObject():SetVelocity(ply:GetAimVector()*256)
|
||||||
|
self:ReloadMine()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:SecondaryAttack()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SWEP:Reload()
|
||||||
|
end
|
||||||
|
|
||||||
|
if CLIENT then
|
||||||
|
local WorldModel = ClientsideModel(SWEP.WorldModel)
|
||||||
|
WorldModel:SetNoDraw(true)
|
||||||
|
|
||||||
|
function SWEP:DrawWorldModel()
|
||||||
|
local _Owner = self:GetOwner()
|
||||||
|
|
||||||
|
if (IsValid(_Owner)) then
|
||||||
|
local offsetVec = Vector(5, -2.7, -3.4)
|
||||||
|
local offsetAng = Angle(180, 90, 0)
|
||||||
|
|
||||||
|
local boneid = _Owner:LookupBone("ValveBiped.Bip01_R_Hand")
|
||||||
|
if !boneid then return end
|
||||||
|
|
||||||
|
local matrix = _Owner:GetBoneMatrix(boneid)
|
||||||
|
if !matrix then return end
|
||||||
|
|
||||||
|
local newPos, newAng = LocalToWorld(offsetVec, offsetAng, matrix:GetTranslation(), matrix:GetAngles())
|
||||||
|
|
||||||
|
WorldModel:SetPos(newPos)
|
||||||
|
WorldModel:SetAngles(newAng)
|
||||||
|
|
||||||
|
WorldModel:SetupBones()
|
||||||
|
else
|
||||||
|
WorldModel:SetPos(self:GetPos())
|
||||||
|
WorldModel:SetAngles(self:GetAngles())
|
||||||
|
end
|
||||||
|
|
||||||
|
if self:GetNWBool('Ready') then
|
||||||
|
WorldModel:DrawModel()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SWEP.IronSightsPos = Vector(0, 25, -12)
|
||||||
|
SWEP.IronSightsAng = Vector(10, 0, 0)
|
||||||
|
|
||||||
|
function SWEP:GetViewModelPosition(EyePos, EyeAng)
|
||||||
|
local Mul = 1.0
|
||||||
|
|
||||||
|
local Offset = self.IronSightsPos
|
||||||
|
if !self:GetNWBool('Ready') then
|
||||||
|
Offset = Vector(0,0,999)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (self.IronSightsAng) then
|
||||||
|
EyeAng = EyeAng * 1
|
||||||
|
|
||||||
|
EyeAng:RotateAroundAxis(EyeAng:Right(), self.IronSightsAng.x * Mul)
|
||||||
|
EyeAng:RotateAroundAxis(EyeAng:Up(), self.IronSightsAng.y * Mul)
|
||||||
|
EyeAng:RotateAroundAxis(EyeAng:Forward(), self.IronSightsAng.z * Mul)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Right = EyeAng:Right()
|
||||||
|
local Up = EyeAng:Up()
|
||||||
|
local Forward = EyeAng:Forward()
|
||||||
|
|
||||||
|
EyePos = EyePos + Offset.x * Right * Mul
|
||||||
|
EyePos = EyePos + Offset.y * Forward * Mul
|
||||||
|
EyePos = EyePos + Offset.z * Up * Mul
|
||||||
|
|
||||||
|
return EyePos, EyeAng
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SetupWeaponHoldTypeForAI
|
||||||
|
Desc: Sets up ACT translations from generic activities to NPC specific activies. In a seperate file to clean up the init.lua
|
||||||
|
Not all NPCs have support for all animations (for example Citizens don't have pistol animations)
|
||||||
|
This only supports the holdtypes the default NPC models can support
|
||||||
|
All of these are taken directly from IMPLEMENT_ACTTABLE() macro of the C++ weapons
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:SetupWeaponHoldTypeForAI( t )
|
||||||
|
|
||||||
|
self.ActivityTranslateAI = {}
|
||||||
|
|
||||||
|
-- Default is pistol/revolver for reasons
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE ] = ACT_IDLE_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_ANGRY ] = ACT_IDLE_ANGRY_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1 ] = ACT_RANGE_ATTACK_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD ] = ACT_RELOAD_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM ] = ACT_WALK_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM ] = ACT_RUN_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RANGE_ATTACK1 ] = ACT_GESTURE_RANGE_ATTACK_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD_LOW ] = ACT_RELOAD_PISTOL_LOW
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1_LOW ] = ACT_RANGE_ATTACK_PISTOL_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_COVER_LOW ] = ACT_COVER_PISTOL_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_AIM_LOW ] = ACT_RANGE_AIM_PISTOL_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RELOAD ] = ACT_GESTURE_RELOAD_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK ] = ACT_WALK_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN ] = ACT_RUN_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_RELAXED ] = ACT_IDLE_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_STIMULATED ] = ACT_IDLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AGITATED ] = ACT_IDLE_ANGRY_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_STEALTH ] = ACT_IDLE_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_RELAXED ] = ACT_WALK
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_STIMULATED ] = ACT_WALK_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AGITATED ] = ACT_WALK_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_STEALTH ] = ACT_WALK_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_RELAXED ] = ACT_RUN
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_STIMULATED ] = ACT_RUN_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AGITATED ] = ACT_RUN_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_STEALTH ] = ACT_RUN_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_RELAXED ] = ACT_IDLE_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_STIMULATED ] = ACT_IDLE_ANGRY_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_AGITATED ] = ACT_IDLE_ANGRY_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_STEALTH ] = ACT_IDLE_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_RELAXED ] = ACT_WALK
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_STIMULATED ] = ACT_WALK_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_AGITATED ] = ACT_WALK_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_STEALTH ] = ACT_WALK_AIM_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_RELAXED ] = ACT_RUN
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_STIMULATED ] = ACT_RUN_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_AGITATED ] = ACT_RUN_AIM_PISTOL
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_STEALTH ] = ACT_RUN_AIM_STEALTH_PISTOL
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_CROUCHIDLE_STIMULATED] = ACT_CROUCHIDLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_CROUCHIDLE_AIM_STIMULATED ] = ACT_RANGE_AIM_PISTOL_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_CROUCHIDLE_AGITATED ] = ACT_RANGE_AIM_PISTOL_LOW
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_READINESS_RELAXED_TO_STIMULATED ] = ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_READINESS_RELAXED_TO_STIMULATED_WALK ] = ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK
|
||||||
|
self.ActivityTranslateAI[ ACT_READINESS_AGITATED_TO_STIMULATED ] = ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_READINESS_STIMULATED_TO_RELAXED ] = ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED
|
||||||
|
|
||||||
|
if ( t == "ar2" || t == "smg" ) then
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1 ] = ACT_RANGE_ATTACK_AR2
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD ] = ACT_RELOAD_SMG1
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE ] = ACT_IDLE_SMG1
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_ANGRY ] = ACT_IDLE_ANGRY_SMG1
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK ] = ACT_WALK_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM ] = ACT_WALK_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_RELAXED ] = ACT_IDLE_SMG1_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_STIMULATED ] = ACT_IDLE_SMG1_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AGITATED ] = ACT_IDLE_ANGRY_SMG1
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_RELAXED ] = ACT_WALK_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_STIMULATED ] = ACT_WALK_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AGITATED ] = ACT_WALK_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_RELAXED ] = ACT_RUN_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_STIMULATED ] = ACT_RUN_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AGITATED ] = ACT_RUN_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_RELAXED ] = ACT_IDLE_SMG1_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_STIMULATED ] = ACT_IDLE_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_AGITATED ] = ACT_IDLE_ANGRY_SMG1
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_RELAXED ] = ACT_WALK_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_STIMULATED ] = ACT_WALK_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_AGITATED ] = ACT_WALK_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_RELAXED ] = ACT_RUN_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_STIMULATED ] = ACT_RUN_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_AGITATED ] = ACT_RUN_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_CROUCH ] = ACT_WALK_CROUCH_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_CROUCH_AIM ] = ACT_WALK_CROUCH_AIM_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN ] = ACT_RUN_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM ] = ACT_RUN_AIM_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_CROUCH ] = ACT_RUN_CROUCH_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_CROUCH_AIM ] = ACT_RUN_CROUCH_AIM_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RANGE_ATTACK1 ] = ACT_GESTURE_RANGE_ATTACK_AR2
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1_LOW ] = ACT_RANGE_ATTACK_SMG1_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_COVER_LOW ] = ACT_COVER_SMG1_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_AIM_LOW ] = ACT_RANGE_AIM_AR2_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD_LOW ] = ACT_RELOAD_SMG1_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RELOAD ] = ACT_GESTURE_RELOAD_SMG1
|
||||||
|
|
||||||
|
-- Extra overrides for SMG holdtype
|
||||||
|
if ( t == "smg" ) then
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1 ] = ACT_RANGE_ATTACK_SMG1
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RANGE_ATTACK1 ] = ACT_GESTURE_RANGE_ATTACK_SMG1
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_AIM_LOW ] = ACT_RANGE_AIM_SMG1_LOW
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( t == "shotgun" || t == "crossbow" ) then
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE ] = ACT_IDLE_SMG1
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1 ] = ACT_RANGE_ATTACK_SHOTGUN
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD ] = ACT_RELOAD_SHOTGUN
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK ] = ACT_WALK_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_ANGRY ] = ACT_IDLE_ANGRY_SHOTGUN
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_RELAXED ] = ACT_IDLE_SHOTGUN_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_STIMULATED ] = ACT_IDLE_SHOTGUN_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AGITATED ] = ACT_IDLE_SHOTGUN_AGITATED
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_RELAXED ] = ACT_WALK_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_STIMULATED ] = ACT_WALK_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AGITATED ] = ACT_WALK_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_RELAXED ] = ACT_RUN_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_STIMULATED ] = ACT_RUN_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AGITATED ] = ACT_RUN_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_RELAXED ] = ACT_IDLE_SMG1_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_STIMULATED ] = ACT_IDLE_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AIM_AGITATED ] = ACT_IDLE_ANGRY_SMG1
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_RELAXED ] = ACT_WALK_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_STIMULATED ] = ACT_WALK_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM_AGITATED ] = ACT_WALK_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_RELAXED ] = ACT_RUN_RIFLE_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_STIMULATED ] = ACT_RUN_AIM_RIFLE_STIMULATED
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM_AGITATED ] = ACT_RUN_AIM_RIFLE
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_AIM ] = ACT_WALK_AIM_SHOTGUN
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_CROUCH ] = ACT_WALK_CROUCH_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_CROUCH_AIM ] = ACT_WALK_CROUCH_AIM_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN ] = ACT_RUN_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_AIM ] = ACT_RUN_AIM_SHOTGUN
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_CROUCH ] = ACT_RUN_CROUCH_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_CROUCH_AIM ] = ACT_RUN_CROUCH_AIM_RIFLE
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RANGE_ATTACK1 ] = ACT_GESTURE_RANGE_ATTACK_SHOTGUN
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1_LOW ] = ACT_RANGE_ATTACK_SHOTGUN_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_RELOAD_LOW ] = ACT_RELOAD_SHOTGUN_LOW
|
||||||
|
self.ActivityTranslateAI[ ACT_GESTURE_RELOAD ] = ACT_GESTURE_RELOAD_SHOTGUN
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( t == "rpg" ) then
|
||||||
|
self.ActivityTranslateAI[ ACT_RANGE_ATTACK1 ] = ACT_RANGE_ATTACK_RPG
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_RELAXED ] = ACT_IDLE_RPG_RELAXED
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_STIMULATED ] = ACT_IDLE_ANGRY_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_AGITATED ] = ACT_IDLE_ANGRY_RPG
|
||||||
|
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE ] = ACT_IDLE_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_IDLE_ANGRY ] = ACT_IDLE_ANGRY_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK ] = ACT_WALK_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_WALK_CROUCH ] = ACT_WALK_CROUCH_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN ] = ACT_RUN_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_RUN_CROUCH ] = ACT_RUN_CROUCH_RPG
|
||||||
|
self.ActivityTranslateAI[ ACT_COVER_LOW ] = ACT_COVER_LOW_RPG
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
|
||||||
|
include( "ai_translations.lua" )
|
||||||
|
include( "sh_anim.lua" )
|
||||||
|
include( "shared.lua" )
|
||||||
|
|
||||||
|
SWEP.Slot = 0 -- Slot in the weapon selection menu
|
||||||
|
SWEP.SlotPos = 10 -- Position in the slot
|
||||||
|
SWEP.DrawAmmo = true -- Should draw the default HL2 ammo counter
|
||||||
|
SWEP.DrawCrosshair = true -- Should draw the default crosshair
|
||||||
|
SWEP.DrawWeaponInfoBox = true -- Should draw the weapon info box
|
||||||
|
SWEP.BounceWeaponIcon = true -- Should the weapon icon bounce?
|
||||||
|
SWEP.SwayScale = 1.0 -- The scale of the viewmodel sway
|
||||||
|
SWEP.BobScale = 1.0 -- The scale of the viewmodel bob
|
||||||
|
|
||||||
|
SWEP.RenderGroup = RENDERGROUP_OPAQUE
|
||||||
|
|
||||||
|
-- Override this in your SWEP to set the icon in the weapon selection
|
||||||
|
SWEP.WepSelectIcon = surface.GetTextureID( "weapons/swep" )
|
||||||
|
|
||||||
|
-- This is the corner of the speech bubble
|
||||||
|
SWEP.SpeechBubbleLid = surface.GetTextureID( "gui/speech_lid" )
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
You can draw to the HUD here - it will only draw when
|
||||||
|
the client has the weapon deployed..
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:DrawHUD()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Checks the objects before any action is taken
|
||||||
|
This is to make sure that the entities haven't been removed
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:DrawWeaponSelection( x, y, wide, tall, alpha )
|
||||||
|
|
||||||
|
-- Set us up the texture
|
||||||
|
surface.SetDrawColor( 255, 255, 255, alpha )
|
||||||
|
surface.SetTexture( self.WepSelectIcon )
|
||||||
|
|
||||||
|
-- Lets get a sin wave to make it bounce
|
||||||
|
local fsin = 0
|
||||||
|
|
||||||
|
if ( self.BounceWeaponIcon == true ) then
|
||||||
|
fsin = math.sin( CurTime() * 10 ) * 5
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Borders
|
||||||
|
y = y + 10
|
||||||
|
x = x + 10
|
||||||
|
wide = wide - 20
|
||||||
|
|
||||||
|
-- Draw that mother
|
||||||
|
surface.DrawTexturedRect( x + fsin, y - fsin, wide - fsin * 2 , ( wide / 2 ) + fsin )
|
||||||
|
|
||||||
|
-- Draw weapon info box
|
||||||
|
self:PrintWeaponInfo( x + wide + 20, y + tall * 0.95, alpha )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
This draws the weapon info box
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:PrintWeaponInfo( x, y, alpha )
|
||||||
|
|
||||||
|
if ( self.DrawWeaponInfoBox == false ) then return end
|
||||||
|
|
||||||
|
if (self.InfoMarkup == nil ) then
|
||||||
|
local str
|
||||||
|
local title_color = "<color=230,230,230,255>"
|
||||||
|
local text_color = "<color=150,150,150,255>"
|
||||||
|
|
||||||
|
str = "<font=HudSelectionText>"
|
||||||
|
if ( self.Author != "" ) then str = str .. title_color .. "Author:</color>\t" .. text_color .. self.Author .. "</color>\n" end
|
||||||
|
if ( self.Contact != "" ) then str = str .. title_color .. "Contact:</color>\t" .. text_color .. self.Contact .. "</color>\n\n" end
|
||||||
|
if ( self.Purpose != "" ) then str = str .. title_color .. "Purpose:</color>\n" .. text_color .. self.Purpose .. "</color>\n\n" end
|
||||||
|
if ( self.Instructions != "" ) then str = str .. title_color .. "Instructions:</color>\n" .. text_color .. self.Instructions .. "</color>\n" end
|
||||||
|
str = str .. "</font>"
|
||||||
|
|
||||||
|
self.InfoMarkup = markup.Parse( str, 250 )
|
||||||
|
end
|
||||||
|
|
||||||
|
surface.SetDrawColor( 60, 60, 60, alpha )
|
||||||
|
surface.SetTexture( self.SpeechBubbleLid )
|
||||||
|
|
||||||
|
surface.DrawTexturedRect( x, y - 64 - 5, 128, 64 )
|
||||||
|
draw.RoundedBox( 8, x - 5, y - 6, 260, self.InfoMarkup:GetHeight() + 18, Color( 60, 60, 60, alpha ) )
|
||||||
|
|
||||||
|
self.InfoMarkup:Draw( x + 5, y + 5, nil, nil, alpha )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:FreezeMovement()
|
||||||
|
Desc: Return true to freeze moving the view
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:FreezeMovement()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:ViewModelDrawn( viewModel )
|
||||||
|
Desc: Called straight after the viewmodel has been drawn
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:ViewModelDrawn( vm )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRestore
|
||||||
|
Desc: Called immediately after a "load"
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:OnRestore()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: CustomAmmoDisplay
|
||||||
|
Desc: Return a table
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:CustomAmmoDisplay()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: GetViewModelPosition
|
||||||
|
Desc: Allows you to re-position the view model
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:GetViewModelPosition( pos, ang )
|
||||||
|
|
||||||
|
return pos, ang
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: TranslateFOV
|
||||||
|
Desc: Allows the weapon to translate the player's FOV (clientside)
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:TranslateFOV( current_fov )
|
||||||
|
|
||||||
|
return current_fov
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DrawWorldModel
|
||||||
|
Desc: Draws the world model (not the viewmodel)
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:DrawWorldModel()
|
||||||
|
|
||||||
|
self:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DrawWorldModelTranslucent
|
||||||
|
Desc: Draws the world model (not the viewmodel)
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:DrawWorldModelTranslucent()
|
||||||
|
|
||||||
|
self:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: AdjustMouseSensitivity
|
||||||
|
Desc: Allows you to adjust the mouse sensitivity.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:AdjustMouseSensitivity()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: GetTracerOrigin
|
||||||
|
Desc: Allows you to override where the tracer comes from (in first person view)
|
||||||
|
returning anything but a vector indicates that you want the default action
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:GetTracerOrigin()
|
||||||
|
|
||||||
|
--[[
|
||||||
|
local ply = self:GetOwner()
|
||||||
|
local pos = ply:EyePos() + ply:EyeAngles():Right() * -5
|
||||||
|
return pos
|
||||||
|
--]]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: FireAnimationEvent
|
||||||
|
Desc: Allows you to override weapon animation events
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:FireAnimationEvent( pos, ang, event, options )
|
||||||
|
|
||||||
|
if ( !self.CSMuzzleFlashes ) then return end
|
||||||
|
|
||||||
|
-- CS Muzzle flashes
|
||||||
|
if ( event == 5001 or event == 5011 or event == 5021 or event == 5031 ) then
|
||||||
|
|
||||||
|
local data = EffectData()
|
||||||
|
data:SetFlags( 0 )
|
||||||
|
data:SetEntity( self.Owner:GetViewModel() )
|
||||||
|
data:SetAttachment( math.floor( ( event - 4991 ) / 10 ) )
|
||||||
|
data:SetScale( 1 )
|
||||||
|
|
||||||
|
if ( self.CSMuzzleX ) then
|
||||||
|
util.Effect( "CS_MuzzleFlash_X", data )
|
||||||
|
else
|
||||||
|
util.Effect( "CS_MuzzleFlash", data )
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
|
||||||
|
AddCSLuaFile( "cl_init.lua" )
|
||||||
|
AddCSLuaFile( "ai_translations.lua" )
|
||||||
|
AddCSLuaFile( "sh_anim.lua" )
|
||||||
|
AddCSLuaFile( "shared.lua" )
|
||||||
|
|
||||||
|
include( "ai_translations.lua" )
|
||||||
|
include( "sh_anim.lua" )
|
||||||
|
include( "shared.lua" )
|
||||||
|
|
||||||
|
SWEP.Weight = 5 -- Decides whether we should switch from/to this
|
||||||
|
SWEP.AutoSwitchTo = true -- Auto switch to if we pick it up
|
||||||
|
SWEP.AutoSwitchFrom = true -- Auto switch from if you pick up a better weapon
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRestore
|
||||||
|
Desc: The game has just been reloaded. This is usually the right place
|
||||||
|
to call the GetNW* functions to restore the script's values.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:OnRestore()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: AcceptInput
|
||||||
|
Desc: Accepts input, return true to override/accept input
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:AcceptInput( name, activator, caller, data )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: KeyValue
|
||||||
|
Desc: Called when a keyvalue is added to us
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:KeyValue( key, value )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Equip
|
||||||
|
Desc: A player or NPC has picked the weapon up
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Equip( newOwner )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: EquipAmmo
|
||||||
|
Desc: The player has picked up the weapon and has taken the ammo from it
|
||||||
|
The weapon will be removed immidiately after this call.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:EquipAmmo( newOwner )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnDrop
|
||||||
|
Desc: Weapon was dropped
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:OnDrop()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: ShouldDropOnDie
|
||||||
|
Desc: Should this weapon be dropped when its owner dies?
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:ShouldDropOnDie()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: GetCapabilities
|
||||||
|
Desc: For NPCs, returns what they should try to do with it.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:GetCapabilities()
|
||||||
|
|
||||||
|
return CAP_WEAPON_RANGE_ATTACK1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: NPCShoot_Secondary
|
||||||
|
Desc: NPC tried to fire secondary attack
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:NPCShoot_Secondary( shootPos, shootDir )
|
||||||
|
|
||||||
|
self:SecondaryAttack()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: NPCShoot_Secondary
|
||||||
|
Desc: NPC tried to fire primary attack
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:NPCShoot_Primary( shootPos, shootDir )
|
||||||
|
|
||||||
|
self:PrimaryAttack()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- These tell the NPC how to use the weapon
|
||||||
|
AccessorFunc( SWEP, "fNPCMinBurst", "NPCMinBurst" )
|
||||||
|
AccessorFunc( SWEP, "fNPCMaxBurst", "NPCMaxBurst" )
|
||||||
|
AccessorFunc( SWEP, "fNPCFireRate", "NPCFireRate" )
|
||||||
|
AccessorFunc( SWEP, "fNPCMinRestTime", "NPCMinRest" )
|
||||||
|
AccessorFunc( SWEP, "fNPCMaxRestTime", "NPCMaxRest" )
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
local ActIndex = {
|
||||||
|
[ "pistol" ] = ACT_HL2MP_IDLE_PISTOL,
|
||||||
|
[ "smg" ] = ACT_HL2MP_IDLE_SMG1,
|
||||||
|
[ "grenade" ] = ACT_HL2MP_IDLE_GRENADE,
|
||||||
|
[ "ar2" ] = ACT_HL2MP_IDLE_AR2,
|
||||||
|
[ "shotgun" ] = ACT_HL2MP_IDLE_SHOTGUN,
|
||||||
|
[ "rpg" ] = ACT_HL2MP_IDLE_RPG,
|
||||||
|
[ "physgun" ] = ACT_HL2MP_IDLE_PHYSGUN,
|
||||||
|
[ "crossbow" ] = ACT_HL2MP_IDLE_CROSSBOW,
|
||||||
|
[ "melee" ] = ACT_HL2MP_IDLE_MELEE,
|
||||||
|
[ "slam" ] = ACT_HL2MP_IDLE_SLAM,
|
||||||
|
[ "normal" ] = ACT_HL2MP_IDLE,
|
||||||
|
[ "fist" ] = ACT_HL2MP_IDLE_FIST,
|
||||||
|
[ "melee2" ] = ACT_HL2MP_IDLE_MELEE2,
|
||||||
|
[ "passive" ] = ACT_HL2MP_IDLE_PASSIVE,
|
||||||
|
[ "knife" ] = ACT_HL2MP_IDLE_KNIFE,
|
||||||
|
[ "duel" ] = ACT_HL2MP_IDLE_DUEL,
|
||||||
|
[ "camera" ] = ACT_HL2MP_IDLE_CAMERA,
|
||||||
|
[ "magic" ] = ACT_HL2MP_IDLE_MAGIC,
|
||||||
|
[ "revolver" ] = ACT_HL2MP_IDLE_REVOLVER
|
||||||
|
}
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SetWeaponHoldType
|
||||||
|
Desc: Sets up the translation table, to translate from normal
|
||||||
|
standing idle pose, to holding weapon pose.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:SetWeaponHoldType( t )
|
||||||
|
|
||||||
|
t = string.lower( t )
|
||||||
|
local index = ActIndex[ t ]
|
||||||
|
|
||||||
|
if ( index == nil ) then
|
||||||
|
Msg( "SWEP:SetWeaponHoldType - ActIndex[ \"" .. t .. "\" ] isn't set! (defaulting to normal)\n" )
|
||||||
|
t = "normal"
|
||||||
|
index = ActIndex[ t ]
|
||||||
|
end
|
||||||
|
|
||||||
|
self.ActivityTranslate = {}
|
||||||
|
self.ActivityTranslate[ ACT_MP_STAND_IDLE ] = index
|
||||||
|
self.ActivityTranslate[ ACT_MP_WALK ] = index + 1
|
||||||
|
self.ActivityTranslate[ ACT_MP_RUN ] = index + 2
|
||||||
|
self.ActivityTranslate[ ACT_MP_CROUCH_IDLE ] = index + 3
|
||||||
|
self.ActivityTranslate[ ACT_MP_CROUCHWALK ] = index + 4
|
||||||
|
self.ActivityTranslate[ ACT_MP_ATTACK_STAND_PRIMARYFIRE ] = index + 5
|
||||||
|
self.ActivityTranslate[ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE ] = index + 5
|
||||||
|
self.ActivityTranslate[ ACT_MP_RELOAD_STAND ] = index + 6
|
||||||
|
self.ActivityTranslate[ ACT_MP_RELOAD_CROUCH ] = index + 6
|
||||||
|
self.ActivityTranslate[ ACT_MP_JUMP ] = index + 7
|
||||||
|
self.ActivityTranslate[ ACT_RANGE_ATTACK1 ] = index + 8
|
||||||
|
self.ActivityTranslate[ ACT_MP_SWIM ] = index + 9
|
||||||
|
|
||||||
|
-- "normal" jump animation doesn't exist
|
||||||
|
if ( t == "normal" ) then
|
||||||
|
self.ActivityTranslate[ ACT_MP_JUMP ] = ACT_HL2MP_JUMP_SLAM
|
||||||
|
end
|
||||||
|
|
||||||
|
self:SetupWeaponHoldTypeForAI( t )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Default hold pos is the pistol
|
||||||
|
SWEP:SetWeaponHoldType( "pistol" )
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: weapon:TranslateActivity()
|
||||||
|
Desc: Translate a player's Activity into a weapon's activity
|
||||||
|
So for example, ACT_HL2MP_RUN becomes ACT_HL2MP_RUN_PISTOL
|
||||||
|
Depending on how you want the player to be holding the weapon
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:TranslateActivity( act )
|
||||||
|
|
||||||
|
if ( self.Owner:IsNPC() ) then
|
||||||
|
if ( self.ActivityTranslateAI[ act ] ) then
|
||||||
|
return self.ActivityTranslateAI[ act ]
|
||||||
|
end
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
|
||||||
|
if ( self.ActivityTranslate[ act ] != nil ) then
|
||||||
|
return self.ActivityTranslate[ act ]
|
||||||
|
end
|
||||||
|
|
||||||
|
return -1
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
|
||||||
|
-- Variables that are used on both client and server
|
||||||
|
|
||||||
|
SWEP.PrintName = "Scripted Weapon" -- 'Nice' Weapon name (Shown on HUD)
|
||||||
|
SWEP.Author = ""
|
||||||
|
SWEP.Contact = ""
|
||||||
|
SWEP.Purpose = ""
|
||||||
|
SWEP.Instructions = ""
|
||||||
|
|
||||||
|
SWEP.ViewModelFOV = 62
|
||||||
|
SWEP.ViewModelFlip = false
|
||||||
|
SWEP.ViewModel = "models/weapons/v_pistol.mdl"
|
||||||
|
SWEP.WorldModel = "models/weapons/w_357.mdl"
|
||||||
|
|
||||||
|
SWEP.Spawnable = false
|
||||||
|
SWEP.AdminOnly = false
|
||||||
|
|
||||||
|
SWEP.Primary.ClipSize = 8 -- Size of a clip
|
||||||
|
SWEP.Primary.DefaultClip = 32 -- Default number of bullets in a clip
|
||||||
|
SWEP.Primary.Automatic = false -- Automatic/Semi Auto
|
||||||
|
SWEP.Primary.Ammo = "Pistol"
|
||||||
|
|
||||||
|
SWEP.Secondary.ClipSize = 8 -- Size of a clip
|
||||||
|
SWEP.Secondary.DefaultClip = 32 -- Default number of bullets in a clip
|
||||||
|
SWEP.Secondary.Automatic = false -- Automatic/Semi Auto
|
||||||
|
SWEP.Secondary.Ammo = "Pistol"
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:Initialize()
|
||||||
|
Desc: Called when the weapon is first loaded
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Initialize()
|
||||||
|
|
||||||
|
self:SetHoldType( "pistol" )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:PrimaryAttack()
|
||||||
|
Desc: +attack1 has been pressed
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:PrimaryAttack()
|
||||||
|
|
||||||
|
-- Make sure we can shoot first
|
||||||
|
if ( !self:CanPrimaryAttack() ) then return end
|
||||||
|
|
||||||
|
-- Play shoot sound
|
||||||
|
self:EmitSound( "Weapon_AR2.Single" )
|
||||||
|
|
||||||
|
-- Shoot 9 bullets, 150 damage, 0.75 aimcone
|
||||||
|
self:ShootBullet( 150, 1, 0.01, self.Primary.Ammo )
|
||||||
|
|
||||||
|
-- Remove 1 bullet from our clip
|
||||||
|
self:TakePrimaryAmmo( 1 )
|
||||||
|
|
||||||
|
-- Punch the player's view
|
||||||
|
if ( !self.Owner:IsNPC() ) then self.Owner:ViewPunch( Angle( -1, 0, 0 ) ) end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:SecondaryAttack()
|
||||||
|
Desc: +attack2 has been pressed
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:SecondaryAttack()
|
||||||
|
|
||||||
|
-- Make sure we can shoot first
|
||||||
|
if ( !self:CanSecondaryAttack() ) then return end
|
||||||
|
|
||||||
|
-- Play shoot sound
|
||||||
|
self:EmitSound("Weapon_Shotgun.Single")
|
||||||
|
|
||||||
|
-- Shoot 9 bullets, 150 damage, 0.75 aimcone
|
||||||
|
self:ShootBullet( 150, 9, 0.2, self.Secondary.Ammo )
|
||||||
|
|
||||||
|
-- Remove 1 bullet from our clip
|
||||||
|
self:TakeSecondaryAmmo( 1 )
|
||||||
|
|
||||||
|
-- Punch the player's view
|
||||||
|
if ( !self.Owner:IsNPC() ) then self.Owner:ViewPunch( Angle( -10, 0, 0 ) ) end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:Reload()
|
||||||
|
Desc: Reload is being pressed
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Reload()
|
||||||
|
self:DefaultReload( ACT_VM_RELOAD )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:Think()
|
||||||
|
Desc: Called every frame
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Think()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:Holster( weapon_to_swap_to )
|
||||||
|
Desc: Weapon wants to holster
|
||||||
|
RetV: Return true to allow the weapon to holster
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Holster( wep )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:Deploy()
|
||||||
|
Desc: Whip it out
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Deploy()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:ShootEffects()
|
||||||
|
Desc: A convenience function to create shoot effects
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:ShootEffects()
|
||||||
|
|
||||||
|
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) -- View model animation
|
||||||
|
self.Owner:MuzzleFlash() -- Crappy muzzle light
|
||||||
|
self.Owner:SetAnimation( PLAYER_ATTACK1 ) -- 3rd Person Animation
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:ShootBullet()
|
||||||
|
Desc: A convenience function to shoot bullets
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:ShootBullet( damage, num_bullets, aimcone, ammo_type, force, tracer )
|
||||||
|
|
||||||
|
local bullet = {}
|
||||||
|
bullet.Num = num_bullets
|
||||||
|
bullet.Src = self.Owner:GetShootPos() -- Source
|
||||||
|
bullet.Dir = self.Owner:GetAimVector() -- Dir of bullet
|
||||||
|
bullet.Spread = Vector( aimcone, aimcone, 0 ) -- Aim Cone
|
||||||
|
bullet.Tracer = tracer || 5 -- Show a tracer on every x bullets
|
||||||
|
bullet.Force = force || 1 -- Amount of force to give to phys objects
|
||||||
|
bullet.Damage = damage
|
||||||
|
bullet.AmmoType = ammo_type || self.Primary.Ammo
|
||||||
|
|
||||||
|
self.Owner:FireBullets( bullet )
|
||||||
|
|
||||||
|
self:ShootEffects()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:TakePrimaryAmmo()
|
||||||
|
Desc: A convenience function to remove ammo
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:TakePrimaryAmmo( num )
|
||||||
|
|
||||||
|
-- Doesn't use clips
|
||||||
|
if ( self:Clip1() <= 0 ) then
|
||||||
|
|
||||||
|
if ( self:Ammo1() <= 0 ) then return end
|
||||||
|
|
||||||
|
self.Owner:RemoveAmmo( num, self:GetPrimaryAmmoType() )
|
||||||
|
|
||||||
|
return end
|
||||||
|
|
||||||
|
self:SetClip1( self:Clip1() - num )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:TakeSecondaryAmmo()
|
||||||
|
Desc: A convenience function to remove ammo
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:TakeSecondaryAmmo( num )
|
||||||
|
|
||||||
|
-- Doesn't use clips
|
||||||
|
if ( self:Clip2() <= 0 ) then
|
||||||
|
|
||||||
|
if ( self:Ammo2() <= 0 ) then return end
|
||||||
|
|
||||||
|
self.Owner:RemoveAmmo( num, self:GetSecondaryAmmoType() )
|
||||||
|
|
||||||
|
return end
|
||||||
|
|
||||||
|
self:SetClip2( self:Clip2() - num )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:CanPrimaryAttack()
|
||||||
|
Desc: Helper function for checking for no ammo
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:CanPrimaryAttack()
|
||||||
|
|
||||||
|
if ( self:Clip1() <= 0 ) then
|
||||||
|
|
||||||
|
self:EmitSound( "Weapon_Pistol.Empty" )
|
||||||
|
self:SetNextPrimaryFire( CurTime() + 0.2 )
|
||||||
|
self:Reload()
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SWEP:CanSecondaryAttack()
|
||||||
|
Desc: Helper function for checking for no ammo
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:CanSecondaryAttack()
|
||||||
|
|
||||||
|
if ( self:Clip2() <= 0 ) then
|
||||||
|
|
||||||
|
self:EmitSound( "Weapon_Pistol.Empty" )
|
||||||
|
self:SetNextSecondaryFire( CurTime() + 0.2 )
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OnRemove
|
||||||
|
Desc: Called just before entity is deleted
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:OnRemove()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: OwnerChanged
|
||||||
|
Desc: When weapon is dropped or picked up by a new player
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:OwnerChanged()
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Ammo1
|
||||||
|
Desc: Returns how much of ammo1 the player has
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Ammo1()
|
||||||
|
return self.Owner:GetAmmoCount( self:GetPrimaryAmmoType() )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: Ammo2
|
||||||
|
Desc: Returns how much of ammo2 the player has
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:Ammo2()
|
||||||
|
return self.Owner:GetAmmoCount( self:GetSecondaryAmmoType() )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: SetDeploySpeed
|
||||||
|
Desc: Sets the weapon deploy speed.
|
||||||
|
This value needs to match on client and server.
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:SetDeploySpeed( speed )
|
||||||
|
self.m_WeaponDeploySpeed = tonumber( speed )
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[---------------------------------------------------------
|
||||||
|
Name: DoImpactEffect
|
||||||
|
Desc: Callback so the weapon can override the impact effects it makes
|
||||||
|
return true to not do the default thing - which is to call UTIL_ImpactTrace in c++
|
||||||
|
-----------------------------------------------------------]]
|
||||||
|
function SWEP:DoImpactEffect( tr, nDamageType )
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
function We(x)
|
||||||
|
return x/1920*ScrW()
|
||||||
|
end
|
||||||
|
|
||||||
|
function He(y)
|
||||||
|
return y/1080*ScrH()
|
||||||
|
end
|
||||||
|
|
||||||
|
include('shared.lua')
|
||||||
|
include('client/cl_hud.lua')
|
||||||
|
include('client/cl_menu.lua')
|
||||||
|
include("client/cl_abilities.lua")
|
||||||
|
include("client/cl_cutscenes.lua")
|
||||||
|
include("client/cl_outline.lua")
|
||||||
|
include("client/cl_other.lua")
|
||||||
|
include("client/cl_buymenu.lua")
|
||||||
@@ -0,0 +1,699 @@
|
|||||||
|
local meta = FindMetaTable("Player")
|
||||||
|
|
||||||
|
net.Receive("SuR.ClientRunString", function()
|
||||||
|
local str = net.ReadString()
|
||||||
|
RunString(str)
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.PlaySoundOnClient", function()
|
||||||
|
local str = net.ReadString()
|
||||||
|
if string.match(str, "https://") then
|
||||||
|
sound.PlayURL(str, "", function(st)
|
||||||
|
if IsValid(st) then
|
||||||
|
st:Play()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
surface.PlaySound(str)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function SuR:GetRandomSound(path)
|
||||||
|
local fil, dir = file.Find("sound/"..path.."*", "GAME")
|
||||||
|
if #fil > 0 then
|
||||||
|
local snd = path..fil[math.random(1,#fil)]
|
||||||
|
return snd
|
||||||
|
else
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:PlayVoiceLine(type, chance)
|
||||||
|
if chance and chance < math.random(1,100) then return end
|
||||||
|
|
||||||
|
local snd = ""
|
||||||
|
local nodelay = false
|
||||||
|
local death = !self:Alive()
|
||||||
|
local voice = self:GetNWString("VoicePack")
|
||||||
|
local tab = SuR.Config.VoicePacks[voice]
|
||||||
|
if istable(tab) then
|
||||||
|
if type == "pain" then
|
||||||
|
snd = SuR:GetRandomSound(tab["pain"])
|
||||||
|
nodelay = true
|
||||||
|
elseif type == "death" then
|
||||||
|
snd = SuR:GetRandomSound(tab["death"])
|
||||||
|
nodelay = true
|
||||||
|
death = false
|
||||||
|
elseif type == "reload" then
|
||||||
|
snd = SuR:GetRandomSound(tab["reload"])
|
||||||
|
elseif type == "enemyback" then
|
||||||
|
snd = SuR:GetRandomSound(tab["enemyback"])
|
||||||
|
nodelay = true
|
||||||
|
elseif type == "enemydown" then
|
||||||
|
snd = SuR:GetRandomSound(tab["enemydown"])
|
||||||
|
elseif type == "pickup" then
|
||||||
|
snd = SuR:GetRandomSound(tab["pickup"])
|
||||||
|
elseif type == "noammo" then
|
||||||
|
snd = SuR:GetRandomSound(tab["noammo"])
|
||||||
|
elseif type == "downed" then
|
||||||
|
snd = SuR:GetRandomSound(tab["downed"])
|
||||||
|
nodelay = true
|
||||||
|
elseif type == "friendlyfire" then
|
||||||
|
snd = SuR:GetRandomSound(tab["friendlyfire"])
|
||||||
|
elseif type == "frienddied" then
|
||||||
|
snd = SuR:GetRandomSound(tab["frienddied"])
|
||||||
|
elseif type == "lowhp" then
|
||||||
|
snd = SuR:GetRandomSound(tab["lowhp"])
|
||||||
|
elseif type == "infected" then
|
||||||
|
snd = SuR:GetRandomSound(tab["infected"])
|
||||||
|
nodelay = true
|
||||||
|
elseif type == "enemyspotted" then
|
||||||
|
snd = SuR:GetRandomSound(tab["enemyspotted"])
|
||||||
|
nodelay = true
|
||||||
|
elseif type == "thanks" then
|
||||||
|
snd = SuR:GetRandomSound(tab["thanks"])
|
||||||
|
elseif type == "cover" then
|
||||||
|
snd = SuR:GetRandomSound(tab["cover"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if type == "zombie_death" then
|
||||||
|
local str = "vj_lnrhl2/walker_male/die0"..math.random(1,5)..".wav"
|
||||||
|
snd = str
|
||||||
|
nodelay = true
|
||||||
|
death = false
|
||||||
|
elseif type == "zombie_idle" then
|
||||||
|
local str = "vj_lnrhl2/infected/zomb_runner_male1-idle-0"..math.random(1,9)..".wav"
|
||||||
|
snd = str
|
||||||
|
elseif type == "zombie_attack" then
|
||||||
|
local rnd = math.random(1,22)
|
||||||
|
local str = "vj_lnrhl2/walker_male/attack_sham_m_"
|
||||||
|
if rnd > 9 then
|
||||||
|
str = str..rnd..".wav"
|
||||||
|
else
|
||||||
|
str = str.."0"..rnd..".wav"
|
||||||
|
end
|
||||||
|
snd = str
|
||||||
|
snd = str
|
||||||
|
elseif type == "zombie_pain" then
|
||||||
|
local str = "vj_lnrhl2/walker_male/pain0"..math.random(1,5)..".wav"
|
||||||
|
snd = str
|
||||||
|
nodelay = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if death then return end
|
||||||
|
|
||||||
|
if not self.PreviousVoiceLine then
|
||||||
|
self.PreviousVoiceLine = 0
|
||||||
|
end
|
||||||
|
if not self.PreviousVoiceLineString then
|
||||||
|
self.PreviousVoiceLineString = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if snd != "" and (self.PreviousVoiceLine < CurTime() or nodelay) then
|
||||||
|
snd = ")"..snd
|
||||||
|
self.PreviousVoiceLine = CurTime()+4
|
||||||
|
self:StopSound(self.PreviousVoiceLineString)
|
||||||
|
self.PreviousVoiceLineString = snd
|
||||||
|
self:EmitSound(snd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
net.Receive("SuR.VoiceLines", function(len, ply)
|
||||||
|
local data = net.ReadTable()
|
||||||
|
if IsEntity(data[1]) and data[1].PlayVoiceLine then
|
||||||
|
data[1]:PlayVoiceLine(data[2], data[3])
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local arrowMat = Material('surrounded/arrow.png')
|
||||||
|
net.Receive("SuR.PointMarker", function()
|
||||||
|
local vec = net.ReadVector()
|
||||||
|
local str = net.ReadString()
|
||||||
|
local delay = CurTime()+120
|
||||||
|
hook.Add("HUDPaint", "SuR_PointMarker", function()
|
||||||
|
local pos = vec:ToScreen()
|
||||||
|
|
||||||
|
surface.SetMaterial(arrowMat)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(pos.x-16,pos.y-16,32,32)
|
||||||
|
|
||||||
|
draw.SimpleText(math.Round(LocalPlayer():GetPos():Distance(vec) * 2/100) .. " m", "SuR_SmallFont1", pos.x+20, pos.y, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
if str != "" then
|
||||||
|
draw.SimpleText(str, "SuR_SmallFont1", pos.x, pos.y-20, Color(240,220,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
if delay < CurTime() or !SuR.Data["DrawHUD"] then
|
||||||
|
hook.Remove("HUDPaint", "SuR_PointMarker")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------JUMP PART
|
||||||
|
|
||||||
|
local jumpDelay = 1
|
||||||
|
local lastJumpTime = 0
|
||||||
|
|
||||||
|
hook.Add("PlayerBindPress", "JumpDelay", function(ply, key)
|
||||||
|
if ply:Alive() and key == "+jump" and lastJumpTime < CurTime() then
|
||||||
|
lastJumpTime = CurTime()+jumpDelay
|
||||||
|
return false
|
||||||
|
elseif ply:Alive() and key == "+jump" and ply:OnGround() and lastJumpTime >= CurTime() then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------CAM PART
|
||||||
|
|
||||||
|
local currentpos = Vector(0,0,0)
|
||||||
|
local currentang = Angle(0,0,0)
|
||||||
|
local changeview = true
|
||||||
|
local viewbob_speed = 10
|
||||||
|
local viewbob_amount = 0.01
|
||||||
|
local viewbob_offset = 0
|
||||||
|
local last_velocity = 0
|
||||||
|
local left_side = false
|
||||||
|
local FPOffsetAngles = Angle(0,0,0)
|
||||||
|
local fp_offset = {x = 0, y = 0, z = 0}
|
||||||
|
hook.Add("PlayerButtonDown", "MainCamButtons", function(ply, but)
|
||||||
|
if but == KEY_CAPSLOCK and not ply:IsTyping() then
|
||||||
|
left_side = !left_side
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
hook.Add("CalcView", "MainCam", function( ply, pos, angles, fov )
|
||||||
|
if ply:Alive() then
|
||||||
|
local body = ply
|
||||||
|
if IsValid(ply:GetNWEntity("CameraEnt")) then
|
||||||
|
body = ply:GetNWEntity("CameraEnt")
|
||||||
|
end
|
||||||
|
local curmask = MASK_SHOT_HULL
|
||||||
|
local plyang = ply:EyeAngles()
|
||||||
|
local headpos = body:GetBonePosition(body:LookupBone("ValveBiped.Bip01_Head1"))
|
||||||
|
local needpos = headpos - angles:Forward()*18 + angles:Right()*16 - angles:Up()*2
|
||||||
|
if ply:IsZombie() then
|
||||||
|
needpos = headpos - angles:Forward()*32 + angles:Right()*20 - angles:Up()*2
|
||||||
|
if left_side then
|
||||||
|
needpos = headpos - angles:Forward()*32 - angles:Right()*20 - angles:Up()*2
|
||||||
|
end
|
||||||
|
elseif not ply:IsZombie() and left_side then
|
||||||
|
needpos = headpos - angles:Forward()*18 - angles:Right()*16 - angles:Up()*2
|
||||||
|
end
|
||||||
|
local limitpos = headpos
|
||||||
|
local cutscene = ply:GetNWBool('SVAnimStopCutscene')
|
||||||
|
local person = GetConVar("sur_viewmod"):GetFloat()
|
||||||
|
local person_cutscene = GetConVar("sur_viewmod_cutscene"):GetFloat()
|
||||||
|
local person_da = GetConVar("sur_viewmod_deathanims"):GetFloat()
|
||||||
|
local wep = ply:GetActiveWeapon()
|
||||||
|
local person_da_check = false
|
||||||
|
|
||||||
|
if ply:KeyDown(IN_ATTACK2) and changeview and IsValid(wep) and isstring(wep.Base) and string.match(wep.Base, "tfa") and wep:GetMaxClip1() > 0 and person > 0 then
|
||||||
|
changeview = false
|
||||||
|
ply:ScreenFade(SCREENFADE.IN, color_black, 0.3, 0)
|
||||||
|
elseif not ply:KeyDown(IN_ATTACK2) and not changeview then
|
||||||
|
changeview = true
|
||||||
|
ply:ScreenFade(SCREENFADE.IN, color_black, 0.3, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local tp_enable = person == 2 and not cutscene or (cutscene or ply:IsDowned()) and person_cutscene == 1
|
||||||
|
local fp_enable = person == 1 and not cutscene or (cutscene or ply:IsDowned()) and person_cutscene == 0
|
||||||
|
if person_da == 0 and (string.match(ply:GetSVAnim(), "killmove") or string.match(ply:GetSVAnim(), "executions")) then
|
||||||
|
fp_enable = true
|
||||||
|
tp_enable = false
|
||||||
|
person_da_check = true
|
||||||
|
elseif person_da == 1 and (string.match(ply:GetSVAnim(), "killmove") or string.match(ply:GetSVAnim(), "executions")) then
|
||||||
|
tp_enable = true
|
||||||
|
fp_enable = false
|
||||||
|
person_da_check = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if fp_enable and not tp_enable then
|
||||||
|
ply:ManipulateBoneScale(ply:LookupBone("ValveBiped.Bip01_Head1"), Vector(0,0,0))
|
||||||
|
else
|
||||||
|
ply:ManipulateBoneScale(ply:LookupBone("ValveBiped.Bip01_Head1"), Vector(1,1,1))
|
||||||
|
end
|
||||||
|
|
||||||
|
if tp_enable then
|
||||||
|
if cutscene or ply:IsDowned() or person_da_check then
|
||||||
|
local pos2 = pos
|
||||||
|
if string.match(ply:GetSVAnim(), "killmove") or string.match(ply:GetSVAnim(), "executions") or string.match(ply:GetSVAnim(), "killanim") then
|
||||||
|
pos2 = body:GetBonePosition(body:LookupBone("ValveBiped.Bip01_Head1"))
|
||||||
|
pos2.z = ply:EyePos().z-16
|
||||||
|
curmask = MASK_SOLID_BRUSHONLY
|
||||||
|
end
|
||||||
|
needpos = pos2 - angles:Forward()*64 + angles:Right()*32 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
if left_side then
|
||||||
|
needpos = pos2 - angles:Forward()*64 - angles:Right()*32 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
plyang = plyang + Angle(10,-20,0)
|
||||||
|
if string.match(ply:GetSVAnim(), "closeencounter") then
|
||||||
|
needpos = pos2 - angles:Forward()*32 - angles:Right()*48 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
plyang = plyang + Angle(15,-30,0)
|
||||||
|
plyang.z = math.Clamp(ply:GetAttachment(ply:LookupAttachment('eyes')).Ang.z/2, -45, 45)
|
||||||
|
curmask = MASK_SOLID_BRUSHONLY
|
||||||
|
elseif string.match(ply:GetSVAnim(), "killanim") then
|
||||||
|
local att = ply:GetAttachment(ply:LookupAttachment('eyes'))
|
||||||
|
needpos = pos2 - angles:Forward()*32 - angles:Right()*48 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
plyang = plyang + Angle(0,-20,0)
|
||||||
|
plyang.x = -(needpos-att.Pos):GetNormalized():Angle().x+15
|
||||||
|
plyang.z = math.Clamp(att.Ang.z/4, -45, 45)
|
||||||
|
curmask = MASK_SOLID_BRUSHONLY
|
||||||
|
end
|
||||||
|
else
|
||||||
|
plyang = plyang + Angle(10,20,0)
|
||||||
|
if string.match(ply:GetSVAnim(), "closeencounter") then
|
||||||
|
needpos = pos2 - angles:Forward()*32 + angles:Right()*48 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
plyang = plyang + Angle(15,30,0)
|
||||||
|
plyang.z = math.Clamp(ply:GetAttachment(ply:LookupAttachment('eyes')).Ang.z/2, -45, 45)
|
||||||
|
curmask = MASK_SOLID_BRUSHONLY
|
||||||
|
elseif string.match(ply:GetSVAnim(), "killanim") then
|
||||||
|
local att = ply:GetAttachment(ply:LookupAttachment('eyes'))
|
||||||
|
needpos = pos2 - angles:Forward()*32 + angles:Right()*48 + ply:GetNWVector('CutsceneAddPos')
|
||||||
|
plyang = plyang + Angle(0,20,0)
|
||||||
|
plyang.x = -(needpos-att.Pos):GetNormalized():Angle().x+15
|
||||||
|
plyang.z = math.Clamp(att.Ang.z/4, -45, 45)
|
||||||
|
curmask = MASK_SOLID_BRUSHONLY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ply:IsDowned() and ply:GetSVAnim() == "" then
|
||||||
|
needpos = needpos + angles:Up()*36
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
currentpos = LerpVector(FrameTime()*6, currentpos, needpos)
|
||||||
|
currentang = LerpAngle(FrameTime()*12, currentang, plyang)
|
||||||
|
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = limitpos,
|
||||||
|
endpos = currentpos,
|
||||||
|
mask = curmask,
|
||||||
|
filter = ply,
|
||||||
|
})
|
||||||
|
|
||||||
|
local wep = ply:GetActiveWeapon()
|
||||||
|
|
||||||
|
if changeview then
|
||||||
|
local view = {
|
||||||
|
origin = tr.HitPos,
|
||||||
|
angles = currentang,
|
||||||
|
fov = fov,
|
||||||
|
drawviewer = true,
|
||||||
|
nearz = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
else
|
||||||
|
currentpos = limitpos
|
||||||
|
end
|
||||||
|
elseif fp_enable then
|
||||||
|
local ang1 = angles
|
||||||
|
currentpos = limitpos
|
||||||
|
|
||||||
|
if changeview then
|
||||||
|
local eye = body:GetAttachment(body:LookupAttachment('eyes'))
|
||||||
|
if string.match(ply:GetSVAnim(), "sur_executions_") and body:LookupAttachment('custom_eyes') > 0 then
|
||||||
|
eye = body:GetAttachment(body:LookupAttachment('custom_eyes'))
|
||||||
|
end
|
||||||
|
if cutscene then
|
||||||
|
ang1 = eye.Ang
|
||||||
|
end
|
||||||
|
local view = {
|
||||||
|
origin = eye.Pos,
|
||||||
|
angles = ang1,
|
||||||
|
fov = fov,
|
||||||
|
drawviewer = true,
|
||||||
|
nearz = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
end
|
||||||
|
else
|
||||||
|
currentpos = limitpos
|
||||||
|
currentang = angles
|
||||||
|
if ply:Alive() and not ply:ShouldDrawLocalPlayer() then
|
||||||
|
local velocity = ply:GetVelocity():Length()
|
||||||
|
if velocity > 0 and last_velocity == 0 then
|
||||||
|
viewbob_offset = 0
|
||||||
|
end
|
||||||
|
last_velocity = velocity
|
||||||
|
viewbob_offset = viewbob_offset + (viewbob_speed * FrameTime())
|
||||||
|
local bob_x = math.sin(viewbob_offset) * viewbob_amount * last_velocity
|
||||||
|
local bob_y = math.cos(viewbob_offset) * viewbob_amount * last_velocity
|
||||||
|
angles.roll = angles.roll + bob_y/2
|
||||||
|
angles.x = angles.x + bob_x/4
|
||||||
|
local view = {}
|
||||||
|
view.origin = pos
|
||||||
|
view.angles = angles+FPOffsetAngles
|
||||||
|
view.fov = fov
|
||||||
|
|
||||||
|
local power = ply:GetVelocity():Length()/25
|
||||||
|
local num1 = math.Clamp(power, 0, 10)
|
||||||
|
|
||||||
|
if ply:KeyDown(IN_MOVELEFT) then
|
||||||
|
fp_offset.z = -num1
|
||||||
|
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||||
|
fp_offset.z = num1
|
||||||
|
else
|
||||||
|
fp_offset.z = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:KeyDown(IN_FORWARD) and !ply:KeyDown(IN_ATTACK2) then
|
||||||
|
fp_offset.x = num1
|
||||||
|
elseif ply:KeyDown(IN_BACK) and !ply:KeyDown(IN_ATTACK2) then
|
||||||
|
fp_offset.x = -num1
|
||||||
|
else
|
||||||
|
fp_offset.x = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
FPOffsetAngles = LerpAngle(FrameTime()*4, FPOffsetAngles, Angle(fp_offset.x, fp_offset.y, fp_offset.z))
|
||||||
|
|
||||||
|
return view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------BOSS PART
|
||||||
|
|
||||||
|
local barMat = Material('surrounded/bar.png', 'smooth')
|
||||||
|
|
||||||
|
net.Receive("SuR.Boss", function()
|
||||||
|
local name = SuR.Language[net.ReadString()]
|
||||||
|
local ent = net.ReadEntity()
|
||||||
|
local alpha = 0
|
||||||
|
local morealpha = true
|
||||||
|
hook.Add("HUDPaint", "SuR_Boss", function()
|
||||||
|
surface.SetMaterial(barMat)
|
||||||
|
surface.SetDrawColor(0,0,0,alpha)
|
||||||
|
surface.DrawTexturedRect(ScrW()/2-We(240), He(30), We(480), He(50))
|
||||||
|
|
||||||
|
if IsValid(ent) then
|
||||||
|
local mult = (ent:Health()/ent:GetMaxHealth())
|
||||||
|
surface.SetMaterial(barMat)
|
||||||
|
surface.SetDrawColor(150,0,0,alpha)
|
||||||
|
render.SetScissorRect( ScrW()/2-We(240), He(30), ScrW()/2+We(480*mult-240), He(80), true )
|
||||||
|
surface.DrawTexturedRect(ScrW()/2-We(235), He(35), We(470), He(40))
|
||||||
|
render.SetScissorRect( 0, 0, 0, 0, false )
|
||||||
|
else
|
||||||
|
morealpha = false
|
||||||
|
end
|
||||||
|
|
||||||
|
draw.SimpleText(name, "SuR_SmallFont2", ScrW()/2, He(25), Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
|
||||||
|
if morealpha then
|
||||||
|
alpha = math.Clamp(alpha+FrameTime()/0.01, 0, 255)
|
||||||
|
else
|
||||||
|
alpha = math.Clamp(alpha-FrameTime()/0.01, 0, 255)
|
||||||
|
if alpha == 0 then
|
||||||
|
hook.Remove("HUDPaint", "SuR_Boss")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------MUSIC PART
|
||||||
|
|
||||||
|
local rndmusic = ""
|
||||||
|
local musicname = ""
|
||||||
|
local currentchannel = nil
|
||||||
|
local otherchannel = nil
|
||||||
|
|
||||||
|
local function RandomizeTrack()
|
||||||
|
local tab = SuR.Config.MusicWave
|
||||||
|
local wave = SuR.Data["Wave"]
|
||||||
|
if SuR.Data["ExfilWave"] and SuR.Data["WaveState"] then
|
||||||
|
rndmusic = tab["Exfil"][math.random(1,#tab["Exfil"])]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if SuR.Config.Objective_Mode then
|
||||||
|
rndmusic = tab["Objective"][math.random(1,#tab["Objective"])]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for k, v in pairs(tab) do
|
||||||
|
local allow = false
|
||||||
|
if (k == "Easy" and wave < 3) or (k == "Medium" and wave >= 3 and wave < 6) or (k == "Hard" and wave >= 6 and wave < 10) or (k == "Chaos" and wave >= 10 and wave < 15) or (k == "Extreme" and wave >= 15) then
|
||||||
|
allow = true
|
||||||
|
end
|
||||||
|
if allow then
|
||||||
|
rndmusic = v[math.random(1,#v)]
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("Think", "MainMusic", function()
|
||||||
|
local wave = SuR.Data["Wave"]
|
||||||
|
local wavest = SuR.Data["WaveState"]
|
||||||
|
if wavest and wave > 0 and not SuR.Data["DisableMusic"] then
|
||||||
|
SuR:PlayMusic(rndmusic)
|
||||||
|
if IsValid(currentchannel) then
|
||||||
|
local maxtime = currentchannel:GetLength()
|
||||||
|
local time = currentchannel:GetTime()
|
||||||
|
currentchannel:SetVolume(GetConVar("sur_music_volume"):GetFloat())
|
||||||
|
if time >= maxtime or currentchannel:GetState() == 0 or currentchannel:GetState() == 2 or (SuR.Data["ExfilWave"] and SuR.Data["WaveState"] and !table.HasValue(SuR.Config.MusicWave["Exfil"], rndmusic)) then
|
||||||
|
RandomizeTrack()
|
||||||
|
SuR:PlayMusic("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if IsValid(currentchannel) then
|
||||||
|
local volume = currentchannel:GetVolume()
|
||||||
|
currentchannel:SetVolume(math.max(volume-FrameTime()/2, 0))
|
||||||
|
if volume == 0 then
|
||||||
|
SuR:PlayMusic("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
RandomizeTrack()
|
||||||
|
end
|
||||||
|
if IsValid(otherchannel) then
|
||||||
|
otherchannel:SetVolume(GetConVar("sur_music_volume"):GetFloat())
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
function SuR:PlayMusicOther(str)
|
||||||
|
if IsValid(otherchannel) then
|
||||||
|
otherchannel:Stop()
|
||||||
|
end
|
||||||
|
sound.PlayFile("sound/"..str, "noblock", function(station, s1, s2)
|
||||||
|
if IsValid(station) then
|
||||||
|
station:Play()
|
||||||
|
station:SetVolume(GetConVar("sur_music_volume"):GetFloat())
|
||||||
|
otherchannel = station
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SuR:PlayMusic(music1, rnd)
|
||||||
|
local music = "sound/"..music1
|
||||||
|
if rnd then
|
||||||
|
RandomizeTrack()
|
||||||
|
music1 = rndmusic
|
||||||
|
end
|
||||||
|
if music1 != "" then
|
||||||
|
if musicname == music1 then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
if IsValid(currentchannel) then
|
||||||
|
currentchannel:Stop()
|
||||||
|
currentchannel = nil
|
||||||
|
end
|
||||||
|
timer.Simple(1, function()
|
||||||
|
sound.PlayFile(music, "noblock", function(station, s1, s2)
|
||||||
|
if IsValid(station) then
|
||||||
|
station:Play()
|
||||||
|
currentchannel = station
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
musicname = music1
|
||||||
|
else
|
||||||
|
musicname = ""
|
||||||
|
if IsValid(currentchannel) then
|
||||||
|
currentchannel:Stop()
|
||||||
|
currentchannel = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(0.5, function()
|
||||||
|
local f = file.Read("surrounded/music_replacement.lua", "LUA")
|
||||||
|
if !isstring(f) then return end
|
||||||
|
|
||||||
|
local pattern = "start_config.-end_config"
|
||||||
|
local musicWaveTable = string.match(f, pattern)
|
||||||
|
|
||||||
|
if !musicWaveTable then return end
|
||||||
|
musicWaveTable = string.Replace(musicWaveTable, "start_config", "SuR.Config.MusicWave = {")
|
||||||
|
musicWaveTable = string.Replace(musicWaveTable, "end_config", "}")
|
||||||
|
RunString(musicWaveTable)
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------ANIM PART
|
||||||
|
|
||||||
|
local disable_tab = {
|
||||||
|
["sur_helpup_trials_follower_try"] = true,
|
||||||
|
["sur_helpup_trials_leader_try"] = true,
|
||||||
|
["sur_helpup_trials_follower_success"] = true,
|
||||||
|
["sur_helpup_trials_leader_success"] = true,
|
||||||
|
["sur_helpup_trials_follower_drophigh"] = true,
|
||||||
|
["sur_helpup_trials_leader_leave"] = true,
|
||||||
|
}
|
||||||
|
hook.Add("AdjustMouseSensitivity", "SuR_Sens", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local downed = ply:IsDowned()
|
||||||
|
local disable = disable_tab[ply:GetSVAnim()]
|
||||||
|
if downed then
|
||||||
|
return 0.1
|
||||||
|
end
|
||||||
|
if disable then
|
||||||
|
return 0.001
|
||||||
|
end
|
||||||
|
if ply:IsZombie() and ply:Alive() then
|
||||||
|
return 0.5
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("CalcMainActivity", "MainAnims", function(ply, vel)
|
||||||
|
local str = ply:GetSVAnim()
|
||||||
|
local num = ply:GetNWFloat('SVAnimDelay')
|
||||||
|
local st = ply:GetNWFloat('SVAnimStartTime')
|
||||||
|
local downed = ply:IsDowned()
|
||||||
|
local dir = ply:GetNWString("MoveDirection")
|
||||||
|
if str != "" then
|
||||||
|
ply:SetCycle((CurTime()-st)/num)
|
||||||
|
return -1, ply:LookupSequence(str)
|
||||||
|
end
|
||||||
|
if downed then
|
||||||
|
if ply:GetCycle() == 1 then
|
||||||
|
ply:SetCycle(0)
|
||||||
|
end
|
||||||
|
local speed = ply:GetVelocity():Length()
|
||||||
|
if speed > 5 then
|
||||||
|
if dir == "forward" then
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_forward")
|
||||||
|
elseif dir == "backward" then
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_backward")
|
||||||
|
elseif dir == "left" then
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_left")
|
||||||
|
elseif dir == "right" then
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_right")
|
||||||
|
else
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_idle")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return -1, ply:LookupSequence("sur_downed_trials_idle")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ply:IsZombie() then
|
||||||
|
local speed = vel:Length()
|
||||||
|
local cr = ply:Crouching()
|
||||||
|
if !ply:OnGround() then
|
||||||
|
return ACT_JUMP, -1
|
||||||
|
elseif speed > 200 and not cr then
|
||||||
|
return ACT_SPRINT, -1
|
||||||
|
elseif speed > 75 and not cr or cr and speed > 25 then
|
||||||
|
if cr then
|
||||||
|
return ACT_WALK_AGITATED, -1
|
||||||
|
else
|
||||||
|
return ACT_RUN, -1
|
||||||
|
end
|
||||||
|
elseif speed > 10 then
|
||||||
|
if cr then
|
||||||
|
return ACT_WALK_STIMULATED, -1
|
||||||
|
else
|
||||||
|
if ply:GetModel() == "models/vj_lnrspecials/brute.mdl" then
|
||||||
|
return ACT_WALK_AIM, -1
|
||||||
|
else
|
||||||
|
return ACT_WALK, -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if cr then
|
||||||
|
return ACT_IDLE_STIMULATED, -1
|
||||||
|
else
|
||||||
|
return ACT_IDLE, -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------MARK PART
|
||||||
|
|
||||||
|
local num_marks = 0
|
||||||
|
local mat_markpoint = Material("surrounded/marks/point.png")
|
||||||
|
local mat_markitem = Material("surrounded/marks/item.png")
|
||||||
|
local mat_markenemy = Material("surrounded/marks/enemy.png")
|
||||||
|
|
||||||
|
function screen_distance(x1, y1, x2, y2)
|
||||||
|
local dif = Vector(x1, y1):Distance(Vector(x2, y2))
|
||||||
|
return dif
|
||||||
|
end
|
||||||
|
|
||||||
|
net.Receive("SuR.PointMark", function()
|
||||||
|
local type = net.ReadString()
|
||||||
|
local ply = net.ReadEntity()
|
||||||
|
local data = net.ReadTable()[1]
|
||||||
|
if not data then return end
|
||||||
|
|
||||||
|
local mat = mat_markpoint
|
||||||
|
if type == "item" then
|
||||||
|
mat = mat_markitem
|
||||||
|
surface.PlaySound("surrounded/sfx/mark_item.mp3")
|
||||||
|
elseif type == "enemy" then
|
||||||
|
mat = mat_markenemy
|
||||||
|
surface.PlaySound("surrounded/sfx/mark_enemy.mp3")
|
||||||
|
else
|
||||||
|
surface.PlaySound("surrounded/sfx/mark_point.mp3")
|
||||||
|
end
|
||||||
|
|
||||||
|
num_marks = num_marks + 1
|
||||||
|
|
||||||
|
local name = "SuR_PointMark"..num_marks
|
||||||
|
local nick = ply:Nick()
|
||||||
|
local alpha = 255
|
||||||
|
local height = ScrH()/2
|
||||||
|
|
||||||
|
hook.Add("HUDPaint", name.."n", function()
|
||||||
|
draw.SimpleText(nick .. SuR.Language["message_mark"], "SuR_SmallFont1", We(50), height, Color(255,255,255,alpha), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
height = height - FrameTime()/0.01
|
||||||
|
alpha = alpha - FrameTime()/0.005
|
||||||
|
if alpha <= 0 then
|
||||||
|
hook.Remove("HUDPaint", name.."n")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("HUDPaint", name, function()
|
||||||
|
if !LocalPlayer():Alive() then
|
||||||
|
hook.Remove("HUDPaint", name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local pos = Vector()
|
||||||
|
if isvector(data) then
|
||||||
|
pos = data
|
||||||
|
else
|
||||||
|
if !IsValid(data) then
|
||||||
|
hook.Remove("HUDPaint", name)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
pos = data:WorldSpaceCenter()
|
||||||
|
end
|
||||||
|
local spos = pos:ToScreen()
|
||||||
|
local dist = screen_distance(ScrW()/2, ScrH()/2, spos.x, spos.y) < 50
|
||||||
|
if dist then
|
||||||
|
surface.SetDrawColor(255,255,255,230)
|
||||||
|
surface.SetMaterial(mat)
|
||||||
|
surface.DrawTexturedRect(spos.x-We(32), spos.y-He(32), We(64), He(64))
|
||||||
|
draw.SimpleText(nick, "SuR_PixelFont", spos.x, spos.y+He(40), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText(math.Round(LocalPlayer():GetPos():Distance(pos) * 2/100) .. " m", "SuR_SmallFont1", spos.x, spos.y+He(55), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
else
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.SetMaterial(mat)
|
||||||
|
surface.DrawTexturedRect(spos.x-We(12), spos.y-He(12), We(24), He(24))
|
||||||
|
draw.SimpleText(math.Round(LocalPlayer():GetPos():Distance(pos) * 2/100) .. " m", "SuR_PixelFont", spos.x, spos.y+He(20), Color(255,255,255,150), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
timer.Simple(30, function()
|
||||||
|
hook.Remove("HUDPaint", name)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
local bg = Material('surrounded/vgui_bg.png')
|
||||||
|
local lang = SuR.Language
|
||||||
|
|
||||||
|
function SuR:OpenBuyMenu()
|
||||||
|
local df = vgui.Create("DFrame")
|
||||||
|
df:SetSize(We(600), He(425))
|
||||||
|
df:Center()
|
||||||
|
df:SetTitle("")
|
||||||
|
df:MakePopup()
|
||||||
|
df:ShowCloseButton(false)
|
||||||
|
df.Paint = function(self, w, h)
|
||||||
|
surface.SetMaterial(bg)
|
||||||
|
surface.SetDrawColor(0,0,0,230)
|
||||||
|
surface.DrawTexturedRect(0, 0, w, h)
|
||||||
|
|
||||||
|
draw.SimpleText(lang["buymenu_main"], "SuR_SmallFont2", We(30), He(15), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
local db = vgui.Create("DButton", df)
|
||||||
|
db:SetSize(We(32), He(32))
|
||||||
|
db:SetPos(We(540),He(15))
|
||||||
|
db:SetText("")
|
||||||
|
function db:Paint(w, h)
|
||||||
|
if self:IsHovered() then
|
||||||
|
draw.SimpleText("X", "SuR_MediumFont1", w/2, h/2, Color(200,255,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
else
|
||||||
|
draw.SimpleText("X", "SuR_MediumFont1", w/2, h/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function db:DoClick()
|
||||||
|
surface.PlaySound("surrounded/click.mp3")
|
||||||
|
df:Remove()
|
||||||
|
end
|
||||||
|
function db:OnCursorEntered()
|
||||||
|
surface.PlaySound("surrounded/tick.wav")
|
||||||
|
end
|
||||||
|
|
||||||
|
local frame = vgui.Create("DPanel", df)
|
||||||
|
frame:SetPos(We(30), He(50))
|
||||||
|
frame:SetSize(We(530), He(350))
|
||||||
|
function frame:Paint(w, h) end
|
||||||
|
|
||||||
|
local propertySheet = vgui.Create("DPropertySheet", frame)
|
||||||
|
propertySheet:Dock(FILL)
|
||||||
|
|
||||||
|
for categoryName, items in SortedPairs(SuR.Config.TierWeapons) do
|
||||||
|
if categoryName == "Melee" or categoryName == "Other" or categoryName == "Tier1" then continue end
|
||||||
|
|
||||||
|
local panel = vgui.Create("DPanel", frame)
|
||||||
|
panel:Dock(FILL)
|
||||||
|
panel.Paint = function(self, w, h)
|
||||||
|
surface.SetDrawColor(0,0,0)
|
||||||
|
surface.DrawRect(0, 0, w, h)
|
||||||
|
end
|
||||||
|
|
||||||
|
local scrollPanel = vgui.Create("DScrollPanel", panel)
|
||||||
|
scrollPanel:Dock(FILL)
|
||||||
|
|
||||||
|
local list = vgui.Create("DIconLayout", scrollPanel)
|
||||||
|
list:Dock(FILL)
|
||||||
|
list:SetSpaceY(5)
|
||||||
|
list:SetSpaceX(5)
|
||||||
|
|
||||||
|
for _, item in ipairs(items) do
|
||||||
|
local wep = weapons.Get(item)
|
||||||
|
if !wep then continue end
|
||||||
|
|
||||||
|
local price = 50
|
||||||
|
if categoryName == "Tier2" then price = SuR.Config.Tier2_Price end
|
||||||
|
if categoryName == "Tier3" then price = SuR.Config.Tier3_Price end
|
||||||
|
if categoryName == "Tier4" then price = SuR.Config.Tier4_Price end
|
||||||
|
if categoryName == "Tier5" then price = SuR.Config.Tier5_Price end
|
||||||
|
|
||||||
|
local itemPanel = list:Add("DPanel")
|
||||||
|
itemPanel:SetSize(530, 100)
|
||||||
|
itemPanel.Paint = function(self, w, h)
|
||||||
|
surface.SetDrawColor(50,50,50)
|
||||||
|
surface.DrawRect(0, 0, w, h)
|
||||||
|
end
|
||||||
|
|
||||||
|
local icon = vgui.Create("DImage", itemPanel)
|
||||||
|
icon:SetImage("entities/"..item..".png")
|
||||||
|
icon:SetSize(We(88), He(88))
|
||||||
|
icon:SetPos(We(5), He(5))
|
||||||
|
|
||||||
|
local nameLabel = vgui.Create("DLabel", itemPanel)
|
||||||
|
nameLabel:SetText(wep.PrintName)
|
||||||
|
nameLabel:SetFont("SuR_SmallFont2")
|
||||||
|
nameLabel:SizeToContents()
|
||||||
|
nameLabel:SetPos(We(100), He(10))
|
||||||
|
|
||||||
|
local priceLabel = vgui.Create("DLabel", itemPanel)
|
||||||
|
priceLabel:SetText("Price: $" .. price)
|
||||||
|
priceLabel:SetFont("SuR_SmallFont1")
|
||||||
|
priceLabel:SizeToContents()
|
||||||
|
priceLabel:SetPos(We(100), He(35))
|
||||||
|
|
||||||
|
local buyButton = vgui.Create("DButton", itemPanel)
|
||||||
|
buyButton:SetText(lang["buymenu_buy"])
|
||||||
|
buyButton:SetFont("SuR_SmallFont1")
|
||||||
|
buyButton:SetPos(We(100), He(60))
|
||||||
|
buyButton:SetSize(100, 30)
|
||||||
|
buyButton.DoClick = function()
|
||||||
|
net.Start("SuR.BuyMenu")
|
||||||
|
net.WriteString(item)
|
||||||
|
net.SendToServer()
|
||||||
|
|
||||||
|
if LocalPlayer():GetNWInt('Money') < price then
|
||||||
|
surface.PlaySound("buttons/combine_button_locked.wav")
|
||||||
|
else
|
||||||
|
surface.PlaySound("buttons/lightswitch2.wav")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
propertySheet:AddSheet(categoryName, panel, "icon16/folder.png")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
local lang = SuR.Language
|
||||||
|
local vinMat = Material('surrounded/vin.png')
|
||||||
|
local anims_tab = {
|
||||||
|
"sur_idles_m_armsback_",
|
||||||
|
"sur_idles_m_armsfront_",
|
||||||
|
"sur_idles_m_headache_",
|
||||||
|
"sur_idles_m_hipleft_",
|
||||||
|
"sur_idles_m_hipright_",
|
||||||
|
"sur_idles_m_hips_",
|
||||||
|
"sur_idles_m_neckache_",
|
||||||
|
}
|
||||||
|
|
||||||
|
local currentPointIndex = 1
|
||||||
|
local startTime = 0
|
||||||
|
local lastdatacam = {}
|
||||||
|
local modelcamtab = {}
|
||||||
|
local last_count_number = 0
|
||||||
|
|
||||||
|
local function CreateCamModels(data)
|
||||||
|
for _, e in pairs(modelcamtab) do
|
||||||
|
if !IsValid(e) then continue end
|
||||||
|
e:Remove()
|
||||||
|
end
|
||||||
|
modelcamtab = {}
|
||||||
|
|
||||||
|
local ply_tab, ply_index = player.GetAll(), 0
|
||||||
|
for k, v in pairs(data.model) do
|
||||||
|
ply_index = ply_index + 1
|
||||||
|
local tar = ply_tab[ply_index]
|
||||||
|
if !IsValid(tar) then continue end
|
||||||
|
|
||||||
|
local anim = anims_tab[math.random(1,#anims_tab)]
|
||||||
|
local model = ClientsideModel(tar:GetModel())
|
||||||
|
modelcamtab[#modelcamtab+1] = model
|
||||||
|
model.active_seq = anim.."loop"
|
||||||
|
model.next_seq = anim.."toready"
|
||||||
|
model.active_seq_noloop = false
|
||||||
|
model.player = tar
|
||||||
|
model:ResetSequence(anim.."loop")
|
||||||
|
model:SetPos(v.pos)
|
||||||
|
model:SetAngles(v.ang)
|
||||||
|
model:SetEyeTarget(data.cam[#data.cam].pos)
|
||||||
|
model:SetCycle(math.Rand(0,1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ready_up_anim()
|
||||||
|
for k, v in pairs(modelcamtab) do
|
||||||
|
v:SetCycle(0)
|
||||||
|
v:ResetSequence(v.next_seq)
|
||||||
|
v.active_seq = v.next_seq
|
||||||
|
v.active_seq_noloop = true
|
||||||
|
end
|
||||||
|
timer.Simple(4, function()
|
||||||
|
LocalPlayer():ScreenFade(SCREENFADE.OUT, color_black, 1, 2)
|
||||||
|
end)
|
||||||
|
timer.Simple(5, function()
|
||||||
|
surface.PlaySound("surrounded/sfx/deploy_begin.mp3")
|
||||||
|
SuR:StopDeployCutscene()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SuR:StartDeployCutscene(cdata)
|
||||||
|
local data = table.Copy(cdata)
|
||||||
|
table.Shuffle(data.model)
|
||||||
|
if !data.cam then return end
|
||||||
|
|
||||||
|
SuR:PlayMusicOther(table.Random(SuR.Config.MusicWave["Deploy"]))
|
||||||
|
SuR:StopDeployCutscene()
|
||||||
|
table.insert(data.cam, 1, data.cam[1])
|
||||||
|
LocalPlayer():ScreenFade(SCREENFADE.IN, color_black, 1, 1)
|
||||||
|
CreateCamModels(data)
|
||||||
|
|
||||||
|
local mode = "survival"
|
||||||
|
if SuR.Config.Objective_Mode then
|
||||||
|
mode = "objective"
|
||||||
|
elseif SuR.Config.Versus_Mode then
|
||||||
|
mode = "versus"
|
||||||
|
end
|
||||||
|
|
||||||
|
local team_ready = false
|
||||||
|
hook.Add("HUDPaint", "SuR_DeployCutscene", function()
|
||||||
|
surface.SetMaterial(vinMat)
|
||||||
|
surface.SetDrawColor(0,0,0,200)
|
||||||
|
surface.DrawTexturedRect(0, 0, ScrW(), ScrH())
|
||||||
|
|
||||||
|
local ortime = SuR.Data["DeployTime"]-CurTime()
|
||||||
|
local dtime = math.floor(ortime)
|
||||||
|
if SuR.Data["Deploying"] and dtime >= 0 and SuR.Data["DrawHUD"] then
|
||||||
|
if dtime > 5 then
|
||||||
|
draw.SimpleText(lang["mode"]..lang["mode_"..mode], "SuR_SmallFont1", ScrW()/2, ScrH()-He(160), Color(200,200,50), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText(string.format(lang["deploy_time"], dtime), "SuR_MediumFont1", ScrW()/2, ScrH()-He(130), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
else
|
||||||
|
draw.SimpleText(dtime, "SuR_LargeFont1", ScrW()/2, ScrH()-He(200), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
draw.SimpleText(lang["deploy_hint"], "SuR_SmallFont1", ScrW()/2, ScrH()-He(100), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
if player.GetCount() > #modelcamtab then
|
||||||
|
draw.SimpleText(lang["deploy_big"], "SuR_SmallFont1", ScrW()/2, ScrH()-He(75), Color(255,255,255,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(modelcamtab) do
|
||||||
|
if !IsValid(v.player) then continue end
|
||||||
|
|
||||||
|
if v.player:GetModel() != v:GetModel() then
|
||||||
|
local model = v.player:GetModel()
|
||||||
|
v:SetModel(model)
|
||||||
|
v:ResetSequence(v.active_seq)
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = v:GetBonePosition(v:LookupBone("ValveBiped.Bip01_Head1"))
|
||||||
|
pos = (pos+Vector(0,0,16)):ToScreen()
|
||||||
|
|
||||||
|
local icon = SuR.Config.ClassIcons[v.player:GetPlayerClass()]
|
||||||
|
surface.SetMaterial(icon)
|
||||||
|
surface.SetDrawColor(255,255,255,alpha)
|
||||||
|
surface.DrawTexturedRect(pos.x-We(40), pos.y-He(16), We(32), He(32))
|
||||||
|
draw.SimpleTextOutlined(v.player:Nick(), "SuR_SmallFont1", pos.x, pos.y-He(4), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, 1, color_black)
|
||||||
|
draw.SimpleTextOutlined(lang["class_lvl_"..v.player:GetLevel()], "SuR_PixelFont", pos.x, pos.y+He(8), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, 1, color_black)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("CalcView", "SuR_DeployCutscene", function(ply, pos, ang, fov)
|
||||||
|
local tab = data.cam
|
||||||
|
local currentTime = CurTime() - startTime
|
||||||
|
local currentPoint = tab[currentPointIndex]
|
||||||
|
local nextPoint = tab[currentPointIndex + 1]
|
||||||
|
|
||||||
|
if player.GetCount() != #modelcamtab and #data.model >= player.GetCount() then
|
||||||
|
surface.PlaySound("surrounded/sfx/deploy_new.mp3")
|
||||||
|
CreateCamModels(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ortime = SuR.Data["DeployTime"]-CurTime()
|
||||||
|
local dtime = math.floor(ortime)
|
||||||
|
if dtime <= 5 and last_count_number != dtime and dtime != 0 then
|
||||||
|
surface.PlaySound("surrounded/sfx/deploy_tick.mp3")
|
||||||
|
if not team_ready then
|
||||||
|
team_ready = true
|
||||||
|
ready_up_anim()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
last_count_number = dtime
|
||||||
|
|
||||||
|
for k, v in pairs(modelcamtab) do
|
||||||
|
if !v.active_seq then continue end
|
||||||
|
local cycle = v:GetCycle()+FrameTime()/select(2, v:LookupSequence(v.active_seq))
|
||||||
|
v:SetCycle(cycle)
|
||||||
|
if cycle > 1 and not v.active_seq_noloop then
|
||||||
|
v:SetCycle(0)
|
||||||
|
end
|
||||||
|
if !IsValid(v.player) then
|
||||||
|
v:Remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if nextPoint then
|
||||||
|
local lerpedPos = LerpVector(currentTime / currentPoint.time, currentPoint.pos, nextPoint.pos)
|
||||||
|
local lerpedAng = LerpAngle(currentTime / currentPoint.time, currentPoint.ang, nextPoint.ang)
|
||||||
|
local lerpedFov = Lerp(currentTime / currentPoint.time, currentPoint.fov, nextPoint.fov)
|
||||||
|
|
||||||
|
if currentTime >= currentPoint.time then
|
||||||
|
currentPointIndex = currentPointIndex + 1
|
||||||
|
startTime = CurTime()
|
||||||
|
end
|
||||||
|
|
||||||
|
lastdatacam = {lerpedPos, lerpedAng, lerpedFov}
|
||||||
|
|
||||||
|
return {
|
||||||
|
origin = lerpedPos,
|
||||||
|
angles = lerpedAng,
|
||||||
|
fov = lerpedFov,
|
||||||
|
drawviewer = true,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
origin = lastdatacam[1],
|
||||||
|
angles = lastdatacam[2],
|
||||||
|
fov = lastdatacam[3],
|
||||||
|
drawviewer = true,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SuR:StopDeployCutscene()
|
||||||
|
hook.Remove("CalcView", "SuR_DeployCutscene")
|
||||||
|
hook.Remove("HUDPaint", "SuR_DeployCutscene")
|
||||||
|
currentPointIndex = 1
|
||||||
|
startTime = 0
|
||||||
|
last_count_number = 0
|
||||||
|
lastdatacam = {}
|
||||||
|
for _, e in pairs(modelcamtab) do
|
||||||
|
if !IsValid(e) then continue end
|
||||||
|
e:Remove()
|
||||||
|
end
|
||||||
|
modelcamtab = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
net.Receive("SuR.DeployCutscene", function()
|
||||||
|
local bool = net.ReadBool()
|
||||||
|
if bool then
|
||||||
|
if !SuR.Config.Deploy_Cutscene then return end
|
||||||
|
SuR:StartDeployCutscene(SuR.Config.Deploy_Cutscene)
|
||||||
|
else
|
||||||
|
SuR:StopDeployCutscene()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.DeathView", function()
|
||||||
|
local ent = net.ReadEntity()
|
||||||
|
hook.Add("CalcView", "SuR_DeathView", function(ply, pos, angles, fov)
|
||||||
|
if !IsValid(ent) or !ent:LookupAttachment('eyes') then
|
||||||
|
hook.Remove("CalcView", "SuR_DeathView")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local eye = ent:GetAttachment(ent:LookupAttachment('eyes'))
|
||||||
|
if isvector(eye.Pos) then
|
||||||
|
local view = {
|
||||||
|
origin = eye.Pos,
|
||||||
|
angles = eye.Ang,
|
||||||
|
fov = fov,
|
||||||
|
drawviewer = true,
|
||||||
|
nearz = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
timer.Simple(2, function()
|
||||||
|
LocalPlayer():ScreenFade(SCREENFADE.OUT, color_black, 1, 1)
|
||||||
|
end)
|
||||||
|
timer.Simple(3.5, function()
|
||||||
|
hook.Remove("CalcView", "SuR_DeathView")
|
||||||
|
LocalPlayer():ScreenFade(SCREENFADE.IN, color_black, 2, 1)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
@@ -0,0 +1,976 @@
|
|||||||
|
------------------------------------------------------------------------OTHER PART
|
||||||
|
SuR.Data = {}
|
||||||
|
SuR.Data["Wave"] = 0
|
||||||
|
SuR.Data["WaveState"] = false
|
||||||
|
SuR.Data["Enemies"] = 0
|
||||||
|
SuR.Data["DrawHUD"] = true
|
||||||
|
SuR.Data["DeployTime"] = 0
|
||||||
|
SuR.Data["Deploying"] = false
|
||||||
|
SuR.Data["Mutator"] = 0
|
||||||
|
SuR.Data["Fuel"] = 0
|
||||||
|
SuR.Data["MaxFuel"] = 0
|
||||||
|
SuR.Data["DisableMusic"] = false
|
||||||
|
|
||||||
|
local lang = SuR.Language
|
||||||
|
local hide = {
|
||||||
|
["CHudHealth"] = true,
|
||||||
|
["CHudAmmo"] = true,
|
||||||
|
["CHudSecondaryAmmo"] = true,
|
||||||
|
["CHudBattery"] = true,
|
||||||
|
["CHudCrosshair"] = true,
|
||||||
|
["CHudDamageIndicator"] = true,
|
||||||
|
["CHudWeaponSelection"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
hook.Add("HUDShouldDraw", "HideHUD", function( name )
|
||||||
|
if hide[name] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("DrawDeathNotice", "DisableKillfeed", function()
|
||||||
|
return 0,0
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.SendDataToClient", function()
|
||||||
|
local str = net.ReadString()
|
||||||
|
local value = net.ReadTable()[1]
|
||||||
|
SuR.Data[str] = value
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.MessageOnClient", function()
|
||||||
|
local fl = net.ReadFloat()
|
||||||
|
local value = net.ReadTable()[1]
|
||||||
|
message = ""
|
||||||
|
message2 = ""
|
||||||
|
if fl == 1 then
|
||||||
|
message = lang["message_main1"]
|
||||||
|
message2 = lang["message_main2"]
|
||||||
|
surface.PlaySound("surrounded/tick.wav")
|
||||||
|
elseif fl == 2 then
|
||||||
|
message = string.format(lang["message_wavestart1"], SuR.Data["Wave"])
|
||||||
|
message2 = lang["message_wavestart2"]
|
||||||
|
elseif fl == 3 then
|
||||||
|
message = string.format(lang["message_waveend1"], SuR.Data["Wave"])
|
||||||
|
message2 = lang["message_waveend2"]
|
||||||
|
elseif fl == 4 then
|
||||||
|
message = value:Nick()..lang["message_thelp1"]
|
||||||
|
message2 = lang["message_thelp2"]
|
||||||
|
surface.PlaySound("surrounded/sfx/player_downed.mp3")
|
||||||
|
elseif fl == 5 then
|
||||||
|
message = lang["message_tdied1"]
|
||||||
|
message2 = value:Nick()..lang["message_tdied2"]
|
||||||
|
surface.PlaySound("trials/player_death_02.wav")
|
||||||
|
elseif fl == 6 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_support"]
|
||||||
|
elseif fl == 7 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_mortar"]
|
||||||
|
elseif fl == 8 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_away"]
|
||||||
|
elseif fl == 9 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_supply"]
|
||||||
|
elseif fl == 10 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_heli"]
|
||||||
|
elseif fl == 11 then
|
||||||
|
message = lang["message_warn"]
|
||||||
|
|
||||||
|
local data = 2
|
||||||
|
if SuR.Data["Wave"] >= 14 then
|
||||||
|
data = 5
|
||||||
|
elseif SuR.Data["Wave"] >= 9 then
|
||||||
|
data = 4
|
||||||
|
elseif SuR.Data["Wave"] >= 5 then
|
||||||
|
data = 3
|
||||||
|
end
|
||||||
|
message2 = string.format(lang["message_zombie_phase"], data)
|
||||||
|
elseif fl == 12 then
|
||||||
|
message = lang["message_warn"]
|
||||||
|
message2 = lang["mutator_appear"]
|
||||||
|
elseif fl == 13 then
|
||||||
|
message = lang["message_radio_accept"]
|
||||||
|
message2 = lang["message_radio_exfil"]
|
||||||
|
elseif fl == 14 then
|
||||||
|
message = lang["message_warn"]
|
||||||
|
message2 = lang["zombie_choose"]
|
||||||
|
elseif fl == 14 then
|
||||||
|
message = lang["message_warn"]
|
||||||
|
message2 = lang["zombie_choose"]
|
||||||
|
elseif fl == 15 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = value..lang["message_radio_found"]
|
||||||
|
elseif fl == 16 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = lang["message_healed"]..value
|
||||||
|
elseif fl == 17 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = lang["message_healing"]..value
|
||||||
|
elseif fl == 18 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = value..lang["message_open_box"]
|
||||||
|
elseif fl == 19 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = value..lang["message_fuel"]
|
||||||
|
elseif fl == 20 then
|
||||||
|
message = lang["message_info"]
|
||||||
|
message2 = lang["message_obj_done"]
|
||||||
|
end
|
||||||
|
GiveMessageOnScreen(message, message2)
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------VOICE PART
|
||||||
|
local icon_voiceMat = Material('surrounded/voice.png')
|
||||||
|
local havevoices = 0
|
||||||
|
|
||||||
|
local function CreateVoicePanel(ply, bool)
|
||||||
|
if bool then
|
||||||
|
havevoices = havevoices + 1
|
||||||
|
local max = 0+(havevoices*He(36))
|
||||||
|
local nick = ""
|
||||||
|
if IsValid(ply) then
|
||||||
|
nick = ply:Nick()
|
||||||
|
end
|
||||||
|
hook.Add("HUDPaint", "ImageOnVoice"..ply:EntIndex(), function()
|
||||||
|
surface.SetMaterial(icon_voiceMat)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(We(10), He(320)-He(24)+max, We(48), He(48))
|
||||||
|
draw.SimpleText(nick, "SuR_SmallFont1", We(64), He(320)+max, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
havevoices = havevoices - 1
|
||||||
|
hook.Remove("HUDPaint", "ImageOnVoice"..ply:EntIndex())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("PlayerStartVoice", "ImageOnVoice", function(ply)
|
||||||
|
CreateVoicePanel(ply, true)
|
||||||
|
return false
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("PlayerEndVoice", "ImageOnVoice", function(ply)
|
||||||
|
CreateVoicePanel(ply, false)
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------HUD PART
|
||||||
|
|
||||||
|
local function create_fonts()
|
||||||
|
surface.CreateFont("SuR_PixelFont",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(10),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
surface.CreateFont("SuR_SmallFont1",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(16),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
surface.CreateFont("SuR_SmallFont2",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(24),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
surface.CreateFont("SuR_MediumFont1",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(32),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
surface.CreateFont("SuR_MediumFont2",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(48),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
surface.CreateFont("SuR_LargeFont1",{
|
||||||
|
font = "sur_font1",
|
||||||
|
extended = true,
|
||||||
|
size = He(64),
|
||||||
|
antialias = true,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
create_fonts()
|
||||||
|
hook.Add("OnScreenSizeChanged", "ChangeFonts", create_fonts)
|
||||||
|
|
||||||
|
local aMat = Material('surrounded/ammo_bg.png')
|
||||||
|
local vMat = Material('surrounded/wave_bg.png')
|
||||||
|
local gMat = Material('surrounded/gradient.png')
|
||||||
|
local cMat = Material('surrounded/crosshair.png')
|
||||||
|
local killMat = Material('surrounded/kill.png')
|
||||||
|
local icon_kickMat = Material('surrounded/kick.png')
|
||||||
|
local icon_vaultMat = Material('surrounded/vault.png')
|
||||||
|
local icon_ammoMat = Material('surrounded/ammo.png')
|
||||||
|
local icon_healMat = Material('surrounded/heal.png')
|
||||||
|
local icon_grenadeMat = Material('surrounded/grenade.png')
|
||||||
|
local icon_sprayMat = Material('surrounded/spray.png')
|
||||||
|
local icon_radioMat = Material('surrounded/radio_ab.png')
|
||||||
|
local icon_srkMat = Material('surrounded/srk.png')
|
||||||
|
local icon_spaceMat = Material('surrounded/space.png')
|
||||||
|
local icon_mutatorMat = Material('surrounded/mutator.png')
|
||||||
|
local vinMat = Material('surrounded/vin.png')
|
||||||
|
|
||||||
|
function GiveMessageOnScreen(m1, m2)
|
||||||
|
local long = 600
|
||||||
|
local longstate = true
|
||||||
|
timer.Simple(8, function()
|
||||||
|
longstate = false
|
||||||
|
end)
|
||||||
|
hook.Add("HUDPaint", "MainHUDMessage1", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
|
||||||
|
surface.SetMaterial(vMat)
|
||||||
|
surface.SetDrawColor(255,255,255,250)
|
||||||
|
surface.DrawTexturedRectRotated(ScrW()-We(300)+long, He(130), We(600), He(120), 180)
|
||||||
|
draw.SimpleText(m1, "SuR_SmallFont2", ScrW()-We(260)+long, He(110), Color(200,200,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(m2, "SuR_SmallFont1", ScrW()-We(260)+long, He(135), Color(200,20,20), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
|
||||||
|
if not longstate then
|
||||||
|
long = math.min(long+FrameTime()/0.001, 600)
|
||||||
|
if long == 600 then
|
||||||
|
hook.Remove("HUDPaint", "MainHUDMessage1")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
long = math.max(long-FrameTime()/0.001, 0)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ShowGameOverScreen()
|
||||||
|
local alpha = 0
|
||||||
|
local morealpha = true
|
||||||
|
local wave = net.ReadFloat()
|
||||||
|
local success = net.ReadBool()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local maintext = ""
|
||||||
|
SuR.Data["DrawHUD"] = false
|
||||||
|
if success then
|
||||||
|
SuR:PlayMusicOther(table.Random(SuR.Config.MusicWave["ExfilOver"]))
|
||||||
|
maintext = SuR.Language["game_over_success"]
|
||||||
|
else
|
||||||
|
SuR:PlayMusicOther(table.Random(SuR.Config.MusicWave["GameOver"]))
|
||||||
|
maintext = SuR.Language["game_over_main"]
|
||||||
|
end
|
||||||
|
ply:ScreenFade(SCREENFADE.OUT, color_black, 1, 1)
|
||||||
|
timer.Simple(2, function()
|
||||||
|
ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0)
|
||||||
|
hook.Add("HUDPaint", "Surrounded_TheEnd", function()
|
||||||
|
draw.SimpleText(maintext, "SuR_LargeFont1", ScrW()/2, ScrH()/2-He(300), Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
if not SuR.Config.Objective_Mode then
|
||||||
|
draw.SimpleText(string.format(SuR.Language["game_over_wave"], wave), "SuR_MediumFont1", ScrW()/2, ScrH()/2-He(180), Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
if morealpha then
|
||||||
|
alpha = math.Clamp(alpha+FrameTime()/0.01, 0, 255)
|
||||||
|
else
|
||||||
|
alpha = math.Clamp(alpha-FrameTime()/0.01, 0, 255)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
hook.Add("CalcView", "Surrounded_TheEnd",function(ply, pos, angles, fov)
|
||||||
|
local view = {
|
||||||
|
origin = SuR.Config.Camera_Position[1],
|
||||||
|
angles = SuR.Config.Camera_Position[2],
|
||||||
|
fov = fov,
|
||||||
|
drawviewer = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
end)
|
||||||
|
|
||||||
|
timer.Simple(SuR.Config.Game_Over_Screen_Delay-6, function()
|
||||||
|
ply:ScreenFade(SCREENFADE.OUT, color_black, 4, 1)
|
||||||
|
morealpha = false
|
||||||
|
timer.Simple(4, function()
|
||||||
|
ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0)
|
||||||
|
hook.Remove("CalcView", "Surrounded_TheEnd")
|
||||||
|
hook.Remove("HUDPaint", "Surrounded_TheEnd")
|
||||||
|
SuR.Data["DrawHUD"] = true
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
net.Receive("SuR.GameOverScreen", ShowGameOverScreen)
|
||||||
|
|
||||||
|
function SuR:StartPhrase()
|
||||||
|
local alpha = 0
|
||||||
|
local add1, add2, add3 = 0, 0, 0
|
||||||
|
local adddelay = 0
|
||||||
|
local morealpha = true
|
||||||
|
local text = lang["start_message1"]
|
||||||
|
if SuR.Config.Objective_Mode then
|
||||||
|
text = lang["start_message_fuel"]
|
||||||
|
end
|
||||||
|
timer.Simple(2, function()
|
||||||
|
hook.Add("HUDPaint", "Surrounded_Phrase", function()
|
||||||
|
draw.SimpleText(text, "SuR_SmallFont1", ScrW()/2+We(add1), ScrH()/2+He(200)+He(add2), Color(255,255,255,alpha+add3), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
if adddelay < CurTime() then
|
||||||
|
adddelay = CurTime()+0.05
|
||||||
|
add1, add2, add3 = math.Rand(-2,2), math.Rand(-2,2), math.Rand(-25,25)
|
||||||
|
end
|
||||||
|
if morealpha then
|
||||||
|
alpha = math.Clamp(alpha+FrameTime()/0.02, -25, 200)
|
||||||
|
else
|
||||||
|
alpha = math.Clamp(alpha-FrameTime()/0.02, -25, 200)
|
||||||
|
if alpha <= -25 then
|
||||||
|
hook.Remove("HUDPaint", "Surrounded_Phrase")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
timer.Simple(15, function()
|
||||||
|
morealpha = false
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local screen_kills = 0
|
||||||
|
local rndnum = 0
|
||||||
|
local alpha = 255
|
||||||
|
local function GiveKillsOnScreen()
|
||||||
|
local bool = net.ReadBool()
|
||||||
|
screen_kills = screen_kills + 1
|
||||||
|
alpha = 255
|
||||||
|
|
||||||
|
local alphaminus = false
|
||||||
|
local text = ""
|
||||||
|
if bool then
|
||||||
|
text = lang["killstreak_exec"]
|
||||||
|
rndnum = 10
|
||||||
|
elseif screen_kills == 2 then
|
||||||
|
text = lang["killstreak_1"]
|
||||||
|
rndnum = 8
|
||||||
|
elseif screen_kills == 3 then
|
||||||
|
text = lang["killstreak_2"]
|
||||||
|
rndnum = 12
|
||||||
|
elseif screen_kills == 4 then
|
||||||
|
text = lang["killstreak_3"]
|
||||||
|
rndnum = 16
|
||||||
|
elseif screen_kills == 5 then
|
||||||
|
text = lang["killstreak_4"]
|
||||||
|
rndnum = 20
|
||||||
|
end
|
||||||
|
hook.Add("HUDPaint", "MainHUDKills", function()
|
||||||
|
local w, h = ScrW(), ScrH()
|
||||||
|
local mat = Matrix()
|
||||||
|
|
||||||
|
rndnum = math.max(rndnum-FrameTime()/0.1, 0)
|
||||||
|
if alphaminus then
|
||||||
|
alpha = math.max(alpha-FrameTime()/0.001, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
mat:Translate(Vector(w/2+math.random(-rndnum,rndnum), 250+math.random(-rndnum,rndnum)))
|
||||||
|
mat:Rotate(Angle(0,math.random(-rndnum,rndnum),0))
|
||||||
|
mat:Scale(Vector(1,1,1))
|
||||||
|
mat:Translate(-Vector(w/2, h/2))
|
||||||
|
|
||||||
|
cam.PushModelMatrix(mat)
|
||||||
|
draw.SimpleTextOutlined(text, "SuR_SmallFont2", w/2, h/2, Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, Color(0, 0, 0, alpha))
|
||||||
|
cam.PopModelMatrix()
|
||||||
|
end)
|
||||||
|
timer.Simple(3.25, function()
|
||||||
|
alphaminus = true
|
||||||
|
end)
|
||||||
|
timer.Create("TimerScreenKills", 4, 1, function()
|
||||||
|
screen_kills = 0
|
||||||
|
hook.Remove("HUDPaint", "MainHUDKills")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
net.Receive("SuR.KillStatus", GiveKillsOnScreen)
|
||||||
|
|
||||||
|
local alpha = 255
|
||||||
|
local countdown_time = 0
|
||||||
|
local function Countdown(num)
|
||||||
|
countdown_time = countdown_time + 1
|
||||||
|
local mytime = countdown_time
|
||||||
|
for i=0,num-1 do
|
||||||
|
timer.Simple(i, function()
|
||||||
|
if mytime != countdown_time then return end
|
||||||
|
alpha = 255
|
||||||
|
surface.PlaySound("surrounded/tick.wav")
|
||||||
|
hook.Add("HUDPaint", "MainHUDTimer", function()
|
||||||
|
alpha = math.max(alpha-FrameTime()/0.004, 0)
|
||||||
|
if alpha == 0 then
|
||||||
|
hook.Remove("HUDPaint", "MainHUDTimer")
|
||||||
|
end
|
||||||
|
draw.SimpleTextOutlined(num-i, "SuR_LargeFont1", ScrW()/2, He(250), Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, Color(0, 0, 0, alpha))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
net.Receive("SuR.Countdown", function()
|
||||||
|
local f = net.ReadFloat()
|
||||||
|
Countdown(f)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cvars.AddChangeCallback("sur_disable_hud", function(convar_name, value_old, value_new)
|
||||||
|
if tonumber(value_new) == 0 then
|
||||||
|
SuR.Data["DrawHUD"] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local wave_long = 300
|
||||||
|
local wave_longstate = false
|
||||||
|
local player_health_alpha = 0
|
||||||
|
local player_health_alphab = false
|
||||||
|
local player_infected_alpha = 0
|
||||||
|
local player_infected_alphab = false
|
||||||
|
local mut_we = 650
|
||||||
|
hook.Add("HUDPaint", "MainHUD", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
|
||||||
|
if SuR.Data["GameplayBlockNode"] == true then
|
||||||
|
surface.SetFont("SuR_SmallFont2")
|
||||||
|
local x = surface.GetTextSize(lang["deploy_error_node"])
|
||||||
|
|
||||||
|
surface.SetDrawColor(0,0,0,200)
|
||||||
|
surface.DrawRect(ScrW()/2-(x/2+5), He(385), (x+10), He(30))
|
||||||
|
draw.SimpleText(lang["deploy_error_node"], "SuR_SmallFont2", ScrW()/2, He(400), Color(200,20,20,255*math.abs(math.cos(CurTime()))), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
if SuR.Data["GameplayBlockConfig"] == true then
|
||||||
|
surface.SetFont("SuR_SmallFont2")
|
||||||
|
local x = surface.GetTextSize(lang["deploy_error_config"])
|
||||||
|
|
||||||
|
surface.SetDrawColor(0,0,0,200)
|
||||||
|
surface.DrawRect(ScrW()/2-(x/2+5), He(415), (x+10), He(30))
|
||||||
|
draw.SimpleText(lang["deploy_error_config"], "SuR_SmallFont2", ScrW()/2, He(430), Color(200,20,20,255*math.abs(math.cos(CurTime()))), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not SuR.Config.Deploy_Cutscene.cam and SuR.Data["Deploying"] and SuR.Data["DeployTime"]-CurTime() > 0 then
|
||||||
|
local dtime = math.floor(SuR.Data["DeployTime"]-CurTime())
|
||||||
|
draw.SimpleText(string.format(lang["deploy_time"], dtime), "SuR_MediumFont1", ScrW()/2, ScrH()-He(130), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText(lang["deploy_hint"], "SuR_SmallFont1", ScrW()/2, ScrH()-He(100), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
if GetConVar("sur_disable_hud"):GetBool() then
|
||||||
|
SuR.Data["DrawHUD"] = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local drawhud = ply:Alive() and !ply:IsDowned() and SuR.Data["DrawHUD"]
|
||||||
|
if drawhud then
|
||||||
|
local see = ply:GetEyeTrace()
|
||||||
|
|
||||||
|
local bug = ply:GetNWFloat('BuggedPos')
|
||||||
|
if bug > 0.3 then
|
||||||
|
draw.SimpleText(lang["unreachable"], "SuR_SmallFont1", ScrW()/2, 200, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
local tr = see.Entity
|
||||||
|
if !ply:IsLockedAbilities() and IsValid(tr) and string.match(tr:GetClass(), "vj") and tr:GetPos():DistToSqr(ply:GetPos()) < 10000 and tr:GetNWBool('flinching', false) and tr:Health() <= 200 then
|
||||||
|
local pos = (tr:EyePos()):ToScreen()
|
||||||
|
if tr:LookupAttachment("eyes") > 0 then
|
||||||
|
pos = (tr:GetAttachment(tr:LookupAttachment("eyes")).Pos):ToScreen()
|
||||||
|
end
|
||||||
|
|
||||||
|
surface.SetMaterial(killMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(pos.x-48,pos.y-160,96,96)
|
||||||
|
end
|
||||||
|
|
||||||
|
if !ply:IsLockedAbilities() and ply:IsSurvivor() then
|
||||||
|
local tr2 = util.TraceLine({
|
||||||
|
start = ply:EyePos(),
|
||||||
|
endpos = ply:EyePos() + ply:GetAimVector() * 72,
|
||||||
|
filter = ply,
|
||||||
|
})
|
||||||
|
if IsValid(tr2.Entity) and tr2.Entity:IsPlayer() and not tr2.Entity:IsDowned() and tr2.Entity:GetNWBool("IsInfected") and ply:GetNWFloat('Sprays') > 0 then
|
||||||
|
draw.SimpleText(lang["heal_spray"], "SuR_SmallFont2", ScrW()/2, ScrH()-He(300), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
elseif IsValid(tr2.Entity) and tr2.Entity:IsPlayer() and not tr2.Entity:IsDowned() and tr2.Entity:Health() < 100 and ply:GetNWFloat("Bandages") > 0 then
|
||||||
|
draw.SimpleText(lang["heal_bandages"], "SuR_SmallFont2", ScrW()/2, ScrH()-He(300), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local h = ply:GetInfection()
|
||||||
|
if h > 0 then
|
||||||
|
surface.SetMaterial(vinMat)
|
||||||
|
surface.SetDrawColor(70,0,125,player_infected_alpha)
|
||||||
|
surface.DrawTexturedRect(0, 0, ScrW(), ScrH())
|
||||||
|
|
||||||
|
surface.SetDrawColor(0,0,0,(h+1-1)*250)
|
||||||
|
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||||
|
|
||||||
|
if player_infected_alpha <= 0 then
|
||||||
|
player_infected_alphab = true
|
||||||
|
elseif player_infected_alpha >= (h+1-1)*125 then
|
||||||
|
player_infected_alphab = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if player_infected_alphab then
|
||||||
|
player_infected_alpha = player_infected_alpha+FrameTime()/0.05
|
||||||
|
else
|
||||||
|
player_infected_alpha = player_infected_alpha-FrameTime()/0.05
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local h = ply:Health()
|
||||||
|
if h < 80 then
|
||||||
|
surface.SetMaterial(vinMat)
|
||||||
|
surface.SetDrawColor(75,0,0,player_health_alpha)
|
||||||
|
surface.DrawTexturedRect(0, 0, ScrW(), ScrH())
|
||||||
|
|
||||||
|
if player_health_alpha <= 0 then
|
||||||
|
player_health_alphab = true
|
||||||
|
elseif player_health_alpha >= (80-h)*1.5 then
|
||||||
|
player_health_alphab = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if player_health_alphab then
|
||||||
|
player_health_alpha = player_health_alpha+(FrameTime()/(ply:Health()/ply:GetMaxHealth()))/0.1
|
||||||
|
else
|
||||||
|
player_health_alpha = player_health_alpha-(FrameTime()/(ply:Health()/ply:GetMaxHealth()))/0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
local ent1 = see.Entity
|
||||||
|
if IsValid(ent1) and see.HitPos:Distance(ply:EyePos()) < 96 then
|
||||||
|
local loot = ent1:GetNWString("LootName", "")
|
||||||
|
local name = SuR.Language[loot]
|
||||||
|
if not name then
|
||||||
|
name = loot
|
||||||
|
end
|
||||||
|
if name != '' then
|
||||||
|
draw.SimpleText(lang["main_pickup"]..name, "SuR_SmallFont2", ScrW()/2, ScrH()-He(150), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
surface.SetMaterial(gMat)
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.DrawTexturedRect(We(15), ScrH()-He(130), We(240), He(60))
|
||||||
|
draw.SimpleText("+ "..ply:Health(), "SuR_MediumFont2", We(25), ScrH()-He(75), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
surface.SetMaterial(gMat)
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.DrawTexturedRect(We(15), He(35), We(300), He(80))
|
||||||
|
|
||||||
|
local icon = SuR.Config.ClassIcons[ply:GetPlayerClass()]
|
||||||
|
surface.SetMaterial(icon)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(We(20), He(39), We(72), He(72))
|
||||||
|
|
||||||
|
draw.SimpleText(lang["class_"..ply:GetPlayerClass()], "SuR_SmallFont2", We(100), We(70), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
draw.SimpleText(lang["class_lvl_"..ply:GetLevel()], "SuR_SmallFont1", We(100), He(85), Color(200,200,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
|
||||||
|
surface.SetDrawColor(120,120,120,50)
|
||||||
|
surface.DrawRect(We(100), He(95), We(120), He(3))
|
||||||
|
|
||||||
|
local mult = ((ply:GetXPToLevel()/ply:GetXPToLevel(true))*-1+1)
|
||||||
|
if ply:GetLevel() == 21 then
|
||||||
|
mult = 1
|
||||||
|
end
|
||||||
|
surface.SetDrawColor(240,240,120,150)
|
||||||
|
surface.DrawRect(We(100), He(95), We(120)*mult, He(3))
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
local mut = SuR.Data["Mutator"]
|
||||||
|
if mut > 0 then
|
||||||
|
mut_we = math.max(mut_we-FrameTime()/0.005, 0)
|
||||||
|
else
|
||||||
|
mut_we = math.min(mut_we+FrameTime()/0.005, 650)
|
||||||
|
end
|
||||||
|
|
||||||
|
surface.SetMaterial(aMat)
|
||||||
|
surface.SetDrawColor(Color(0,0,0,200))
|
||||||
|
surface.DrawTexturedRect(We(15-mut_we), ScrH()-He(275), We(560), He(130))
|
||||||
|
|
||||||
|
surface.SetMaterial(icon_mutatorMat)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(We(60-mut_we), ScrH()-He(260), We(60), He(60))
|
||||||
|
|
||||||
|
draw.SimpleText(lang["mutator_main"], "SuR_SmallFont1", We(145-mut_we), ScrH()-He(250), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
if mut > 0 then
|
||||||
|
draw.SimpleText(lang["mutator_"..mut], "SuR_SmallFont2", We(145-mut_we), ScrH()-He(230), Color(200,200,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(lang["mutator_"..mut.."_desc"], "SuR_SmallFont1", We(80-mut_we), ScrH()-He(190), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
local tr = (see.HitPos):ToScreen()
|
||||||
|
local wep = ply:GetActiveWeapon()
|
||||||
|
local drawcrosshair = IsValid(wep) and !ply:IsDowned() and !ply:GetNWBool('SVAnimStopCutscene') and ply:ShouldDrawLocalPlayer()
|
||||||
|
|
||||||
|
if drawcrosshair then
|
||||||
|
surface.SetMaterial(cMat)
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
surface.DrawTexturedRect(tr.x-16, tr.y-16, We(32), He(32))
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
local drawweapon = IsValid(wep) and wep:GetPrintName()
|
||||||
|
if drawweapon and ply:IsSurvivor() then
|
||||||
|
local tier = 0
|
||||||
|
local clip = wep:Clip1()
|
||||||
|
local maxclip = wep:GetMaxClip1()
|
||||||
|
local ammo = ply:GetAmmoCount(wep:GetPrimaryAmmoType())
|
||||||
|
local color = color_white
|
||||||
|
local color2 = color_white
|
||||||
|
if clip == -1 then
|
||||||
|
clip = 0
|
||||||
|
end
|
||||||
|
if clip == 0 then
|
||||||
|
color = Color(200,20,20)
|
||||||
|
end
|
||||||
|
if ammo == 0 then
|
||||||
|
color2 = Color(200,20,20)
|
||||||
|
elseif ammo <= maxclip then
|
||||||
|
color2 = Color(200,150,20)
|
||||||
|
end
|
||||||
|
if maxclip > 0 then
|
||||||
|
surface.SetMaterial(aMat)
|
||||||
|
surface.SetDrawColor(Color(255,255,255,240))
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(550), ScrH()-He(250), We(400), He(220))
|
||||||
|
|
||||||
|
draw.SimpleText(clip, "SuR_MediumFont2", ScrW()-We(430), ScrH()-He(130), color, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("/", "SuR_MediumFont2", ScrW()-We(420), ScrH()-He(120), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(maxclip, "SuR_MediumFont2", ScrW()-We(410), ScrH()-He(110), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
|
||||||
|
surface.SetMaterial(icon_ammoMat)
|
||||||
|
surface.SetDrawColor(Color(255,255,255,240))
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(275), ScrH()-He(160), We(48), He(48))
|
||||||
|
draw.SimpleText(ammo, "SuR_SmallFont2", ScrW()-We(250), ScrH()-He(100), color2, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(aMat)
|
||||||
|
surface.SetDrawColor(Color(255,255,255,240))
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(550), ScrH()-He(240), We(400), He(110))
|
||||||
|
end
|
||||||
|
draw.SimpleText(wep:GetPrintName(), "SuR_SmallFont2", ScrW()-We(500), ScrH()-He(205), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
|
||||||
|
local t = SuR.Config.TierWeapons
|
||||||
|
local cl = wep:GetClass()
|
||||||
|
if table.HasValue(t["Tier1"], cl) then
|
||||||
|
tier = 1
|
||||||
|
elseif table.HasValue(t["Tier2"], cl) or table.HasValue(t["Melee"], cl) then
|
||||||
|
tier = 2
|
||||||
|
elseif table.HasValue(t["Tier3"], cl) or table.HasValue(t["Other"], cl) then
|
||||||
|
tier = 3
|
||||||
|
elseif table.HasValue(t["Tier4"], cl) then
|
||||||
|
tier = 4
|
||||||
|
elseif table.HasValue(t["Tier5"], cl) then
|
||||||
|
tier = 5
|
||||||
|
end
|
||||||
|
if wep:GetNWFloat('Tier') > 0 then
|
||||||
|
tier = wep:GetNWFloat('Tier')
|
||||||
|
end
|
||||||
|
if tier > 0 then
|
||||||
|
draw.SimpleText(lang["loot_tier"..tier], "SuR_SmallFont1", ScrW()-We(500), ScrH()-He(180), SuR.Config.Tier_Colors[tier], TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
if ply:IsSurvivor() then
|
||||||
|
surface.SetMaterial(gMat)
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.DrawTexturedRect(We(15), He(230), We(150), He(50))
|
||||||
|
draw.SimpleText("$ "..ply:GetNWInt('Money'), "SuR_SmallFont2", We(25), He(240), SuR.Config.Tier_Colors[tier], TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
|
||||||
|
if string.match(ply:GetSVAnim(), "grappleloop") or ply:IsStunned(true) then
|
||||||
|
surface.SetMaterial(icon_spaceMat)
|
||||||
|
if input.IsKeyDown(KEY_SPACE) then
|
||||||
|
surface.SetDrawColor(100,255,100)
|
||||||
|
else
|
||||||
|
surface.SetDrawColor(255,255,255)
|
||||||
|
end
|
||||||
|
if ply:IsStunned(true) then
|
||||||
|
surface.DrawTexturedRectRotated(ScrW()/2, ScrH()-He(150), We(350), He(350), 8*math.sin(CurTime()*4))
|
||||||
|
else
|
||||||
|
surface.DrawTexturedRectRotated(ScrW()/2+math.Rand(-5,5), ScrH()-He(150)+math.Rand(-5,5), We(350), He(350), 10*math.sin(CurTime()*4))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetNWFloat('SelfRevive') > 0 then
|
||||||
|
surface.SetMaterial(icon_srkMat)
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.DrawTexturedRect(We(10), ScrH()-He(75), We(80), He(75))
|
||||||
|
draw.SimpleText(ply:GetNWFloat('SelfRevive'), "SuR_SmallFont2", We(85), ScrH()-He(10), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_srkMat)
|
||||||
|
surface.SetDrawColor(0,0,0,100)
|
||||||
|
surface.DrawTexturedRect(We(10), ScrH()-He(75), We(80), He(75))
|
||||||
|
draw.SimpleText(ply:GetNWFloat('SelfRevive'), "SuR_SmallFont2", We(85), ScrH()-He(10), Color(0,0,0,100), TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetNWFloat('CanCallSupport') > 0 and !ply:IsLockedAbilities() then
|
||||||
|
surface.SetMaterial(icon_radioMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(800), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("M", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(700), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat('CanCallSupport'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(685), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_radioMat)
|
||||||
|
surface.SetDrawColor(100,0,0,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(800), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("M", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(700), Color(100,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat('CanCallSupport'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(685), Color(100,0,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetInfection() > 0 and ply:GetNWFloat('Sprays') > 0 and !ply:IsLockedAbilities() then
|
||||||
|
surface.SetMaterial(icon_sprayMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(650), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("H", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(550), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat('Sprays'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(535), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_sprayMat)
|
||||||
|
surface.SetDrawColor(100,0,0,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(650), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("H", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(550), Color(100,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat('Sprays'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(535), Color(100,0,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetNWBool('CanHeal') and !ply:IsLockedAbilities() and ply:GetNWFloat("Bandages") > 0 then
|
||||||
|
surface.SetMaterial(icon_healMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(500), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("B", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(400), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat("Bandages"), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(385), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_healMat)
|
||||||
|
surface.SetDrawColor(100,0,0,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(500), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("B", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(400), Color(100,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWFloat("Bandages"), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(385), Color(100,0,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetNWInt('Grenades') > 0 and !ply:IsLockedAbilities() then
|
||||||
|
surface.SetMaterial(icon_grenadeMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(350), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("L", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(250), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWInt('Grenades'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(235), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_grenadeMat)
|
||||||
|
surface.SetDrawColor(100,0,0,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(350), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("L", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(250), Color(100,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText("x"..ply:GetNWInt('Grenades'), "SuR_SmallFont1", ScrW()-We(60), ScrH()-He(235), Color(100,0,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:GetNWBool('CanVault') and !ply:IsLockedAbilities() then
|
||||||
|
surface.SetMaterial(icon_vaultMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(250), ScrH()-He(350), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("V", "SuR_MediumFont1", ScrW()-We(200), ScrH()-He(250), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
if !ply:IsLockedAbilities() then
|
||||||
|
surface.SetMaterial(icon_kickMat)
|
||||||
|
surface.SetDrawColor(255,255,255,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(200), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("G", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(100), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
surface.SetMaterial(icon_kickMat)
|
||||||
|
surface.SetDrawColor(100,0,0,240)
|
||||||
|
surface.DrawTexturedRect(ScrW()-We(125), ScrH()-He(200), We(100), He(100))
|
||||||
|
|
||||||
|
draw.SimpleText("G", "SuR_MediumFont1", ScrW()-We(75), ScrH()-He(100), Color(100,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = ply:EyePos(),
|
||||||
|
endpos = ply:EyePos() + ply:GetAimVector() * 50,
|
||||||
|
filter = ply,
|
||||||
|
mask = MASK_SHOT_HULL
|
||||||
|
})
|
||||||
|
|
||||||
|
local ent = tr.Entity
|
||||||
|
if IsValid(ent) and ent:IsPlayer() and ent:IsDowned() and !ply:IsDowned() and ply:Alive() and ply:GetVelocity():Length() < 10 then
|
||||||
|
draw.SimpleText(lang["revive_help"], "SuR_MediumFont1", ScrW()/2, ScrH()-He(150), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
surface.SetMaterial(vinMat)
|
||||||
|
surface.SetDrawColor(70,0,125,100)
|
||||||
|
surface.DrawTexturedRect(0, 0, ScrW(), ScrH())
|
||||||
|
|
||||||
|
draw.SimpleText(lang["zombie_attack1"], "SuR_MediumFont1", ScrW()-We(100), ScrH()-He(140), color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(lang["zombie_attack2"], "SuR_MediumFont1", ScrW()-We(100), ScrH()-He(110), color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
elseif not drawhud and ply:IsZombie() then
|
||||||
|
if !ply:Alive() and SuR.Data["WaveState"] then
|
||||||
|
draw.SimpleText(lang["zombie_spawn"], "SuR_MediumFont1", ScrW()/2, ScrH()-He(200), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(lang["zombie_menu"], "SuR_SmallFont2", ScrW()/2, ScrH()-He(230), Color(225,200,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
elseif !ply:Alive() and not SuR.Data["WaveState"] then
|
||||||
|
draw.SimpleText(lang["zombie_wait"], "SuR_MediumFont1", ScrW()/2, ScrH()-He(200), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(lang["zombie_menu"], "SuR_SmallFont2", ScrW()/2, ScrH()-He(230), Color(225,200,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
draw.SimpleText("SURROUNDED - v"..SuR.Version.." ["..SuR.Build.."]", "SuR_SmallFont1", 5, 5, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(lang["hud_discord_join"], "SuR_PixelFont", 5, He(22), Color(225, 200, 0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
|
||||||
|
surface.SetMaterial(vMat)
|
||||||
|
surface.SetDrawColor(255,255,255,250)
|
||||||
|
surface.DrawTexturedRect(0-wave_long, He(130), We(230), He(70))
|
||||||
|
if SuR.Data["ExfilWave"] then
|
||||||
|
draw.SimpleText(lang["evac"], "SuR_MediumFont1", We(15)-wave_long, He(145), Color(200,200*math.cos(CurTime()*3),200*math.cos(CurTime()*3)), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
elseif SuR.Config.Objective_Mode then
|
||||||
|
local fuel, maxfuel = SuR.Data["Fuel"], SuR.Data["MaxFuel"]
|
||||||
|
draw.SimpleText(lang["fuel"], "SuR_SmallFont1", We(110)-wave_long, He(145), Color(200,200,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
draw.SimpleText(fuel.."/"..maxfuel, "SuR_MediumFont1", We(110)-wave_long, He(160), Color(200,200,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
||||||
|
else
|
||||||
|
draw.SimpleText(lang["main_wave"]..SuR.Data["Wave"], "SuR_MediumFont1", We(15)-wave_long, He(140), Color(200,200,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
if wave_longstate then
|
||||||
|
draw.SimpleText(lang["main_count"]..SuR.Data["Enemies"], "SuR_SmallFont1", We(15)-wave_long, He(175), Color(100,20,20), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
wave_longstate = SuR.Data["WaveState"]
|
||||||
|
if not wave_longstate then
|
||||||
|
wave_long = math.min(wave_long+FrameTime()/0.005, 300)
|
||||||
|
else
|
||||||
|
wave_long = math.max(wave_long-FrameTime()/0.005, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local tab = player.GetAll()
|
||||||
|
for i=1,#tab do
|
||||||
|
local ent = tab[i]
|
||||||
|
if ent:Team() != ply:Team() then continue end
|
||||||
|
if ent != ply and ent:Alive() and ent:IsLineOfSightClear(ply) then
|
||||||
|
local pos = (ent:GetBonePosition(ent:LookupBone("ValveBiped.Bip01_Head1"))+Vector(0,0,20)):ToScreen()
|
||||||
|
if string.match(ent:GetSVAnim(), "executions") or string.match(ent:GetSVAnim(), "killmove") or string.match(ent:GetSVAnim(), "grappleloop") then
|
||||||
|
draw.SimpleText(ent:Nick(), "SuR_SmallFont1", pos.x, pos.y-He(16), Color(200,120,20), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText("[HELP]", "SuR_SmallFont1", pos.x, pos.y, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
elseif ent:IsDowned() then
|
||||||
|
draw.SimpleText(ent:Nick(), "SuR_SmallFont1", pos.x, pos.y-He(16), Color(200,20,20), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText("[+]", "SuR_SmallFont1", pos.x, pos.y, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
else
|
||||||
|
local alpha = 255/(ent:EyePos():Distance(EyePos())/500)
|
||||||
|
if alpha > 200 then
|
||||||
|
draw.SimpleText(ent:Nick(), "SuR_SmallFont1", pos.x, pos.y, Color(255,255,255,alpha), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
|
||||||
|
local icon = SuR.Config.ClassIcons[ent:GetPlayerClass()]
|
||||||
|
surface.SetMaterial(icon)
|
||||||
|
surface.SetDrawColor(255,255,255,alpha)
|
||||||
|
surface.DrawTexturedRect(pos.x-We(40), pos.y-He(16), We(32), He(32))
|
||||||
|
else
|
||||||
|
draw.SimpleText(ent:Nick(), "SuR_PixelFont", pos.x, pos.y, Color(255,255,255,alpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ply:IsDowned() then
|
||||||
|
draw.SimpleText(lang["revive_main"], "SuR_MediumFont1", ScrW()/2, ScrH()-He(150), Color(200,20,20), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
draw.SimpleText(lang["revive_wait"], "SuR_SmallFont2", ScrW()/2, ScrH()-He(110), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
|
||||||
|
if ply:GetNWFloat('SelfRevive') > 0 and ply:GetSVAnim() != "sur_selfrevive" then
|
||||||
|
draw.SimpleText(lang["revive_self"], "SuR_SmallFont1", ScrW()/2, ScrH()-He(300), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
||||||
|
surface.SetMaterial(icon_srkMat)
|
||||||
|
surface.SetDrawColor(255,255,255,150)
|
||||||
|
surface.DrawTexturedRect(ScrW()/2-We(35), ScrH()-He(300), We(80), He(75))
|
||||||
|
draw.SimpleText(ply:GetNWFloat('SelfRevive'), "SuR_SmallFont2", ScrW()/2+We(35), ScrH()-He(235), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local addmat_r = Material("surrounded/add_r")
|
||||||
|
local addmat_g = Material("surrounded/add_g")
|
||||||
|
local addmat_b = Material("surrounded/add_b")
|
||||||
|
local vgbm = Material("vgui/black")
|
||||||
|
|
||||||
|
function DrawCA(rx, gx, bx, ry, gy, by)
|
||||||
|
render.UpdateScreenEffectTexture()
|
||||||
|
|
||||||
|
addmat_r:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||||
|
addmat_g:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||||
|
addmat_b:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||||
|
|
||||||
|
render.SetMaterial(vgbm)
|
||||||
|
render.DrawScreenQuad()
|
||||||
|
|
||||||
|
render.SetMaterial(addmat_r)
|
||||||
|
render.DrawScreenQuadEx(-rx / 2, -ry / 2, ScrW() + rx, ScrH() + ry)
|
||||||
|
|
||||||
|
render.SetMaterial(addmat_g)
|
||||||
|
render.DrawScreenQuadEx(-gx / 2, -gy / 2, ScrW() + gx, ScrH() + gy)
|
||||||
|
|
||||||
|
render.SetMaterial(addmat_b)
|
||||||
|
render.DrawScreenQuadEx(-bx / 2, -by / 2, ScrW() + bx, ScrH() + by)
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("RenderScreenspaceEffects", "MainColorHP", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local death = isfunction(hook.GetTable()["CalcView"]["SuR_DeathView"])
|
||||||
|
if ply:Alive() or death then
|
||||||
|
local tab = {
|
||||||
|
["$pp_colour_contrast"] = (ply:Health()/ply:GetMaxHealth())/4+0.75,
|
||||||
|
["$pp_colour_colour"] = (ply:Health()/ply:GetMaxHealth()),
|
||||||
|
}
|
||||||
|
if ply:IsDowned() or death then
|
||||||
|
tab = {
|
||||||
|
["$pp_colour_contrast"] = 0.75,
|
||||||
|
["$pp_colour_colour"] = 0.1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
DrawColorModify(tab)
|
||||||
|
|
||||||
|
local num = ply:IsDowned() and 25 or ( (1-(ply:Health()/ply:GetMaxHealth()))*10 )
|
||||||
|
if ply:Health() < 50 or ply:IsDowned() or death then
|
||||||
|
num = num*math.abs(math.sin(CurTime()))+0.1
|
||||||
|
if num > 0 then
|
||||||
|
DrawCA(4 * num, 2 * num, 0, 2 * num, 1 * num, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------WORK PART
|
||||||
|
|
||||||
|
hook.Add("InitPostEntity", "MainDeleter", function()
|
||||||
|
function GAMEMODE:HUDDrawTargetID() end
|
||||||
|
function GAMEMODE:HUDDrawPickupHistory() end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local bindfalse = {
|
||||||
|
["-voicerecord"] = true,
|
||||||
|
["+voicerecord"] = true,
|
||||||
|
["messagemode"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local movebind = {
|
||||||
|
["-forward"] = true,
|
||||||
|
["+forward"] = true,
|
||||||
|
["-moveleft"] = true,
|
||||||
|
["+moveleft"] = true,
|
||||||
|
["-moveright"] = true,
|
||||||
|
["+moveright"] = true,
|
||||||
|
["-back"] = true,
|
||||||
|
["+back"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
hook.Add("PlayerBindPress", "Main_PlayerBindPress", function(ply, bind, pressed)
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
local cutscene = ply:GetNWBool('SVAnimStopCutscene')
|
||||||
|
if (ply:KeyDown(IN_DUCK) or !ply:OnGround()) and bind == "+jump" then return true end
|
||||||
|
if (ply:KeyDown(IN_JUMP) or !ply:OnGround()) and bind == "+duck" then return true end
|
||||||
|
if cutscene and not bindfalse[bind] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if ply:IsDowned() and not bindfalse[bind] and not movebind[bind] then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,732 @@
|
|||||||
|
function render.BorderSphereUnit( color, pos, radius, detail, thickness, dds )
|
||||||
|
local snr = {[0]=2,[1]=1,[3]=2,[5]=1,[7]=2,[9]=1}
|
||||||
|
local lens = string.len( tostring( radius ) )
|
||||||
|
local thickness = math.floor( thickness ) or 24
|
||||||
|
local detail = math.min( math.floor( detail ), 100 ) or 32
|
||||||
|
local radius = math.floor( radius )
|
||||||
|
local ds = 0
|
||||||
|
|
||||||
|
if thickness >= radius then thickness = radius end
|
||||||
|
|
||||||
|
if dds ~= true then
|
||||||
|
if snr[tonumber( string.sub( tostring( radius ), lens, lens ) )] == 1 then ds = 1 end
|
||||||
|
if snr[tonumber( string.sub( tostring( radius ), lens, lens ) )] == 2 then ds = 0.50 end
|
||||||
|
end
|
||||||
|
|
||||||
|
cam.IgnoreZ(false)
|
||||||
|
render.SetStencilEnable(true)
|
||||||
|
render.SetStencilReferenceValue( 0x55 )
|
||||||
|
render.SetStencilTestMask( 0x1C )
|
||||||
|
render.SetStencilWriteMask( 0x1C )
|
||||||
|
render.ClearStencil()
|
||||||
|
render.SetColorMaterial()
|
||||||
|
|
||||||
|
render.SetStencilReferenceValue( 1 )
|
||||||
|
render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS )
|
||||||
|
|
||||||
|
render.SetStencilZFailOperation( STENCILOPERATION_INVERT )
|
||||||
|
|
||||||
|
render.DrawSphere( pos, -radius, detail, detail, Color( 0, 0, 0, 0 ) )
|
||||||
|
render.DrawSphere( pos, radius, detail, detail, Color( 0, 0, 0, 0 ) )
|
||||||
|
render.DrawSphere( pos, -( radius -thickness ), detail +ds, detail +ds, Color( 0, 0, 0, 0 ) )
|
||||||
|
render.DrawSphere( pos, ( radius -thickness ), detail +ds, detail +ds, Color( 0, 0, 0, 0 ) )
|
||||||
|
|
||||||
|
if dds ~= true then
|
||||||
|
render.SetStencilZFailOperation( STENCILOPERATION_REPLACE )
|
||||||
|
render.DrawSphere( pos, radius +0.25, detail +ds, detail +ds, Color( 0, 0, 0, 0 ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_NOTEQUAL )
|
||||||
|
|
||||||
|
local cam_pos = LocalPlayer():EyePos()
|
||||||
|
local cam_angle = LocalPlayer():EyeAngles()
|
||||||
|
|
||||||
|
if LocalPlayer():GetViewEntity() ~= LocalPlayer() then
|
||||||
|
cam_pos = ( LocalPlayer():GetViewEntity() ):GetPos()
|
||||||
|
cam_angle = ( LocalPlayer():GetViewEntity() ):GetAngles()
|
||||||
|
end
|
||||||
|
|
||||||
|
local cam_normal = cam_angle:Forward()
|
||||||
|
|
||||||
|
cam.IgnoreZ(true)
|
||||||
|
render.SetStencilReferenceValue( 1 )
|
||||||
|
render.DrawQuadEasy( cam_pos + cam_normal * 10, -cam_normal, 10000, 10000, color, cam_angle.roll )
|
||||||
|
cam.IgnoreZ(false)
|
||||||
|
render.SetStencilEnable(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
local delay = 0
|
||||||
|
hook.Add("Think", "SuR.ClearErrorModels", function()
|
||||||
|
if delay > CurTime() then return end
|
||||||
|
delay = CurTime()+15
|
||||||
|
|
||||||
|
for _, ent in ipairs(ents.GetAll()) do
|
||||||
|
if !ent:IsPlayer() and !ent:IsNPC() and ent:GetModel() == "models/error.mdl" then
|
||||||
|
ent:SetRenderMode(10)
|
||||||
|
ent:SetMaterial("null")
|
||||||
|
ent:SetNoDraw(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.PrecacheModels", function()
|
||||||
|
local tab = net.ReadTable()
|
||||||
|
for _, m in ipairs(tab) do
|
||||||
|
util.PrecacheModel(m)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.BecomeRagdoll", function()
|
||||||
|
local ent = net.ReadEntity()
|
||||||
|
if IsValid(ent) then
|
||||||
|
local base = ent:BecomeRagdollOnClient()
|
||||||
|
if IsValid(base) then
|
||||||
|
local rag = ClientsideRagdoll(base:GetModel())
|
||||||
|
rag:SetPos(base:GetPos())
|
||||||
|
SuR:TransferModelData(base, rag)
|
||||||
|
SuR:TransferBones(base, rag)
|
||||||
|
rag:SetNoDraw(false)
|
||||||
|
base:Remove()
|
||||||
|
SafeRemoveEntityDelayed(rag, 60)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
concommand.Add("sur_debug_animations", function(ply)
|
||||||
|
MsgC(Color(150,250,150), "Debug Tool Info:\n\n----------------\n\n")
|
||||||
|
MsgC(Color(250,250,250), "Count of Sequences: "..ply:GetSequenceCount().."\n")
|
||||||
|
MsgC(Color(200,200,200), "List of Sequences: \n\n")
|
||||||
|
for i=0,ply:GetSequenceCount()-1 do
|
||||||
|
timer.Simple(3+(i/100), function()
|
||||||
|
local name = ply:GetSequenceName(i)
|
||||||
|
local long = math.Round(select(2, ply:LookupSequence(name)), 3)
|
||||||
|
MsgC(Color(250,250,250), "ID: "..i.." Name:"..name.." Duration:"..long.."\n")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-----------------------FIRST PERSON BODY, TAKED FROM WORKSHOP, DONT BEAT ME PLS
|
||||||
|
|
||||||
|
local cache = {}
|
||||||
|
local _GetChildBonesRecursive
|
||||||
|
local mdl = ""
|
||||||
|
|
||||||
|
_GetChildBonesRecursive = function(ent, bone, src)
|
||||||
|
local t = src or {}
|
||||||
|
table.insert(t, bone)
|
||||||
|
local cbones = ent:GetChildBones(bone)
|
||||||
|
|
||||||
|
if cbones then
|
||||||
|
for _, bone in next, cbones do
|
||||||
|
_GetChildBonesRecursive(ent, bone, t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetChildBonesRecursive(ent, bone)
|
||||||
|
local mdl = ent:GetModel()
|
||||||
|
local mdlbones = cache[mdl]
|
||||||
|
|
||||||
|
if not mdlbones then
|
||||||
|
mdlbones = {}
|
||||||
|
cache[mdl] = mdlbones
|
||||||
|
end
|
||||||
|
|
||||||
|
local ret = mdlbones[bone]
|
||||||
|
if ret then return ret end
|
||||||
|
ret = _GetChildBonesRecursive(ent, bone)
|
||||||
|
mdlbones[bone] = ret
|
||||||
|
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
local bones = {}
|
||||||
|
local bonesName = {}
|
||||||
|
local forwardDistance = 16
|
||||||
|
local queue = {}
|
||||||
|
local work = false
|
||||||
|
local lowerbody = false
|
||||||
|
|
||||||
|
SuR.EnableFPBody = true
|
||||||
|
|
||||||
|
local MarkToRemove = function(ent)
|
||||||
|
if not IsValid(ent) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
work = true
|
||||||
|
ent:SetNoDraw(true)
|
||||||
|
table.insert(queue, ent)
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("Think", "legs.MarkToRemove", function()
|
||||||
|
if not work then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for key, ent in pairs(queue) do
|
||||||
|
if ent:IsValid() then
|
||||||
|
ent:Remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
queue[key] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if not next(queue) then
|
||||||
|
work = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("LocalPlayer_Validated", "sur_gmod_legs", function(ply)
|
||||||
|
hook.Remove("LocalPlayer_Validated", "sur_gmod_legs")
|
||||||
|
|
||||||
|
local pairs, ipairs = pairs, ipairs
|
||||||
|
local playermodelbones = {"ValveBiped.Bip01_Head1","ValveBiped.Bip01_R_Trapezius","ValveBiped.Bip01_R_Bicep","ValveBiped.Bip01_R_Shoulder", "ValveBiped.Bip01_R_Elbow","ValveBiped.Bip01_R_Wrist","ValveBiped.Bip01_R_Ulna","ValveBiped.Bip01_L_Trapezius","ValveBiped.Bip01_L_Bicep","ValveBiped.Bip01_L_Shoulder", "ValveBiped.Bip01_L_Elbow","ValveBiped.Bip01_L_Wrist","ValveBiped.Bip01_L_Ulna", "ValveBiped.Bip01_Neck1","ValveBiped.Bip01_Hair1","ValveBiped.Bip01_Hair2","ValveBiped.Bip01_L_Clavicle","ValveBiped.Bip01_R_Clavicle","ValveBiped.Bip01_R_UpperArm", "ValveBiped.Bip01_R_Forearm", "ValveBiped.Bip01_R_Hand", "ValveBiped.Bip01_L_UpperArm", "ValveBiped.Bip01_L_Forearm", "ValveBiped.Bip01_L_Hand", "ValveBiped.Bip01_L_Wrist", "ValveBiped.Bip01_R_Wrist", "ValveBiped.Bip01_L_Finger4", "ValveBiped.Bip01_L_Finger41", "ValveBiped.Bip01_L_Finger42", "ValveBiped.Bip01_L_Finger3", "ValveBiped.Bip01_L_Finger31", "ValveBiped.Bip01_L_Finger32", "ValveBiped.Bip01_L_Finger2", "ValveBiped.Bip01_L_Finger21", "ValveBiped.Bip01_L_Finger22", "ValveBiped.Bip01_L_Finger1", "ValveBiped.Bip01_L_Finger11", "ValveBiped.Bip01_L_Finger12", "ValveBiped.Bip01_L_Finger0", "ValveBiped.Bip01_L_Finger01", "ValveBiped.Bip01_L_Finger02", "ValveBiped.Bip01_R_Finger4", "ValveBiped.Bip01_R_Finger41", "ValveBiped.Bip01_R_Finger42", "ValveBiped.Bip01_R_Finger3", "ValveBiped.Bip01_R_Finger31", "ValveBiped.Bip01_R_Finger32", "ValveBiped.Bip01_R_Finger2", "ValveBiped.Bip01_R_Finger21", "ValveBiped.Bip01_R_Finger22", "ValveBiped.Bip01_R_Finger1", "ValveBiped.Bip01_R_Finger11", "ValveBiped.Bip01_R_Finger12", "ValveBiped.Bip01_R_Finger0", "ValveBiped.Bip01_R_Finger01", "ValveBiped.Bip01_R_Finger02"}
|
||||||
|
local a = {}
|
||||||
|
|
||||||
|
for key, v in pairs(playermodelbones) do
|
||||||
|
a[v] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local ply = ply or LocalPlayer()
|
||||||
|
local vec9999 = Vector(9999, 9999, 9999)
|
||||||
|
|
||||||
|
local ENTITY, PLAYER = FindMetaTable("Entity"), FindMetaTable("Player")
|
||||||
|
|
||||||
|
local GetBoneName = ENTITY.GetBoneName
|
||||||
|
local LookupBone = ENTITY.LookupBone
|
||||||
|
|
||||||
|
local MATRIX = FindMetaTable("VMatrix")
|
||||||
|
local Scale, Translate, SetTranslation, SetAngles = MATRIX.Scale, MATRIX.Translate, MATRIX.SetTranslation, MATRIX.SetAngles
|
||||||
|
local GetTranslation, GetAngles = MATRIX.GetTranslation, MATRIX.GetAngles
|
||||||
|
local SetBoneMatrix = ENTITY.SetBoneMatrix
|
||||||
|
local cam_Start3D, render_EnableClipping, render_PushCustomClipPlane, render_PopCustomClipPlane, render_EnableClipping, cam_End3D =
|
||||||
|
cam.Start3D, render.EnableClipping, render.PushCustomClipPlane, render.PopCustomClipPlane, render.EnableClipping, cam.End3D
|
||||||
|
local SetupBones = ENTITY.SetupBones
|
||||||
|
local _EyePos = ENTITY.EyePos
|
||||||
|
|
||||||
|
MarkToRemove(ply.Body)
|
||||||
|
MarkToRemove(ply.Body_NoDraw)
|
||||||
|
|
||||||
|
local remap = math.Remap
|
||||||
|
local eyeAngles = Angle()
|
||||||
|
local suppress = false
|
||||||
|
|
||||||
|
local isDucking = false
|
||||||
|
local finalPos = Vector()
|
||||||
|
local limit_check = 0
|
||||||
|
local timeCache = 0.1
|
||||||
|
local vector_origin = Vector(0, 0, 0)
|
||||||
|
|
||||||
|
local find, insert = string.find, table.insert
|
||||||
|
|
||||||
|
local SetPoseParameter, GetPoseParameter = ENTITY.SetPoseParameter, ENTITY.GetPoseParameter
|
||||||
|
local SetPlaybackRate, GetPlaybackRate = ENTITY.SetPlaybackRate, ENTITY.GetPlaybackRate
|
||||||
|
local GetBoneMatrix = ENTITY.GetBoneMatrix
|
||||||
|
|
||||||
|
local a1, b1, c1 = 0, 0, 0
|
||||||
|
local headPos = Vector(0,10000,0)
|
||||||
|
local limitJump = 0
|
||||||
|
|
||||||
|
local onGround = true
|
||||||
|
local JUMPING_ = false
|
||||||
|
|
||||||
|
hook.Add("SetupMove", "legs.SetupMove", function(ply, move)
|
||||||
|
if not IsFirstTimePredicted() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if bit.band(move:GetButtons(), IN_JUMP) ~= 0
|
||||||
|
and bit.band(move:GetOldButtons(), IN_JUMP) == 0
|
||||||
|
and ply:OnGround() then
|
||||||
|
JUMPING, onGround = true, false
|
||||||
|
|
||||||
|
if IsFirstTimePredicted() then
|
||||||
|
JUMPING_ = not JUMPING_
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("FinishMove", "legs.FinishMove", function(ply, move)
|
||||||
|
if not IsFirstTimePredicted() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
JUMPING = nil
|
||||||
|
|
||||||
|
local isOnGround = ply:OnGround()
|
||||||
|
|
||||||
|
if onGround ~= isOnGround then
|
||||||
|
onGround = isOnGround
|
||||||
|
|
||||||
|
if onGround then
|
||||||
|
limitJump = CurTime() + FrameTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local validBones = {}
|
||||||
|
|
||||||
|
local removeHead = function()
|
||||||
|
local legs = ply.Body
|
||||||
|
local h = LookupBone(legs, "ValveBiped.Bip01_Head1")
|
||||||
|
|
||||||
|
if h then
|
||||||
|
legs:ManipulateBonePosition(h, headPos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local GetPos, GetViewOffset = ENTITY.GetPos, PLAYER.GetViewOffset
|
||||||
|
|
||||||
|
local removeGarbage = function(bonesSuccess, boneCount)
|
||||||
|
local ent = ply.Body
|
||||||
|
local goofyUhhPosition = GetPos(ply) + GetViewOffset(ply) - eyeAngles:Forward() * 32
|
||||||
|
|
||||||
|
for i = 0, boneCount - 1 do
|
||||||
|
local boneName = GetBoneName(ent, i)
|
||||||
|
local mat = GetBoneMatrix(ent, i)
|
||||||
|
|
||||||
|
if mat then
|
||||||
|
if a[boneName] then
|
||||||
|
SetTranslation(mat, goofyUhhPosition)
|
||||||
|
|
||||||
|
bonesSuccess[i] = true
|
||||||
|
|
||||||
|
local recursive = GetChildBonesRecursive(ent, i)
|
||||||
|
|
||||||
|
for key = 1, #recursive do
|
||||||
|
local bone = recursive[key]
|
||||||
|
|
||||||
|
if not bonesSuccess[bone] then
|
||||||
|
bonesSuccess[bone] = true
|
||||||
|
|
||||||
|
local mat = GetBoneMatrix(ent, bone)
|
||||||
|
|
||||||
|
if mat then
|
||||||
|
SetTranslation(mat, goofyUhhPosition)
|
||||||
|
|
||||||
|
SetBoneMatrix(ent, bone, mat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif not bonesSuccess[i] then
|
||||||
|
local bone = LookupBone(ply, boneName)
|
||||||
|
|
||||||
|
if bone then
|
||||||
|
local mat2 = GetBoneMatrix(ply, bone)
|
||||||
|
|
||||||
|
if mat2 then
|
||||||
|
SetTranslation(mat, GetTranslation(mat2))
|
||||||
|
SetAngles(mat, GetAngles(mat2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SetBoneMatrix(ent, i, mat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local Legs_NoDraw_Angle = Angle(0, 0, 0)
|
||||||
|
local potentionalBones, timeCacheBones = {}, 0
|
||||||
|
|
||||||
|
local spineBones = {
|
||||||
|
["ValveBiped.Bip01_Spine2"] = true,
|
||||||
|
["ValveBiped.Bip01_Spine4"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
local GetNumPoseParameters, GetPoseParameterRange = ENTITY.GetNumPoseParameters, ENTITY.GetPoseParameterRange
|
||||||
|
local GetPoseParameterName, GetSequence = ENTITY.GetPoseParameterName, ENTITY.GetSequence
|
||||||
|
local GetRenderAngles, SetRenderAngles = PLAYER.GetRenderAngles, PLAYER.SetRenderAngles
|
||||||
|
|
||||||
|
local buildBonePosition = function()
|
||||||
|
ply.Body.Callback = ply.Body:AddCallback("BuildBonePositions", function(ent, boneCount)
|
||||||
|
if not SuR.EnableFPBody then
|
||||||
|
return ent:RemoveCallback("BuildBonePositions", ent.Callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not ply.TimeToDuck
|
||||||
|
or suppress then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ang = GetRenderAngles(ply)
|
||||||
|
SetRenderAngles(ply, eyeAngles)
|
||||||
|
|
||||||
|
a1, b1, c1 = GetPoseParameter(ply, "body_yaw", 0), GetPoseParameter(ply, "aim_yaw", 0), GetPoseParameter(ply, "aim_pitch", 0)
|
||||||
|
|
||||||
|
SetPoseParameter(ply, "body_yaw", 0)
|
||||||
|
SetPoseParameter(ply, "aim_yaw", 0)
|
||||||
|
SetPoseParameter(ply, "aim_pitch", 0)
|
||||||
|
|
||||||
|
SetupBones(ply)
|
||||||
|
|
||||||
|
local seq = GetSequence(ply)
|
||||||
|
|
||||||
|
if ent.Seq ~= seq then
|
||||||
|
ent.Seq = seq
|
||||||
|
|
||||||
|
ent:ResetSequence(seq)
|
||||||
|
end
|
||||||
|
|
||||||
|
local legsNoDraw = ply.Body_NoDraw
|
||||||
|
|
||||||
|
for i = 0, GetNumPoseParameters(ply) - 1 do
|
||||||
|
local flMin, flMax = GetPoseParameterRange(ply, i)
|
||||||
|
local sPose = GetPoseParameterName(ply, i)
|
||||||
|
local remap = remap(GetPoseParameter(ply, sPose), 0, 1, flMin, flMax)
|
||||||
|
SetPoseParameter(legsNoDraw, sPose, remap)
|
||||||
|
SetPoseParameter(ent, sPose, remap)
|
||||||
|
end
|
||||||
|
|
||||||
|
local bonesSuccess = {}
|
||||||
|
removeGarbage(bonesSuccess, boneCount)
|
||||||
|
|
||||||
|
SetPoseParameter(ply, "body_yaw", a1)
|
||||||
|
SetPoseParameter(ply, "aim_yaw", b1)
|
||||||
|
SetPoseParameter(ply, "aim_pitch", c1)
|
||||||
|
|
||||||
|
removeHead()
|
||||||
|
|
||||||
|
SetupBones(legsNoDraw)
|
||||||
|
|
||||||
|
local this = (2 - (0.8 * ply.TimeToDuck))
|
||||||
|
local cacheThis = this
|
||||||
|
local CT = CurTime()
|
||||||
|
|
||||||
|
if timeCacheBones < CT then
|
||||||
|
timeCacheBones, potentionalBones = CT + timeCache, {}
|
||||||
|
|
||||||
|
for i = 1, #validBones do
|
||||||
|
local array = validBones[i]
|
||||||
|
local bone, isPelvis = array[2], array[1]
|
||||||
|
|
||||||
|
if bonesSuccess[bone] then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
local recursive = GetChildBonesRecursive(ent, bone)
|
||||||
|
|
||||||
|
for key = 1, #recursive do
|
||||||
|
local i = recursive[key]
|
||||||
|
|
||||||
|
if not bonesSuccess[i]
|
||||||
|
and (isPelvis and i == bone or not isPelvis) then
|
||||||
|
bonesSuccess[i] = true
|
||||||
|
|
||||||
|
local boneName = GetBoneName(ent, i)
|
||||||
|
local mat = GetBoneMatrix(ent, i)
|
||||||
|
|
||||||
|
if mat then
|
||||||
|
local b = LookupBone(legsNoDraw, boneName)
|
||||||
|
|
||||||
|
if b then
|
||||||
|
local mat2 = GetBoneMatrix(legsNoDraw, b)
|
||||||
|
|
||||||
|
if mat2 then
|
||||||
|
local matTR, mat2TR = GetTranslation(mat), GetTranslation(mat2)
|
||||||
|
|
||||||
|
if boneName == "ValveBiped.Bip01_Pelvis" then
|
||||||
|
Legs_NoDraw_Angle.y = (math.NormalizeAngle(ply:EyeAngles().y - GetAngles(mat).y) + 90) / 1.25
|
||||||
|
elseif spineBones[boneName] then
|
||||||
|
this = 20 - (16 * ply.TimeToDuck)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not lowerbody then
|
||||||
|
SetTranslation(mat, mat2TR - (mat2TR - matTR) / this)
|
||||||
|
this = cacheThis
|
||||||
|
SetAngles(mat, GetAngles(mat2))
|
||||||
|
SetBoneMatrix(ent, i, mat)
|
||||||
|
end
|
||||||
|
|
||||||
|
potentionalBones[#potentionalBones + 1] = {
|
||||||
|
[1] = i,
|
||||||
|
[2] = boneName
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for key = 1, #potentionalBones do
|
||||||
|
local array = potentionalBones[key]
|
||||||
|
local i, boneName = array[1], array[2]
|
||||||
|
local mat = GetBoneMatrix(ent, i)
|
||||||
|
|
||||||
|
if mat then
|
||||||
|
local b = LookupBone(legsNoDraw, boneName)
|
||||||
|
|
||||||
|
if b then
|
||||||
|
local mat2 = GetBoneMatrix(legsNoDraw, b)
|
||||||
|
|
||||||
|
if mat2 then
|
||||||
|
if boneName == "ValveBiped.Bip01_Pelvis" then
|
||||||
|
Legs_NoDraw_Angle.y = (math.NormalizeAngle(ply:EyeAngles().y - GetAngles(mat).y) + 90) / 1.25
|
||||||
|
elseif spineBones[boneName] then
|
||||||
|
this = 20 - (16 * ply.TimeToDuck)
|
||||||
|
end
|
||||||
|
|
||||||
|
local matTR, mat2TR = GetTranslation(mat), GetTranslation(mat2)
|
||||||
|
|
||||||
|
if not lowerbody then
|
||||||
|
SetTranslation(mat, mat2TR - (mat2TR - matTR) / this)
|
||||||
|
this = cacheThis
|
||||||
|
SetAngles(mat, GetAngles(mat2))
|
||||||
|
SetBoneMatrix(ent, i, mat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SetRenderAngles(ply, ang)
|
||||||
|
end)
|
||||||
|
|
||||||
|
ply.Body.FullyLoaded = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local faggot = Vector()
|
||||||
|
local SetParent, SetPos, SetAngles, SetCycle = ENTITY.SetParent, ENTITY.SetPos, ENTITY.SetAngles, ENTITY.SetCycle
|
||||||
|
local GetCycle = ENTITY.GetCycle
|
||||||
|
local lowerbodyseq = {
|
||||||
|
["sur_dropkick"] = {0.2, 1},
|
||||||
|
["sur_fall_idle"] = {0, 1},
|
||||||
|
["sur_fall_down"] = {0.2, 1},
|
||||||
|
["sur_fall_standup"] = {0, 0.4},
|
||||||
|
}
|
||||||
|
|
||||||
|
hook.Add("RenderScene", "firstperson.RenderScene", function(vec, ee)
|
||||||
|
if not SuR.EnableFPBody then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local anim = ply:GetSVAnim()
|
||||||
|
local tab = lowerbodyseq[anim]
|
||||||
|
if istable(tab) then
|
||||||
|
local cycle = math.Clamp((CurTime()-ply:GetNWFloat('SVAnimStartTime'))/ply:GetNWFloat('SVAnimDelay'), 0, 1)
|
||||||
|
if cycle >= tab[1] and cycle <= tab[2] then
|
||||||
|
lowerbody = true
|
||||||
|
else
|
||||||
|
lowerbody = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lowerbody = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if lowerbody then
|
||||||
|
forwardDistance = Lerp(FrameTime()/0.1, forwardDistance, 0)
|
||||||
|
else
|
||||||
|
forwardDistance = Lerp(FrameTime()/0.1, forwardDistance, 16)
|
||||||
|
end
|
||||||
|
|
||||||
|
eyePos = vec
|
||||||
|
eyeAngles = ply:EyeAngles()
|
||||||
|
eyeAngles.p = 0
|
||||||
|
|
||||||
|
local onGround = ply:OnGround()
|
||||||
|
isDucking = bit.band(ply:GetFlags(), FL_ANIMDUCKING) > 0
|
||||||
|
and onGround
|
||||||
|
|
||||||
|
local FT = FrameTime()
|
||||||
|
|
||||||
|
ply.TimeToDuck = math.Clamp((ply.TimeToDuck or 0) + FT * 3.5 * (isDucking and 1 or -1), 0, 1)
|
||||||
|
|
||||||
|
local realEyeAngles = EyeAngles()
|
||||||
|
local legs = ply.Body
|
||||||
|
|
||||||
|
suppress = ply:ShouldDrawLocalPlayer()
|
||||||
|
or not ply:Alive()
|
||||||
|
or not IsValid(ply.Body)
|
||||||
|
or not ply.Body.FullyLoaded
|
||||||
|
or not IsValid(ply.Body_NoDraw)
|
||||||
|
or ply:GetRagdollEntity():IsValid()
|
||||||
|
or ply:InVehicle()
|
||||||
|
or ply:GetObserverMode() ~= 0
|
||||||
|
or realEyeAngles.p > 110
|
||||||
|
or realEyeAngles.p < -110
|
||||||
|
or ply:GetNWBool('SVAnimStopCutscene')
|
||||||
|
|
||||||
|
local CT = SysTime()
|
||||||
|
|
||||||
|
if limit_check < CT and IsValid(ply.Body) then
|
||||||
|
limit_check = CT + timeCache
|
||||||
|
|
||||||
|
if ply.Body.Callback then
|
||||||
|
local getCallbacks = ply.Body:GetCallbacks("BuildBonePositions")
|
||||||
|
|
||||||
|
if not getCallbacks[ply.Body.Callback] then
|
||||||
|
buildBonePosition()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
buildBonePosition()
|
||||||
|
end
|
||||||
|
|
||||||
|
ply.Body:SetSkin(ply:GetSkin())
|
||||||
|
ply.Body:SetMaterial(ply:GetMaterial())
|
||||||
|
|
||||||
|
if not suppress then
|
||||||
|
for k, v in ipairs(ply:GetBodyGroups()) do
|
||||||
|
local bg = ply:GetBodygroup(v.id)
|
||||||
|
|
||||||
|
ply.Body:SetBodygroup(v.id, bg)
|
||||||
|
ply.Body_NoDraw:SetBodygroup(v.id, bg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
validBones = {}
|
||||||
|
|
||||||
|
for i = 0, ply.Body:GetBoneCount() - 1 do
|
||||||
|
local boneName = GetBoneName(ply.Body, i)
|
||||||
|
local isPelvis = find(boneName, "Pelvis", 1, true) or false
|
||||||
|
|
||||||
|
if find(boneName, "Spine", 1, true)
|
||||||
|
or isPelvis
|
||||||
|
or find(boneName, "Jacket", 1, true) then
|
||||||
|
validBones[#validBones + 1] = {
|
||||||
|
[1] = isPelvis,
|
||||||
|
[2] = i
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if suppress then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local getPos = GetPos(ply)
|
||||||
|
local getView = GetViewOffset(ply)
|
||||||
|
local cycle = GetCycle(ply)
|
||||||
|
|
||||||
|
SetParent(ply.Body, ply)
|
||||||
|
SetPos(ply.Body, getPos)
|
||||||
|
SetAngles(ply.Body, eyeAngles)
|
||||||
|
SetPlaybackRate(ply.Body, GetPlaybackRate(ply))
|
||||||
|
SetCycle(ply.Body, cycle)
|
||||||
|
|
||||||
|
local currentView = ply:GetCurrentViewOffset()
|
||||||
|
local forward = eyeAngles:Forward() * forwardDistance
|
||||||
|
|
||||||
|
ply.TimeToFaggot = math.Clamp((ply.TimeToFaggot or 0) + FT * (ply:Crouching() and 4 or 10000) * (not onGround and 1 or -1), 0, 1)
|
||||||
|
|
||||||
|
SetParent(ply.Body_NoDraw, ply)
|
||||||
|
SetPos(ply.Body_NoDraw, getPos)
|
||||||
|
SetAngles(ply.Body_NoDraw, eyeAngles - Legs_NoDraw_Angle)
|
||||||
|
|
||||||
|
faggot = (not onGround or limitJump > CurTime()) and getView - currentView or vector_origin
|
||||||
|
|
||||||
|
finalPos = getPos
|
||||||
|
+ currentView
|
||||||
|
+ forward
|
||||||
|
+ (faggot * ply.TimeToFaggot)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local vector_down = Vector(0, 0, -1)
|
||||||
|
local vec1 = Vector(0, 0, 1)
|
||||||
|
local erroredModels = {}
|
||||||
|
|
||||||
|
hook.Add("PreDrawViewModels", "firstperson.PreDrawViewModel", function(depth, skybox, isDraw3DSkybox)
|
||||||
|
if not SuR.EnableFPBody then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local current = ply.wardrobe or ply:GetModel()
|
||||||
|
|
||||||
|
if not erroredModels[current]
|
||||||
|
and (not IsValid(ply.Body)
|
||||||
|
or ply.Body:GetModel() ~= current) then
|
||||||
|
MarkToRemove(ply.Body)
|
||||||
|
MarkToRemove(ply.Body_NoDraw)
|
||||||
|
|
||||||
|
ply.Body = ClientsideModel(current)
|
||||||
|
ply.Body:SetNoDraw(true)
|
||||||
|
ply.Body:SetIK(false)
|
||||||
|
SetupBones(ply.Body)
|
||||||
|
ply.Body.GetPlayerColor = function()
|
||||||
|
return ply:GetPlayerColor()
|
||||||
|
end
|
||||||
|
|
||||||
|
local seq = ply.Body:LookupSequence("idle_all_01")
|
||||||
|
|
||||||
|
if seq < 0 then
|
||||||
|
MarkToRemove(ply.Body)
|
||||||
|
|
||||||
|
erroredModels[current] = true
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
ply.Body_NoDraw = ClientsideModel(current)
|
||||||
|
ply.Body_NoDraw:SetNoDraw(true)
|
||||||
|
ply.Body_NoDraw:SetIK(false)
|
||||||
|
ply.Body_NoDraw.GetPlayerColor = function()
|
||||||
|
return ply:GetPlayerColor()
|
||||||
|
end
|
||||||
|
|
||||||
|
ply.Body_NoDraw:SetSequence(seq)
|
||||||
|
|
||||||
|
ply.Body.FullyLoaded, timeCacheBones = false, 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if suppress then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local RT = render.GetRenderTarget()
|
||||||
|
|
||||||
|
if RT then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if hook.Run("ShouldDisableLegs", ply.Body) == true then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ret = hook.Run("PreDrawBody", ply.Body)
|
||||||
|
|
||||||
|
if ret == false then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local shootPos, getPos = _EyePos(ply), GetPos(ply)
|
||||||
|
shootPos.z = 0
|
||||||
|
getPos.z = 0
|
||||||
|
|
||||||
|
local color = ply:GetColor()
|
||||||
|
local m1, m2, m3 = render.GetColorModulation()
|
||||||
|
|
||||||
|
cam_Start3D(finalPos + (shootPos - getPos), nil, nil, 0, 0, nil, nil, 0.5, -1)
|
||||||
|
local bEnabled = render_EnableClipping(true)
|
||||||
|
render_PushCustomClipPlane(vector_down, vector_down:Dot(finalPos + vec1))
|
||||||
|
render.SetColorModulation(color.r / 255, color.g / 255, color.b / 255)
|
||||||
|
ply.Body:DrawModel()
|
||||||
|
render.SetColorModulation(m1, m2, m3)
|
||||||
|
render_PopCustomClipPlane()
|
||||||
|
render_EnableClipping(bEnabled)
|
||||||
|
cam_End3D()
|
||||||
|
|
||||||
|
hook.Run("PostDrawBody", ply.Body)
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("PreDrawBody", "sur_body.PreDrawBody_Compat", function()
|
||||||
|
if VWallrunning
|
||||||
|
or inmantle then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("Think", "sur_legs.Load", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
|
||||||
|
if IsValid(ply) then
|
||||||
|
hook.Remove("Think", "sur_legs.Load")
|
||||||
|
|
||||||
|
hook.Run("LocalPlayer_Validated", ply)
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
--By Shadow Bonnie from GitHub
|
||||||
|
|
||||||
|
OUTLINE_MODE_BOTH = 0 -- Render always
|
||||||
|
OUTLINE_MODE_NOTVISIBLE = 1
|
||||||
|
OUTLINE_MODE_VISIBLE = 2
|
||||||
|
|
||||||
|
OUTLINE_RENDERTYPE_BEFORE_VM = 0 -- Render before drawing the view model
|
||||||
|
OUTLINE_RENDERTYPE_BEFORE_EF = 1 -- Render before drawing all effects (after drawing the viewmodel)
|
||||||
|
OUTLINE_RENDERTYPE_AFTER_EF = 2 -- Render after drawing all effects
|
||||||
|
|
||||||
|
local istable = istable
|
||||||
|
local render = render
|
||||||
|
local Material = Material
|
||||||
|
local CreateMaterial = CreateMaterial
|
||||||
|
local hook = hook
|
||||||
|
local cam = cam
|
||||||
|
local ScrW = ScrW
|
||||||
|
local ScrH = ScrH
|
||||||
|
local IsValid = IsValid
|
||||||
|
local surface = surface
|
||||||
|
|
||||||
|
module( "outline", package.seeall )
|
||||||
|
|
||||||
|
local List, ListSize = {}, 0
|
||||||
|
local RenderEnt = NULL
|
||||||
|
local RenderType = OUTLINE_RENDERTYPE_AFTER_EF
|
||||||
|
local OutlineThickness = 1
|
||||||
|
|
||||||
|
local StoreTexture = render.GetScreenEffectTexture( 0 )
|
||||||
|
local DrawTexture = render.GetScreenEffectTexture( 1 )
|
||||||
|
|
||||||
|
local OutlineMatSettings = {
|
||||||
|
[ "$basetexture" ] = DrawTexture:GetName(),
|
||||||
|
[ "$ignorez" ] = 1,
|
||||||
|
[ "$alphatest" ] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local CopyMat = Material( "pp/copy" )
|
||||||
|
local OutlineMat = CreateMaterial( "outline", "UnlitGeneric", OutlineMatSettings )
|
||||||
|
|
||||||
|
local ENTS, COLOR, MODE = 1, 2, 3
|
||||||
|
|
||||||
|
function Add( ents, color, mode )
|
||||||
|
|
||||||
|
if ( ListSize >= 255 ) then return end --Maximum 255 reference values
|
||||||
|
if ( !istable( ents ) ) then ents = { ents } end --Support for passing Entity as first argument
|
||||||
|
if ( ents[ 1 ] == nil ) then return end --Do not pass empty tables
|
||||||
|
|
||||||
|
if (
|
||||||
|
mode != OUTLINE_MODE_BOTH &&
|
||||||
|
mode != OUTLINE_MODE_NOTVISIBLE &&
|
||||||
|
mode != OUTLINE_MODE_VISIBLE
|
||||||
|
) then
|
||||||
|
mode = OUTLINE_MODE_BOTH
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = {
|
||||||
|
[ ENTS ] = ents,
|
||||||
|
[ COLOR ] = color,
|
||||||
|
[ MODE ] = mode
|
||||||
|
}
|
||||||
|
|
||||||
|
ListSize = ListSize + 1
|
||||||
|
List[ ListSize ] = data
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function RenderedEntity()
|
||||||
|
|
||||||
|
return RenderEnt
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SetRenderType( render_type )
|
||||||
|
|
||||||
|
if (
|
||||||
|
render_type != OUTLINE_RENDERTYPE_BEFORE_VM &&
|
||||||
|
render_type != OUTLINE_RENDERTYPE_BEFORE_EF &&
|
||||||
|
render_type != OUTLINE_RENDERTYPE_AFTER_EF
|
||||||
|
) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_type = RenderType
|
||||||
|
RenderType = render_type
|
||||||
|
|
||||||
|
return old_type
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetRenderType()
|
||||||
|
|
||||||
|
return RenderType
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SetDoubleThickness( thickness )
|
||||||
|
|
||||||
|
local old_thickness = OutlineThickness == 2
|
||||||
|
OutlineThickness = thickness && 2 || 1
|
||||||
|
|
||||||
|
return old_thickness
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function IsDoubleThickness()
|
||||||
|
|
||||||
|
return OutlineThickness == 2
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Render()
|
||||||
|
|
||||||
|
local scene = render.GetRenderTarget()
|
||||||
|
render.CopyRenderTargetToTexture( StoreTexture )
|
||||||
|
|
||||||
|
local w, h = ScrW(), ScrH()
|
||||||
|
|
||||||
|
render.ClearStencil()
|
||||||
|
|
||||||
|
render.SetStencilEnable( true )
|
||||||
|
render.SuppressEngineLighting( true )
|
||||||
|
|
||||||
|
render.SetStencilWriteMask( 0xFF )
|
||||||
|
render.SetStencilTestMask( 0xFF )
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCIL_GREATER )
|
||||||
|
render.SetStencilFailOperation( STENCIL_KEEP )
|
||||||
|
|
||||||
|
cam.Start3D()
|
||||||
|
render.SetBlend(1)
|
||||||
|
|
||||||
|
for i = 1, ListSize do
|
||||||
|
|
||||||
|
local reference = 0xFF - ( i - 1 )
|
||||||
|
|
||||||
|
local data = List[ i ]
|
||||||
|
local mode = data[ MODE ]
|
||||||
|
local ents = data[ ENTS ]
|
||||||
|
|
||||||
|
render.SetStencilReferenceValue( reference )
|
||||||
|
|
||||||
|
if ( mode == OUTLINE_MODE_BOTH || mode == OUTLINE_MODE_VISIBLE ) then
|
||||||
|
|
||||||
|
render.SetStencilZFailOperation( mode == OUTLINE_MODE_BOTH && STENCIL_REPLACE || STENCIL_KEEP )
|
||||||
|
render.SetStencilPassOperation( STENCIL_REPLACE )
|
||||||
|
|
||||||
|
for j = 1, #ents do
|
||||||
|
|
||||||
|
local ent = ents[ j ]
|
||||||
|
|
||||||
|
if ( IsValid( ent ) ) then
|
||||||
|
|
||||||
|
RenderEnt = ent
|
||||||
|
ent:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif ( mode == OUTLINE_MODE_NOTVISIBLE ) then
|
||||||
|
|
||||||
|
render.SetStencilZFailOperation( STENCIL_REPLACE )
|
||||||
|
render.SetStencilPassOperation( STENCIL_KEEP )
|
||||||
|
|
||||||
|
for j = 1, #ents do
|
||||||
|
|
||||||
|
local ent = ents[ j ]
|
||||||
|
|
||||||
|
if ( IsValid( ent ) ) then
|
||||||
|
|
||||||
|
RenderEnt = ent
|
||||||
|
ent:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||||
|
render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||||
|
render.SetStencilPassOperation( STENCIL_ZERO )
|
||||||
|
|
||||||
|
for j = 1, #ents do
|
||||||
|
|
||||||
|
local ent = ents[ j ]
|
||||||
|
|
||||||
|
if ( IsValid( ent ) ) then
|
||||||
|
|
||||||
|
RenderEnt = ent
|
||||||
|
ent:DrawModel()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCIL_GREATER )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
RenderEnt = NULL
|
||||||
|
|
||||||
|
render.SetBlend(1)
|
||||||
|
cam.End3D()
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||||
|
render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||||
|
render.SetStencilPassOperation( STENCIL_KEEP )
|
||||||
|
|
||||||
|
render.Clear( 0, 0, 0, 0, false, false )
|
||||||
|
|
||||||
|
cam.Start2D()
|
||||||
|
|
||||||
|
for i = 1, ListSize do
|
||||||
|
|
||||||
|
local reference = 0xFF - ( i - 1 )
|
||||||
|
|
||||||
|
render.SetStencilReferenceValue( reference )
|
||||||
|
|
||||||
|
surface.SetDrawColor( List[ i ][ COLOR ] )
|
||||||
|
surface.DrawRect( 0, 0, w, h )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
cam.End2D()
|
||||||
|
|
||||||
|
render.SuppressEngineLighting( false )
|
||||||
|
render.SetStencilEnable( false )
|
||||||
|
|
||||||
|
render.CopyRenderTargetToTexture( DrawTexture )
|
||||||
|
|
||||||
|
render.SetRenderTarget( scene )
|
||||||
|
CopyMat:SetTexture( "$basetexture", StoreTexture )
|
||||||
|
render.SetMaterial( CopyMat )
|
||||||
|
render.DrawScreenQuad()
|
||||||
|
|
||||||
|
render.SetStencilEnable( true )
|
||||||
|
|
||||||
|
render.SetStencilReferenceValue( 0 )
|
||||||
|
|
||||||
|
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||||
|
|
||||||
|
OutlineMat:SetTexture( "$basetexture", DrawTexture )
|
||||||
|
render.SetMaterial( OutlineMat )
|
||||||
|
|
||||||
|
render.DrawScreenQuadEx( -OutlineThickness, -OutlineThickness, w ,h )
|
||||||
|
render.DrawScreenQuadEx( -OutlineThickness, 0, w, h )
|
||||||
|
render.DrawScreenQuadEx( -OutlineThickness, OutlineThickness, w, h )
|
||||||
|
render.DrawScreenQuadEx( 0, -OutlineThickness, w, h )
|
||||||
|
render.DrawScreenQuadEx( 0, OutlineThickness, w, h )
|
||||||
|
render.DrawScreenQuadEx( OutlineThickness, -OutlineThickness, w, h )
|
||||||
|
render.DrawScreenQuadEx( OutlineThickness, 0, w, h )
|
||||||
|
render.DrawScreenQuadEx( OutlineThickness, OutlineThickness, w, h )
|
||||||
|
|
||||||
|
render.SetStencilEnable( false )
|
||||||
|
|
||||||
|
render.ClearDepth() -- Allows to render view model and other stuff in front of outline
|
||||||
|
end
|
||||||
|
|
||||||
|
local function RenderOutlines()
|
||||||
|
|
||||||
|
hook.Run( "SetupOutlines", Add )
|
||||||
|
|
||||||
|
if ( ListSize == 0 ) then return end
|
||||||
|
|
||||||
|
Render()
|
||||||
|
|
||||||
|
List, ListSize = {}, 0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add( "PreDrawViewModels", "RenderOutlines", function()
|
||||||
|
|
||||||
|
if ( RenderType == OUTLINE_RENDERTYPE_BEFORE_VM ) then
|
||||||
|
|
||||||
|
RenderOutlines()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end )
|
||||||
|
|
||||||
|
hook.Add( "PreDrawEffects", "RenderOutlines", function()
|
||||||
|
|
||||||
|
if ( RenderType == OUTLINE_RENDERTYPE_BEFORE_EF ) then
|
||||||
|
|
||||||
|
RenderOutlines()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end )
|
||||||
|
|
||||||
|
hook.Add( "PostDrawEffects", "RenderOutlines", function()
|
||||||
|
|
||||||
|
if ( RenderType == OUTLINE_RENDERTYPE_AFTER_EF ) then
|
||||||
|
|
||||||
|
RenderOutlines()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end )
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
hook.Add("SetupOutlines", "SuR_ScoutAbility", function()
|
||||||
|
local ply = LocalPlayer()
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
if ply:Alive() and ply:IsSurvivor() then
|
||||||
|
local tab1 = {}
|
||||||
|
local tab2 = {}
|
||||||
|
local tab3 = {}
|
||||||
|
local tab4 = {}
|
||||||
|
for _, ent in pairs(player.GetAll()) do
|
||||||
|
if ent:IsZombie() or !ent:Alive() or ply:IsLineOfSightClear(ent) then continue end
|
||||||
|
local alpha = 255/(ent:EyePos():Distance(EyePos())/500)
|
||||||
|
if string.match(ent:GetSVAnim(), "executions") or string.match(ent:GetSVAnim(), "killmove") or string.match(ent:GetSVAnim(), "grappleloop") then
|
||||||
|
tab4[#tab4+1] = ent
|
||||||
|
elseif ent:IsDowned() then
|
||||||
|
tab3[#tab3+1] = ent
|
||||||
|
elseif alpha > 200 then
|
||||||
|
tab1[#tab1+1] = ent
|
||||||
|
else
|
||||||
|
tab2[#tab2+1] = ent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
outline.Add(tab1, Color(200,200,200), 1)
|
||||||
|
outline.Add(tab2, Color(120,120,120,180), 1)
|
||||||
|
outline.Add(tab3, Color(200,20,20), 1)
|
||||||
|
outline.Add(tab4, Color(200,120,20), 1)
|
||||||
|
|
||||||
|
local tr = ply:GetEyeTrace().Entity
|
||||||
|
if !ply:IsLockedAbilities() and IsValid(tr) and string.match(tr:GetClass(), "vj") and tr:GetPos():DistToSqr(ply:GetPos()) < 10000 and tr:GetNWBool('flinching', false) and tr:Health() <= 200 then
|
||||||
|
outline.Add({tr}, Color(180,0,0), 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
if not SuR.Config.Objective_Mode and ply:GetPlayerClass() == "scout" and ply:GetLevelState() >= 1 and ply:Alive() then
|
||||||
|
local tab = {}
|
||||||
|
for _, ent in pairs(ents.FindInSphere(ply:GetPos(), 400)) do
|
||||||
|
if ent:GetClass() == "sur_loot" or ent:GetClass() == "sur_resupply" then
|
||||||
|
tab[#tab+1] = ent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
outline.Add(tab, Color(150,200,150), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
if SuR.Config.Objective_Mode and ply:Alive() then
|
||||||
|
local wep = ply:GetWeapon("sur_fuel")
|
||||||
|
if IsValid(wep) then
|
||||||
|
local tab = {}
|
||||||
|
local ftab = ents.FindByClass("sur_generator")
|
||||||
|
for i = 1, #ftab do
|
||||||
|
local v = ftab[i]
|
||||||
|
if !v:GetNWBool('HaveFuel', false) then
|
||||||
|
tab[#tab+1] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
outline.Add(tab, Color(220,200,0), 1)
|
||||||
|
else
|
||||||
|
local tab = {}
|
||||||
|
local ftab = ents.FindByClass("sur_loot")
|
||||||
|
for i = 1, #ftab do
|
||||||
|
local v = ftab[i]
|
||||||
|
if v:GetModel() == "models/surrounded/obj/w_jerrycanblue.mdl" then
|
||||||
|
tab[#tab+1] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
outline.Add(tab, Color(240,160,0), 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
AddCSLuaFile("shared.lua")
|
||||||
|
AddCSLuaFile("client/cl_hud.lua")
|
||||||
|
AddCSLuaFile("client/cl_menu.lua")
|
||||||
|
AddCSLuaFile("client/cl_abilities.lua")
|
||||||
|
AddCSLuaFile("client/cl_cutscenes.lua")
|
||||||
|
AddCSLuaFile("client/cl_outline.lua")
|
||||||
|
AddCSLuaFile("client/cl_other.lua")
|
||||||
|
AddCSLuaFile("client/cl_buymenu.lua")
|
||||||
|
|
||||||
|
include("shared.lua")
|
||||||
|
include("server/sv_nets.lua")
|
||||||
|
include("server/sv_abilities.lua")
|
||||||
|
include("server/sv_functions.lua")
|
||||||
|
include("server/sv_revive.lua")
|
||||||
|
include("server/sv_nodegraph.lua")
|
||||||
|
include("server/sv_waves.lua")
|
||||||
|
include("server/sv_lnr.lua")
|
||||||
|
include("server/sv_executions.lua")
|
||||||
|
include("server/sv_exfil.lua")
|
||||||
|
include("server/sv_qte.lua")
|
||||||
|
include("server/sv_classes.lua")
|
||||||
|
include("server/sv_other.lua")
|
||||||
|
include("server/sv_buymenu.lua")
|
||||||
|
|
||||||
|
local url = SuR.Config.LoadingURL
|
||||||
|
if isstring(url) and url != "" then
|
||||||
|
RunConsoleCommand("sv_loadingurl", url)
|
||||||
|
end
|
||||||
|
hook.Add("ShutDown", "SuR.ShutDown", function()
|
||||||
|
RunConsoleCommand("sv_loadingurl", "")
|
||||||
|
end)
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
SuR.Language = {
|
||||||
|
["settings_main"] = "Client Settings",
|
||||||
|
["settings_vm"] = "View mode",
|
||||||
|
["settings_vmc"] = "3rd person cutscenes?",
|
||||||
|
["settings_vmd"] = "3rd person death animations?",
|
||||||
|
["settings_mv"] = "Music Volume",
|
||||||
|
["settings_rus"] = "Enable russian voicelines",
|
||||||
|
["settings_zc"] = "Disable interface",
|
||||||
|
["settings_dh"] = "Disable tips",
|
||||||
|
|
||||||
|
["mode"] = "Mode: ",
|
||||||
|
["mode_survival"] = "Survival",
|
||||||
|
["mode_versus"] = "Versus",
|
||||||
|
["mode_objective"] = "Objective",
|
||||||
|
|
||||||
|
["pmsettings_main"] = "Character Model",
|
||||||
|
["pmsettings_wep"] = "Character Weapon",
|
||||||
|
["pmsettings_voice"] = "Character Voice",
|
||||||
|
["pmsettings_mes1"] = "You can't edit your character, while the wave has started.",
|
||||||
|
["pmsettings_mes2"] = "You changed the settings for your character.",
|
||||||
|
["pmsettings_mes3"] = "You can only change character settings when you are in spectator mode.",
|
||||||
|
["pmsettings_info"] = "Settings will be saved after closing",
|
||||||
|
|
||||||
|
["classmenu_choose"] = "Viewing class: %s, class level - %s",
|
||||||
|
["classmenu_current"] = "Your current class: ",
|
||||||
|
["classmenu_info"] = "Ability Information",
|
||||||
|
["classmenu_state"] = "Unlock level - ",
|
||||||
|
|
||||||
|
["adminsettings_main"] = "Admin Settings",
|
||||||
|
["adminsettings_startgame"] = "Start Game",
|
||||||
|
["adminsettings_skipwave"] = "Skip Wave",
|
||||||
|
["adminsettings_spawnmenu"] = "Open Spawnmenu",
|
||||||
|
|
||||||
|
["fuel"] = "Fuel",
|
||||||
|
["evac"] = "Evacuation",
|
||||||
|
["evac_start"] = "EXFIL HELICOPTER INBOUND",
|
||||||
|
["evac_last_start"] = "LAST EXFIL HELICOPTER INBOUND",
|
||||||
|
["radio_main"] = "RADIO",
|
||||||
|
["radio_1"] = "Call supply drop",
|
||||||
|
["radio_2"] = "Request artillery support",
|
||||||
|
["radio_3"] = "Call reinforcements",
|
||||||
|
["radio_4"] = "Deploy bait",
|
||||||
|
["radio_5"] = "Call assault helicopter",
|
||||||
|
["radio_6"] = "Start exfil",
|
||||||
|
["radio_6_warn"] = "Exfil will be allowed on %i wave.",
|
||||||
|
["radio_6_disable"] = "Exfil is not allowed on this map.",
|
||||||
|
["radio_7"] = "Buy weapon",
|
||||||
|
|
||||||
|
["revive_main"] = "You are heavily wounded",
|
||||||
|
["revive_wait"] = "Wait for your teammates to revive you",
|
||||||
|
["revive_help"] = "Hold [E] to help your teammate",
|
||||||
|
["revive_self"] = "Press [E] to use self revive kit",
|
||||||
|
|
||||||
|
["main_count"] = "Enemies remaining: ",
|
||||||
|
["main_wave"] = "WAVE ",
|
||||||
|
["main_pickup"] = "Press [E] to pick up ",
|
||||||
|
|
||||||
|
["killstreak_exec"] = "EXECUTION",
|
||||||
|
["killstreak_1"] = "DOUBLE KILL",
|
||||||
|
["killstreak_2"] = "TRIPLE KILL",
|
||||||
|
["killstreak_3"] = "ULTRA KILL",
|
||||||
|
["killstreak_4"] = "MEAT GRINDER",
|
||||||
|
|
||||||
|
["message_main1"] = "Survive",
|
||||||
|
["message_main2"] = "You can find loot in buildings every wave",
|
||||||
|
["message_wavestart1"] = "Wave %i has started",
|
||||||
|
["message_wavestart2"] = "Each wave will become more difficult",
|
||||||
|
["message_waveend1"] = "Wave %i has ended",
|
||||||
|
["message_waveend2"] = "You have time to search for loot and catch your breath",
|
||||||
|
["message_thelp1"] = " has been critically wounded",
|
||||||
|
["message_thelp2"] = "Help your teammate before he bleeds out",
|
||||||
|
["message_tdied1"] = "You have suffered a loss",
|
||||||
|
["message_tdied2"] = " was killed in action",
|
||||||
|
["message_radio_accept"] = "Radio request accepted",
|
||||||
|
["message_radio_support"] = "New reinforcements have arrived in your sector",
|
||||||
|
["message_radio_mortar"] = "Mark targets for artillery support using markers",
|
||||||
|
["message_radio_away"] = "Bait will be deployed in 15 seconds",
|
||||||
|
["message_radio_supply"] = "Supply drop will be delivered in 30 seconds",
|
||||||
|
["message_radio_heli"] = "Assault helicopter will be arrived in 30 seconds",
|
||||||
|
["message_radio_exfil"] = "Exfil will start in 2 minutes",
|
||||||
|
["message_warn"] = "Warning",
|
||||||
|
["message_zombie_phase"] = "The horde has mutated to the %i stage, get ready",
|
||||||
|
["message_mark"] = " placed a mark",
|
||||||
|
["message_info"] = "Information",
|
||||||
|
["message_radio_found"] = " found a radio",
|
||||||
|
["message_healed"] = "You were healed by ",
|
||||||
|
["message_healing"] = "You have healed ",
|
||||||
|
["message_open_box"] = " opened the supply box",
|
||||||
|
["message_fuel"] = " used a fuel canister",
|
||||||
|
["message_obj_done"] = "The task has been completed, move to the evacuation point",
|
||||||
|
|
||||||
|
["loot_pistol"] = "Pistol Rounds",
|
||||||
|
["loot_smg"] = "SMG Rounds",
|
||||||
|
["loot_bucks"] = "Buckshot",
|
||||||
|
["loot_ar"] = "AR Rounds",
|
||||||
|
["loot_sr"] = "SR Rounds",
|
||||||
|
["loot_radio"] = "Radio",
|
||||||
|
["loot_bandages"] = "Bandages",
|
||||||
|
["loot_antidote"] = "Antidote",
|
||||||
|
["loot_nails"] = "Nails",
|
||||||
|
["loot_fak"] = "First Aid Kit",
|
||||||
|
["loot_gr"] = "Explosive Round",
|
||||||
|
["loot_ammocrate"] = "Ammo Crate",
|
||||||
|
["loot_selfrevive"] = "Self Revive Kit",
|
||||||
|
["loot_capsule"] = "XP Capsule",
|
||||||
|
["loot_grenades"] = "Grenade Crate",
|
||||||
|
["loot_money"] = "Money",
|
||||||
|
["loot_tier1"] = "Common",
|
||||||
|
["loot_tier2"] = "Uncommon",
|
||||||
|
["loot_tier3"] = "Rare",
|
||||||
|
["loot_tier4"] = "Epic",
|
||||||
|
["loot_tier5"] = "Legendary",
|
||||||
|
|
||||||
|
["game_over_main"] = "The Survivor Squad was overrun",
|
||||||
|
["game_over_success"] = "Exfil was successful",
|
||||||
|
["game_over_wave"] = "You survived %i wave",
|
||||||
|
|
||||||
|
["deploy_big"] = "There are more people in the squad than you see, when you deploy you will see them.",
|
||||||
|
["deploy_hint"] = "By pressing ESC, you can open the main menu and customize your character",
|
||||||
|
["deploy_time"] = "Time to deployment: %i sec.",
|
||||||
|
["deploy_error_node"] = "[Gamemode Error] There are no AI Nodes on the map, please install AI nodes for the map",
|
||||||
|
["deploy_error_config"] = "[Gamemode Error] There is no config on the map, please create a config for the map",
|
||||||
|
|
||||||
|
["main_menu_1"] = "Continue",
|
||||||
|
["main_menu_2"] = "Character",
|
||||||
|
["main_menu_3"] = "Classes",
|
||||||
|
["main_menu_4"] = "Settings",
|
||||||
|
["main_menu_discord"] = "Discord Community",
|
||||||
|
["main_menu_site"] = "Our Website",
|
||||||
|
["main_menu_5"] = "Main Menu",
|
||||||
|
["hud_discord_join"] = "Join us on Discord!",
|
||||||
|
|
||||||
|
["menu_drop"] = "Drop Items",
|
||||||
|
["menu_nodrop"] = "You don't have any items.",
|
||||||
|
|
||||||
|
["heal_bandages"] = "Press [B] to patch up your teammate",
|
||||||
|
["heal_spray"] = "Press [H] to cure your infected teammate",
|
||||||
|
|
||||||
|
["unreachable"] = "You are in a position where the NPCs can't reach you, you will be teleported if you don't get out of there.",
|
||||||
|
["start_message1"] = "Objective: Kill as many zombies as possible, in extreme cases - evacuate.",
|
||||||
|
["start_message_fuel"] = "Objective: Refuel the generators and retreat to the evacuation zone.",
|
||||||
|
|
||||||
|
["hammer_parts"] = "Nails: ",
|
||||||
|
["hammer_controls"] = "Controls: LMB - Attach, RMB - Unattach, R - Drag, Shift - Hold, Alt - Rotate",
|
||||||
|
|
||||||
|
["boss_punk"] = "Punk",
|
||||||
|
["boss_butcher"] = "Butcher",
|
||||||
|
["boss_tyrant"] = "Tyrant",
|
||||||
|
["boss_tank"] = "Tank",
|
||||||
|
|
||||||
|
["mutator_main"] = "Mutator",
|
||||||
|
["mutator_appear"] = "A mutator has been discovered for this wave, get ready",
|
||||||
|
["mutator_1"] = "Explosive Burst",
|
||||||
|
["mutator_2"] = "Mutator Breakthrough",
|
||||||
|
["mutator_3"] = "Strong Grip",
|
||||||
|
["mutator_4"] = "Fragile organs",
|
||||||
|
["mutator_5"] = "Berserker",
|
||||||
|
["mutator_6"] = "Necrosis",
|
||||||
|
["mutator_7"] = "Loser",
|
||||||
|
["mutator_8"] = "Airstrike",
|
||||||
|
["mutator_9"] = "Scavenger",
|
||||||
|
["mutator_10"] = "Pain Shock",
|
||||||
|
["mutator_11"] = "Gas Leak",
|
||||||
|
["mutator_12"] = "Weakness",
|
||||||
|
["mutator_1_desc"] = "Zombies may explode when killed",
|
||||||
|
["mutator_2_desc"] = "All zombies mutated into special variants",
|
||||||
|
["mutator_3_desc"] = "Zombies grab the player more often",
|
||||||
|
["mutator_4_desc"] = "Zombie health reduced to 25%",
|
||||||
|
["mutator_5_desc"] = "Melee damage will instakill zombies",
|
||||||
|
["mutator_6_desc"] = "Any melee hit by a zombie will cause a infection",
|
||||||
|
["mutator_7_desc"] = "Items stopped spawning, until next wave",
|
||||||
|
["mutator_8_desc"] = "Permanent supply drop every minute",
|
||||||
|
["mutator_9_desc"] = "Zombies may drop loot upon death",
|
||||||
|
["mutator_10_desc"] = "Players immediately die upon losing all their health",
|
||||||
|
["mutator_11_desc"] = "A deadly gas leak has been discovered, get ready to exfil",
|
||||||
|
["mutator_12_desc"] = "Players move slowly, as if injured",
|
||||||
|
|
||||||
|
["zombiemenu_choose"] = "Choose Zombie Class",
|
||||||
|
["zombiemenu_unlock"] = "Unlock on %i wave",
|
||||||
|
["zombiemenu_unlocked"] = "Unlocked",
|
||||||
|
["zombie_attack1"] = "Attack - LMB",
|
||||||
|
["zombie_attack2"] = "Ability - RMB",
|
||||||
|
["zombie_spawn"] = "LMB - Spawn as a zombie",
|
||||||
|
["zombie_wait"] = "Wait for the wave to start attack again",
|
||||||
|
["zombie_choose"] = "The game has chosen you to be infected, kill all humans",
|
||||||
|
["zombie_menu"] = "F1 - Select zombie class",
|
||||||
|
|
||||||
|
["tip_main"] = "Tips",
|
||||||
|
["tip_survival"] = "Beginning",
|
||||||
|
["tip_survival_desc"] = "Greetings, survivor! Quite a long time has passed since the virus spread across the planet, now your main task is to survive. You can find things most often in buildings, they will help you fight off attacks. If you don't need hints, you can turn them off. Good luck!",
|
||||||
|
["tip_waves"] = "Waves",
|
||||||
|
["tip_waves_desc"] = "The further you survive in this place, the more and more difficult the infected become, so look for equipment as quickly as possible! With each wave of them, the onslaught increases. Their evolution does not stand still...",
|
||||||
|
["tip_items"] = "Items",
|
||||||
|
["tip_items_desc"] = "Equipment scattered around the location is an important part of your survival. The higher the wave, the greater the chances of finding rare equipment. By the way, on F1 you can share things with your teammates, on F2 you can mark positions, items and enemies.",
|
||||||
|
["tip_bosses"] = "Leaders",
|
||||||
|
["tip_bosses_desc"] = "On some waves, you can meet the so-called leaders. Leaders are the most powerful infected who lead the main crowd. I hope you have already found the equipment, since the battle with him will be extremely difficult...",
|
||||||
|
["tip_revive"] = "Revive",
|
||||||
|
["tip_revive_desc"] = "Someday, you or your partner will be seriously injured, causing you to fall to the ground. Try to help your partner as soon as possible, with each wave the zombies react better to those who have fallen.",
|
||||||
|
["tip_radio"] = "Radio",
|
||||||
|
["tip_radio_desc"] = "Finally, you were able to find contact with the military. Now you can request reinforcements or evacuation from them. I advise you to take care of the radios, as they are very rare. They play a key role in your survival...",
|
||||||
|
["tip_cade"] = "Hammer",
|
||||||
|
["tip_cade_desc"] = "This find greatly increases your chances of survival. By picking up a hammer and finding some nails, you can build a barricade from movable objects. To nail an object, you need to aim at its edge and hammer in a nail. Unfortunately, the strength items have limits, be careful!",
|
||||||
|
["tip_evac"] = "Evacuation",
|
||||||
|
["tip_evac_desc"] = "Well, survivor, it's time to leave here. You have to fight a huge horde of zombies to hold out and make your way to the helicopter. Usually the helicopter flight to the landing site takes 2 minutes. I hope we see you alive, I wish you Good luck.",
|
||||||
|
|
||||||
|
["class_survivor"] = "Survivor",
|
||||||
|
["class_scout"] = "Scout",
|
||||||
|
["class_medic"] = "Medic",
|
||||||
|
["class_engineer"] = "Engineer",
|
||||||
|
["class_marksman"] = "Shooter",
|
||||||
|
["class_berserker"] = "Berserker",
|
||||||
|
["class_demoman"] = "Demoman",
|
||||||
|
|
||||||
|
["class_survivor_state_1"] = "At start, 1 emergency kit is given",
|
||||||
|
["class_survivor_state_2"] = "You can now escape from grabs much easier",
|
||||||
|
["class_survivor_state_3"] = "Damage from firearms weapons increased by 10%",
|
||||||
|
["class_survivor_state_4"] = "Damage from firearms weapons increased by 20%",
|
||||||
|
["class_survivor_state_5"] = "Damage from firearms weapons increased by 30%",
|
||||||
|
|
||||||
|
["class_scout_state_1"] = "Ability to see nearby items through the wall",
|
||||||
|
["class_scout_state_2"] = "Running speed increased by 20%",
|
||||||
|
["class_scout_state_3"] = "At start you are given 2 radios",
|
||||||
|
["class_scout_state_4"] = "Running speed increased by 40%",
|
||||||
|
["class_scout_state_5"] = "At start you are given 5 radios",
|
||||||
|
|
||||||
|
["class_medic_state_1"] = "At start you are given 9 bandages and 3 antidotes",
|
||||||
|
["class_medic_state_2"] = "Bandages now heal full health",
|
||||||
|
["class_medic_state_3"] = "At start you are given 18 bandages, 6 antidotes, 3 emergency kits",
|
||||||
|
["class_medic_state_4"] = "You can now instantly revive downed players",
|
||||||
|
["class_medic_state_5"] = "At start you are given 100 bandages and 50 antidotes, 5 emergency kits",
|
||||||
|
|
||||||
|
["class_engineer_state_1"] = "The strength of the barricades is increased by 10%",
|
||||||
|
["class_engineer_state_2"] = "At start you are given a hammer and nails",
|
||||||
|
["class_engineer_state_3"] = "Barricade strength increased by 50%",
|
||||||
|
["class_engineer_state_4"] = "Barricade strength increased by 100%",
|
||||||
|
["class_engineer_state_5"] = "A landmines is given at startup",
|
||||||
|
|
||||||
|
["class_marksman_state_1"] = "Additional ammo is given at start",
|
||||||
|
["class_marksman_state_2"] = "Sniper rifle damage increased by 25%",
|
||||||
|
["class_marksman_state_3"] = "Sniper rifle damage increased by 50%",
|
||||||
|
["class_marksman_state_4"] = "At start, you are given a random weapon of rarity 3",
|
||||||
|
["class_marksman_state_5"] = "Sniper rifle damage increased by 100%",
|
||||||
|
|
||||||
|
["class_berserker_state_1"] = "Melee weapon damage increased by 50%",
|
||||||
|
["class_berserker_state_2"] = "Kick damage increased by 4 times",
|
||||||
|
["class_berserker_state_3"] = "Melee weapon damage increased by 100%, random melee weapon on spawn",
|
||||||
|
["class_berserker_state_4"] = "Reducing damage at half to player",
|
||||||
|
["class_berserker_state_5"] = "Melee weapon damage increased by 200%",
|
||||||
|
|
||||||
|
["class_demoman_state_1"] = "Stun by damage is disabled, damage from explosions reduced",
|
||||||
|
["class_demoman_state_2"] = "Double ammo for grenade launchers",
|
||||||
|
["class_demoman_state_3"] = "M79 giving at start",
|
||||||
|
["class_demoman_state_4"] = "Damage from explosions increased by 50%",
|
||||||
|
["class_demoman_state_5"] = "Damage from explosions increased by 100%",
|
||||||
|
|
||||||
|
["class_lvl_1"] = "Beginner I",
|
||||||
|
["class_lvl_2"] = "Beginner II",
|
||||||
|
["class_lvl_3"] = "Beginner III",
|
||||||
|
["class_lvl_4"] = "Beginner IV",
|
||||||
|
["class_lvl_5"] = "Beginner V",
|
||||||
|
["class_lvl_6"] = "Average I",
|
||||||
|
["class_lvl_7"] = "Average II",
|
||||||
|
["class_lvl_8"] = "Average III",
|
||||||
|
["class_lvl_9"] = "Average IV",
|
||||||
|
["class_lvl_10"] = "Average V",
|
||||||
|
["class_lvl_11"] = "Experienced I",
|
||||||
|
["class_lvl_12"] = "Experienced II",
|
||||||
|
["class_lvl_13"] = "Experienced III",
|
||||||
|
["class_lvl_14"] = "Experienced IV",
|
||||||
|
["class_lvl_15"] = "Experienced V",
|
||||||
|
["class_lvl_16"] = "Veteran I",
|
||||||
|
["class_lvl_17"] = "Veteran II",
|
||||||
|
["class_lvl_18"] = "Veteran III",
|
||||||
|
["class_lvl_19"] = "Veteran IV",
|
||||||
|
["class_lvl_20"] = "Veteran V",
|
||||||
|
["class_lvl_21"] = "Expert",
|
||||||
|
|
||||||
|
["buymenu_main"] = "Shop",
|
||||||
|
["buymenu_buy"] = "Buy",
|
||||||
|
}
|
||||||
@@ -0,0 +1,280 @@
|
|||||||
|
SuR.Language = {
|
||||||
|
["settings_main"] = "Клиентские настройки",
|
||||||
|
["settings_vm"] = "Режим камеры",
|
||||||
|
["settings_vmc"] = "Катсцены от 3 лица?",
|
||||||
|
["settings_vmd"] = "Анимации смерти от 3 лица?",
|
||||||
|
["settings_mv"] = "Громкость музыки",
|
||||||
|
["settings_rus"] = "Включить русскую озвучку",
|
||||||
|
["settings_zc"] = "Отключить интерфейс",
|
||||||
|
["settings_dh"] = "Отключить советы",
|
||||||
|
|
||||||
|
["mode"] = "Режим: ",
|
||||||
|
["mode_survival"] = "Выживание",
|
||||||
|
["mode_versus"] = "Сражение",
|
||||||
|
["mode_objective"] = "Операция",
|
||||||
|
|
||||||
|
["pmsettings_main"] = "Модель персонажа",
|
||||||
|
["pmsettings_wep"] = "Оружие персонажа",
|
||||||
|
["pmsettings_voice"] = "Голос персонажа",
|
||||||
|
["pmsettings_mes1"] = "Вы можете поменять настройки персонажа только во время передышки.",
|
||||||
|
["pmsettings_mes2"] = "Вы изменили настройки персонажа на новые.",
|
||||||
|
["pmsettings_mes3"] = "Вы можете поменять настройки персонажа только, когда вы не играете за персонажа.",
|
||||||
|
["pmsettings_info"] = "Настройки сохранятся после закрытия",
|
||||||
|
|
||||||
|
["classmenu_choose"] = "Просмотр класса: %s, его уровень - %s",
|
||||||
|
["classmenu_current"] = "Ваш текущий класс: ",
|
||||||
|
["classmenu_info"] = "Информация о способностях",
|
||||||
|
["classmenu_state"] = "Уровень разблокировки - ",
|
||||||
|
|
||||||
|
["adminsettings_main"] = "Админ настройки",
|
||||||
|
["adminsettings_startgame"] = "Начать игру",
|
||||||
|
["adminsettings_skipwave"] = "Пропустить волну",
|
||||||
|
["adminsettings_spawnmenu"] = "Открыть спавнменю",
|
||||||
|
|
||||||
|
["fuel"] = "Топливо",
|
||||||
|
["evac"] = "Эвакуация",
|
||||||
|
["evac_start"] = "ЭВАКУАЦИОННЫЙ ВЕРТОЛЁТ ВЫЛЕТЕЛ",
|
||||||
|
["evac_last_start"] = "ПОСЛЕДНИЙ ЭВАКУАЦИОННЫЙ ВЕРТОЛЁТ ВЫЛЕТЕЛ",
|
||||||
|
["radio_main"] = "РАДИО",
|
||||||
|
["radio_1"] = "Вызвать посылку с припасами",
|
||||||
|
["radio_2"] = "Указать цель для артобстрела",
|
||||||
|
["radio_3"] = "Доставить подкрепление",
|
||||||
|
["radio_4"] = "Запустить приманку",
|
||||||
|
["radio_5"] = "Вызвать вертолёт поддержки",
|
||||||
|
["radio_6"] = "Начать эвакуацию",
|
||||||
|
["radio_6_warn"] = "Эвакуацию можно начать только с %i волны.",
|
||||||
|
["radio_6_disable"] = "Эвакуация невозможна на этой карте.",
|
||||||
|
["radio_7"] = "Купить оружие",
|
||||||
|
|
||||||
|
["revive_main"] = "Вы тяжело ранены",
|
||||||
|
["revive_wait"] = "Подождите пока вас поднимут напарники",
|
||||||
|
["revive_help"] = "Зажмите [E] чтобы помочь напарнику",
|
||||||
|
["revive_self"] = "Нажмите [E] чтобы использовать набор самореанимации",
|
||||||
|
|
||||||
|
["main_count"] = "Осталось врагов: ",
|
||||||
|
["main_wave"] = "ВОЛНА ",
|
||||||
|
["main_pickup"] = "Нажмите [E] чтобы подобрать ",
|
||||||
|
|
||||||
|
["killstreak_exec"] = "ДОБИВАНИЕ",
|
||||||
|
["killstreak_1"] = "ДВОЙНОЕ УБИЙСТВО",
|
||||||
|
["killstreak_2"] = "ТРОЙНОЕ УБИЙСТВО",
|
||||||
|
["killstreak_3"] = "УЛЬТРА УБИЙСТВО",
|
||||||
|
["killstreak_4"] = "МЯСОРУБКА",
|
||||||
|
|
||||||
|
["message_main1"] = "Выживите",
|
||||||
|
["message_main2"] = "Вы можете найти лут в доме каждую волну",
|
||||||
|
["message_wavestart1"] = "Волна %i началась",
|
||||||
|
["message_wavestart2"] = "С каждой волной становится всё сложней",
|
||||||
|
["message_waveend1"] = "Волна %i закончилась",
|
||||||
|
["message_waveend2"] = "У вас есть время на поиск лута и передышку",
|
||||||
|
["message_thelp1"] = " получил тяжелое ранение",
|
||||||
|
["message_thelp2"] = "Помогите напарнику до того как он истечет кровью",
|
||||||
|
["message_tdied1"] = "Вы несете потери",
|
||||||
|
["message_tdied2"] = " погиб в бою",
|
||||||
|
["message_radio_accept"] = "Запрос по рации принят",
|
||||||
|
["message_radio_support"] = "Новые бойцы прибыли в ваш сектор",
|
||||||
|
["message_radio_mortar"] = "Укажите цели для артобстрела с помощью маркеров",
|
||||||
|
["message_radio_away"] = "Сброс приманки будет в течении 15 секунд",
|
||||||
|
["message_radio_supply"] = "Сброс припасов будет в течении 30 секунд",
|
||||||
|
["message_radio_heli"] = "Вертолёт поддержки будет в течении 30 секунд",
|
||||||
|
["message_radio_exfil"] = "Эвакуация начнется через 2 минуты",
|
||||||
|
["message_warn"] = "Внимание",
|
||||||
|
["message_zombie_phase"] = "Орда развилась до %i стадии, будьте готовы",
|
||||||
|
["message_mark"] = " поставил метку",
|
||||||
|
["message_info"] = "Информация",
|
||||||
|
["message_radio_found"] = " нашел рацию",
|
||||||
|
["message_healed"] = "Вас вылечил ",
|
||||||
|
["message_healing"] = "Вы вылечили ",
|
||||||
|
["message_open_box"] = " открыл ящик с припасами",
|
||||||
|
["message_fuel"] = " использовал канистру с топливом",
|
||||||
|
["message_obj_done"] = "Задача была выполнена, бегите в точку эвакуации",
|
||||||
|
|
||||||
|
["loot_pistol"] = "Патроны для пистолетов",
|
||||||
|
["loot_smg"] = "Патроны для СМГ",
|
||||||
|
["loot_bucks"] = "Патроны для дробовика",
|
||||||
|
["loot_ar"] = "Патроны для автом. винтовок",
|
||||||
|
["loot_sr"] = "Патроны для снайп. винтовок",
|
||||||
|
["loot_radio"] = "Рация",
|
||||||
|
["loot_bandages"] = "Бинты",
|
||||||
|
["loot_antidote"] = "Антидот",
|
||||||
|
["loot_nails"] = "Гвозди",
|
||||||
|
["loot_fak"] = "Аптечка",
|
||||||
|
["loot_gr"] = "Снаряд",
|
||||||
|
["loot_ammocrate"] = "Ящик с патронами",
|
||||||
|
["loot_selfrevive"] = "Набор самореанимации",
|
||||||
|
["loot_capsule"] = "Капсула опыта",
|
||||||
|
["loot_grenades"] = "Ящик с гранатами",
|
||||||
|
["loot_money"] = "Деньги",
|
||||||
|
["loot_tier1"] = "Стартовый",
|
||||||
|
["loot_tier2"] = "Обычный",
|
||||||
|
["loot_tier3"] = "Редкий",
|
||||||
|
["loot_tier4"] = "Раритетный",
|
||||||
|
["loot_tier5"] = "Легендарный",
|
||||||
|
|
||||||
|
["game_over_main"] = "Группа Выживших была уничтожена",
|
||||||
|
["game_over_success"] = "Эвакуация завершилась успешно",
|
||||||
|
["game_over_wave"] = "Вы прожили %i волн",
|
||||||
|
|
||||||
|
["deploy_big"] = "В отряде больше человек, чем вы видите, при высадке вы их увидите.",
|
||||||
|
["deploy_hint"] = "На клавишу ESC, вы можете открыть главное меню и настроить вашего персонажа",
|
||||||
|
["deploy_time"] = "Время до высадки: %i сек.",
|
||||||
|
["deploy_error_node"] = "[Режим Остановлен] На карте нет AI Nodes, пожалуйста установите сетку на карту",
|
||||||
|
["deploy_error_config"] = "[Режим Остановлен] На карте нет config файла, пожалуйста сделайте config файл для карты",
|
||||||
|
|
||||||
|
["main_menu_1"] = "Продолжить",
|
||||||
|
["main_menu_2"] = "Персонаж",
|
||||||
|
["main_menu_3"] = "Классы",
|
||||||
|
["main_menu_4"] = "Настройки",
|
||||||
|
["main_menu_discord"] = "Сообщество Discord",
|
||||||
|
["main_menu_site"] = "Наш сайт",
|
||||||
|
["main_menu_5"] = "Главное меню",
|
||||||
|
["hud_discord_join"] = "Присоединяйтесь к нам в Discord!",
|
||||||
|
|
||||||
|
["menu_drop"] = "Выбросить предмет",
|
||||||
|
["menu_nodrop"] = "У вас нету вещей.",
|
||||||
|
|
||||||
|
["heal_spray"] = "Нажмите [H] чтобы вылечить инфекцию напарника",
|
||||||
|
["heal_bandages"] = "Нажмите [B] чтобы завязать раны напарника",
|
||||||
|
|
||||||
|
["unreachable"] = "Вы находитесь в позиции, где вас не могут достать нпс, вы будете телепортированы, если не выберитесь оттуда.",
|
||||||
|
["start_message1"] = "Ваша задача: Убить как можно больше зомби, в крайнем случае - эвакуироваться.",
|
||||||
|
["start_message_fuel"] = "Ваша задача: Заправить генераторы и отступить в зону эвакуации.",
|
||||||
|
|
||||||
|
["hammer_parts"] = "Гвозди: ",
|
||||||
|
["hammer_controls"] = "Управление: ЛКМ - Прибить, ПКМ - Открепить, R - Перетаскивать, Shift - Удерживать, Alt - Вращать",
|
||||||
|
|
||||||
|
["boss_punk"] = "Панк",
|
||||||
|
["boss_butcher"] = "Мясник",
|
||||||
|
["boss_tyrant"] = "Тиран",
|
||||||
|
["boss_tank"] = "Танк",
|
||||||
|
|
||||||
|
["mutator_main"] = "Мутатор",
|
||||||
|
["mutator_appear"] = "На эту волну был обнаружен мутатор, готовтесь",
|
||||||
|
["mutator_1"] = "Взрывная серия",
|
||||||
|
["mutator_2"] = "Прорыв мутаций",
|
||||||
|
["mutator_3"] = "Сильный хват",
|
||||||
|
["mutator_4"] = "Хрупкие органы",
|
||||||
|
["mutator_5"] = "Берсерк",
|
||||||
|
["mutator_6"] = "Некроз",
|
||||||
|
["mutator_7"] = "Неудачник",
|
||||||
|
["mutator_8"] = "Авианалет",
|
||||||
|
["mutator_9"] = "Падальщик",
|
||||||
|
["mutator_10"] = "Болевой шок",
|
||||||
|
["mutator_11"] = "Утечка газа",
|
||||||
|
["mutator_12"] = "Слабость",
|
||||||
|
["mutator_1_desc"] = "После смерти зомби могут взорваться",
|
||||||
|
["mutator_2_desc"] = "Все обычные зомби мутировали в специальных",
|
||||||
|
["mutator_3_desc"] = "Зомби чаще хватают игрока",
|
||||||
|
["mutator_4_desc"] = "Жизни зомби уменьшены до 25%",
|
||||||
|
["mutator_5_desc"] = "Любой удар с рукопашного оружия, убивает зомби",
|
||||||
|
["mutator_6_desc"] = "Любой удар зомби приведёт к инфекции",
|
||||||
|
["mutator_7_desc"] = "На локации и в посылках больше нету вещей",
|
||||||
|
["mutator_8_desc"] = "Постоянный сброс припасов каждую минуту",
|
||||||
|
["mutator_9_desc"] = "С зомби может упасть лут после смерти",
|
||||||
|
["mutator_10_desc"] = "Игроки умирают сразу без падения",
|
||||||
|
["mutator_11_desc"] = "Произошла утечка смертельного газа, готовтесь",
|
||||||
|
["mutator_12_desc"] = "Игроки ходят медленно, как при ранении",
|
||||||
|
|
||||||
|
["zombiemenu_choose"] = "Выбор класса зомби",
|
||||||
|
["zombiemenu_unlock"] = "Доступ на %i волне",
|
||||||
|
["zombiemenu_unlocked"] = "Разблокирован",
|
||||||
|
["zombie_attack1"] = "Удар - ЛКМ",
|
||||||
|
["zombie_attack2"] = "Способность - ПКМ",
|
||||||
|
["zombie_spawn"] = "ЛКМ - Возродиться за зомби",
|
||||||
|
["zombie_wait"] = "Ожидайте начало волны, чтобы возобновить атаку",
|
||||||
|
["zombie_choose"] = "Игра выбрала вас зараженным, убейте всех людей",
|
||||||
|
["zombie_menu"] = "F1 - Выбрать класс зомби",
|
||||||
|
|
||||||
|
["tip_main"] = "Советы",
|
||||||
|
["tip_survival"] = "Начало",
|
||||||
|
["tip_survival_desc"] = "Приветствую тебя, выживший! Прошло довольно много времени с распространения вируса по планете, теперь твоя основная задача - выжить. Ты можешь найти вещи чаще всего в зданиях, они помогут тебе отбиться от атак. Если тебе не нужны подсказки, ты можешь их отключить. Удачи!",
|
||||||
|
["tip_waves"] = "Волны",
|
||||||
|
["tip_waves_desc"] = "Чем дальше ты выживаешь в этом месте, тем больше и сложнее идут зараженные, поэтому как можно быстрее ищи экипировку! С каждой их волной, натиск возрастает. Их эволюция не стоит на месте...",
|
||||||
|
["tip_items"] = "Вещи",
|
||||||
|
["tip_items_desc"] = "Экипировка, разбросанная на локации - важная часть твоего выживания. Чем выше волна, тем больше шансов найти редкое снаряжение. Кстати, на F1 ты можешь делиться вещами со своими напарниками, на F2 ты можешь пометить позицию, вещи или противника.",
|
||||||
|
["tip_bosses"] = "Главари",
|
||||||
|
["tip_bosses_desc"] = "На некоторых волнах, ты можешь встретить так называемых главарей. Главари - это самые сильные зараженные, которые руководят основной толпой. Надеюсь ты уже нашел снаряжение, так как сражение с ним будет крайне тяжелым...",
|
||||||
|
["tip_revive"] = "Реанимация",
|
||||||
|
["tip_revive_desc"] = "Когда нибудь, ты или твой напарник получит тяжелые ранения, из-за чего упадут на землю. Как можно скорее постарайся помочь своему напарнику, с каждой волной зомби лучше реагируют на упавших.",
|
||||||
|
["tip_radio"] = "Рация",
|
||||||
|
["tip_radio_desc"] = "Наконец-то ты смог найти связь с военными. Теперь ты можешь запросить у них подкрепление или эвакуацию. Советую беречь рации, так как они очень редкие. Они играют ключевую роль в твоём выживании...",
|
||||||
|
["tip_cade"] = "Молоток",
|
||||||
|
["tip_cade_desc"] = "Эта находка сильно увеличивает твои шансы выживания. Взяв в руки молоток, найдя немного гвоздей, ты сможешь построить баррикаду из подвижных подручных предметов. Чтобы приколотить предмет, нужно навестись на его край и забить гвоздь. К сожалению, прочность предметов имеет пределы, будь аккуратен!",
|
||||||
|
["tip_evac"] = "Эвакуация",
|
||||||
|
["tip_evac_desc"] = "Ну что, выживший, пора уходить отсюда. Тебе предстоит сразиться с огромной ордой зомби, чтобы продержаться и пробиться к вертолёту. Обычно полет вертолета до место посадки занимает 2 минуты. Я надеюсь мы увидим тебя живым, желаю тебе удачи.",
|
||||||
|
|
||||||
|
["class_survivor"] = "Выживший",
|
||||||
|
["class_scout"] = "Разведчик",
|
||||||
|
["class_medic"] = "Медик",
|
||||||
|
["class_engineer"] = "Инженер",
|
||||||
|
["class_marksman"] = "Стрелок",
|
||||||
|
["class_berserker"] = "Берсерк",
|
||||||
|
["class_demoman"] = "Подрывник",
|
||||||
|
|
||||||
|
["class_survivor_state_1"] = "При старте дается 1 набор экстренной помощи",
|
||||||
|
["class_survivor_state_2"] = "Теперь вы намного легче вырывайтесь из захватов",
|
||||||
|
["class_survivor_state_3"] = "Урон от огнестрельных оружий повышен на 10%",
|
||||||
|
["class_survivor_state_4"] = "Урон от огнестрельных оружий повышен на 20%",
|
||||||
|
["class_survivor_state_5"] = "Урон от огнестрельных оружий повышен на 30%",
|
||||||
|
|
||||||
|
["class_scout_state_1"] = "Возможность видеть ближайшие предметы сквозь стены",
|
||||||
|
["class_scout_state_2"] = "Скорость бега повышена на 20%",
|
||||||
|
["class_scout_state_3"] = "При старте дается 2 рации",
|
||||||
|
["class_scout_state_4"] = "Скорость бега повышена на 40%",
|
||||||
|
["class_scout_state_5"] = "При старте дается 5 раций",
|
||||||
|
|
||||||
|
["class_medic_state_1"] = "При старте дается 9 бинтов и 3 антидота",
|
||||||
|
["class_medic_state_2"] = "Теперь бинты лечат полное здоровье",
|
||||||
|
["class_medic_state_3"] = "При старте дается 18 бинтов, 6 антидотов, 3 набора экстренной помощи",
|
||||||
|
["class_medic_state_4"] = "Теперь вы моментально поднимаете упавших игроков",
|
||||||
|
["class_medic_state_5"] = "Бинты и антидоты теперь в большом количестве",
|
||||||
|
|
||||||
|
["class_engineer_state_1"] = "Прочность баррикад повышена на 10%",
|
||||||
|
["class_engineer_state_2"] = "При старте дается молоток и гвозди",
|
||||||
|
["class_engineer_state_3"] = "Прочность баррикад повышена на 50%",
|
||||||
|
["class_engineer_state_4"] = "Прочность баррикад повышена на 100%",
|
||||||
|
["class_engineer_state_5"] = "При старте даются мины",
|
||||||
|
|
||||||
|
["class_marksman_state_1"] = "При старте даются дополнительные патроны",
|
||||||
|
["class_marksman_state_2"] = "Урон со снайперских винтовок повышен на 25%",
|
||||||
|
["class_marksman_state_3"] = "Урон со снайперских винтовок повышен на 50%",
|
||||||
|
["class_marksman_state_4"] = "При старте дается случайное оружие 3 редкости",
|
||||||
|
["class_marksman_state_5"] = "Урон со снайперских винтовок повышен на 100%",
|
||||||
|
|
||||||
|
["class_berserker_state_1"] = "Урон от рукопашного оружия повышен на 50%",
|
||||||
|
["class_berserker_state_2"] = "Урон от пинка повышен в 4 раза",
|
||||||
|
["class_berserker_state_3"] = "Урон от рукопашного оружия повышен на 100%, случайное холодное оружие при спавне",
|
||||||
|
["class_berserker_state_4"] = "Уменьшение получаемого урона вдвое",
|
||||||
|
["class_berserker_state_5"] = "Урон от рукопашного оружия повышен на 200%",
|
||||||
|
|
||||||
|
["class_demoman_state_1"] = "Оглушение от урона отсутствует, уменьшен урон от взрывов",
|
||||||
|
["class_demoman_state_2"] = "Удвоенные патроны для гранатомётов",
|
||||||
|
["class_demoman_state_3"] = "Выдача M79 при старте",
|
||||||
|
["class_demoman_state_4"] = "Урон от взрывов повышен на 50%",
|
||||||
|
["class_demoman_state_5"] = "Урон от взрывов повышен на 100%",
|
||||||
|
|
||||||
|
["class_lvl_1"] = "Новичок I",
|
||||||
|
["class_lvl_2"] = "Новичок II",
|
||||||
|
["class_lvl_3"] = "Новичок III",
|
||||||
|
["class_lvl_4"] = "Новичок IV",
|
||||||
|
["class_lvl_5"] = "Новичок V",
|
||||||
|
["class_lvl_6"] = "Средний I",
|
||||||
|
["class_lvl_7"] = "Средний II",
|
||||||
|
["class_lvl_8"] = "Средний III",
|
||||||
|
["class_lvl_9"] = "Средний IV",
|
||||||
|
["class_lvl_10"] = "Средний V",
|
||||||
|
["class_lvl_11"] = "Опытный I",
|
||||||
|
["class_lvl_12"] = "Опытный II",
|
||||||
|
["class_lvl_13"] = "Опытный III",
|
||||||
|
["class_lvl_14"] = "Опытный IV",
|
||||||
|
["class_lvl_15"] = "Опытный V",
|
||||||
|
["class_lvl_16"] = "Ветеран I",
|
||||||
|
["class_lvl_17"] = "Ветеран II",
|
||||||
|
["class_lvl_18"] = "Ветеран III",
|
||||||
|
["class_lvl_19"] = "Ветеран IV",
|
||||||
|
["class_lvl_20"] = "Ветеран V",
|
||||||
|
["class_lvl_21"] = "Эксперт",
|
||||||
|
|
||||||
|
["buymenu_main"] = "Закупка",
|
||||||
|
["buymenu_buy"] = "Купить",
|
||||||
|
}
|
||||||
@@ -0,0 +1,495 @@
|
|||||||
|
local meta = FindMetaTable("Player")
|
||||||
|
|
||||||
|
function meta:PlayVoiceLine(type, chance)
|
||||||
|
net.Start("SuR.VoiceLines")
|
||||||
|
net.WriteTable({self, type, chance})
|
||||||
|
net.Broadcast()
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:CheckHitbox(pos)
|
||||||
|
pos = pos or self:GetPos()
|
||||||
|
local tr = util.TraceHull({
|
||||||
|
start = pos,
|
||||||
|
endpos = pos,
|
||||||
|
filter = self,
|
||||||
|
mins = self:OBBMins(),
|
||||||
|
maxs = self:OBBMaxs(),
|
||||||
|
mask = MASK_PLAYERSOLID
|
||||||
|
})
|
||||||
|
return !tr.Hit
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:PlaceMark()
|
||||||
|
if not self.MarkDelay then
|
||||||
|
self.MarkDelay = 0
|
||||||
|
end
|
||||||
|
if !self:Alive() or self.MarkDelay > CurTime() then return end
|
||||||
|
|
||||||
|
local type = "point"
|
||||||
|
local tr = self:GetEyeTrace()
|
||||||
|
local data = tr.HitPos
|
||||||
|
local ent = tr.Entity
|
||||||
|
if IsValid(ent) and (ent:GetClass() == "sur_loot" or ent:GetClass() == "sur_resupply") then
|
||||||
|
type = "item"
|
||||||
|
data = ent
|
||||||
|
elseif IsValid(ent) and ent.IsZombie and ent:IsNPC() then
|
||||||
|
type = "enemy"
|
||||||
|
data = ent
|
||||||
|
end
|
||||||
|
|
||||||
|
net.Start("SuR.PointMark")
|
||||||
|
net.WriteString(type)
|
||||||
|
net.WriteEntity(self)
|
||||||
|
net.WriteTable({data})
|
||||||
|
net.Send(team.GetPlayers(self:Team()))
|
||||||
|
self.MarkDelay = CurTime()+10
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:AbilityKick()
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() then return end
|
||||||
|
|
||||||
|
local anim = "sur_kick"..math.random(1,3)
|
||||||
|
local _, ddelay = self:LookupSequence("sur_dropkick")
|
||||||
|
local delay = 0.4
|
||||||
|
if !self:OnGround() then
|
||||||
|
anim = "sur_dropkick"
|
||||||
|
delay = 0.3
|
||||||
|
end
|
||||||
|
local isdropkick = anim == "sur_dropkick"
|
||||||
|
|
||||||
|
self:SetSVAnimation(anim, true, true)
|
||||||
|
self:DropButtons()
|
||||||
|
|
||||||
|
timer.Simple(0.1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:EmitSound("bsmod/EvilDead/punch/punch_swing_2d_0"..math.random(1,4)..".wav", 70, math.random(80,120))
|
||||||
|
end)
|
||||||
|
|
||||||
|
if isdropkick then
|
||||||
|
timer.Simple(ddelay, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:Stun(true)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(delay, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
local tr = util.TraceLine({
|
||||||
|
start = self:GetShootPos(),
|
||||||
|
endpos = self:GetShootPos() + self:GetAimVector() * 64,
|
||||||
|
filter = self,
|
||||||
|
mask = MASK_SHOT_HULL
|
||||||
|
})
|
||||||
|
|
||||||
|
if !IsValid(tr.Entity) then
|
||||||
|
tr = util.TraceHull({
|
||||||
|
start = self:GetShootPos(),
|
||||||
|
endpos = self:GetShootPos() + self:GetAimVector() * 64,
|
||||||
|
filter = self,
|
||||||
|
mins = Vector( -10, -10, -8 ),
|
||||||
|
maxs = Vector( 10, 10, 8 ),
|
||||||
|
mask = MASK_SHOT_HULL
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local ent = tr.Entity
|
||||||
|
|
||||||
|
if IsValid(ent) then
|
||||||
|
local dmg = math.random(20,40)
|
||||||
|
local npc_vel = isdropkick and ent:IsNPC()
|
||||||
|
if isdropkick then
|
||||||
|
dmg = dmg*3
|
||||||
|
self:EmitSound("bsmod/EvilDead/punch/punch_impact_face_2d_0"..math.random(1,9)..".wav", 70, math.random(80,120))
|
||||||
|
else
|
||||||
|
self:EmitSound("bsmod/EvilDead/punch/punch_impact_body_2d_0"..math.random(1,6)..".wav", 70, math.random(80,120))
|
||||||
|
end
|
||||||
|
if self:GetPlayerClass() == "berserker" and self:GetLevelState() >= 2 then
|
||||||
|
ent:TakeDamage(dmg*4, self, self)
|
||||||
|
else
|
||||||
|
ent:TakeDamage(dmg, self, self)
|
||||||
|
end
|
||||||
|
self:ViewPunch(Angle(10,0,0))
|
||||||
|
local phys = ent:GetPhysicsObject()
|
||||||
|
if IsValid(phys) then
|
||||||
|
phys:SetVelocity(self:GetForward()*150+Vector(0,0,50))
|
||||||
|
end
|
||||||
|
if npc_vel then
|
||||||
|
ent:SetPos(ent:GetPos()+Vector(0,0,8))
|
||||||
|
ent:SetVelocity(self:GetForward()*1000)
|
||||||
|
end
|
||||||
|
if ent.IsVJBaseSNPC and (ent:Health() < 250 or isdropkick and ent:Health() < 1000) and not ent.LNR_Crawler then
|
||||||
|
ent.Flinching = true
|
||||||
|
ent:StopAttacks(true)
|
||||||
|
ent.PlayingAttackAnimation = false
|
||||||
|
local animTbl = ent.AnimTbl_Flinch
|
||||||
|
if HitgroupInfo != nil then animTbl = HitgroupInfo.Animation end
|
||||||
|
local anim = istable(animTbl) and VJ_PICK(animTbl) or animTbl
|
||||||
|
local animDur = ent.NextMoveAfterFlinchTime
|
||||||
|
if animDur == false and anim then
|
||||||
|
animDur = ent:DecideAnimationLength(anim, false, ent.FlinchAnimationDecreaseLengthAmount)
|
||||||
|
end
|
||||||
|
animDur = tonumber(animDur) or 0.1
|
||||||
|
if animDur <= 0 then
|
||||||
|
animDur = 0.1
|
||||||
|
end
|
||||||
|
if anim then
|
||||||
|
ent:VJ_ACT_PLAYACTIVITY(anim, true, animDur, false, 0, {SequenceDuration=animDur, PlayBackRateCalculated=true})
|
||||||
|
end
|
||||||
|
timer.Create("timer_act_flinching"..ent:EntIndex(), tonumber(animDur) or 0.1, 1, function() ent.Flinching = false end)
|
||||||
|
if isfunction(ent.CustomOnFlinch_AfterFlinch) then
|
||||||
|
ent:CustomOnFlinch_AfterFlinch(dmginfo, hitgroup)
|
||||||
|
end
|
||||||
|
ent.NextFlinchT = CurTime() + (tonumber(ent.NextFlinchTime) or 0)
|
||||||
|
end
|
||||||
|
if ent:IsPlayer() and ent:IsZombie() then
|
||||||
|
ent:Stun()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:AbilityGrenade()
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or self:GetNWInt('Grenades') <= 0 then return end
|
||||||
|
|
||||||
|
self:SetSVAnimation("sur_throw_grenade", true, true, true)
|
||||||
|
self:DropButtons()
|
||||||
|
self:SetNWInt('Grenades', self:GetNWInt('Grenades')-1)
|
||||||
|
|
||||||
|
timer.Simple(1.6, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
local grenade = ents.Create("obj_vj_grenade_sur")
|
||||||
|
grenade:SetPos(self:GetBonePosition(self:LookupBone("ValveBiped.Bip01_L_Hand")))
|
||||||
|
grenade:SetAngles(self:EyeAngles())
|
||||||
|
grenade:Spawn()
|
||||||
|
grenade:Activate()
|
||||||
|
grenade:GetPhysicsObject():ApplyForceCenter(self:GetAimVector() * 512 + Vector(0,0,128))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function meta:AbilityVault()
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or !self:GetNWBool('CanVault') then return end
|
||||||
|
|
||||||
|
self:SetSVAnimation("sur_vault1", true, true, true)
|
||||||
|
self:Freeze(true)
|
||||||
|
self:DropButtons()
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
timer.Create("Vaulting"..self:EntIndex(), 0.033, 60, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
i = i + 1
|
||||||
|
if i == 20 then
|
||||||
|
self:EmitSound("npc/footsteps/hardboot_generic"..math.random(1,6)..".wav", 70, 80)
|
||||||
|
end
|
||||||
|
if i == 60 then
|
||||||
|
self:SetPos(self:GetPos()+self:GetForward()*60)
|
||||||
|
self:Freeze(false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:AbilityHealing(teammate)
|
||||||
|
if IsValid(teammate) then
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or self:GetNWFloat("Bandages") <= 0 then return end
|
||||||
|
|
||||||
|
if !IsValid(self.LastPickupWeapon) then
|
||||||
|
self.LastPickupWeapon = self:GetActiveWeapon()
|
||||||
|
end
|
||||||
|
self:SetActiveWeapon(nil)
|
||||||
|
|
||||||
|
local _, dur = self:LookupSequence("sur_heal_friend")
|
||||||
|
self:SetSVAnimation("sur_heal_friend", true, true, true)
|
||||||
|
self:EmitSound("surrounded/player/healing.wav", 70)
|
||||||
|
self:PlayVoiceLine("cover", 10)
|
||||||
|
self:SetNWFloat("Bandages", self:GetNWFloat("Bandages")-1)
|
||||||
|
self:Freeze(true)
|
||||||
|
|
||||||
|
teammate:SetSVAnimation("idle_all_scared", false, true, false)
|
||||||
|
teammate:DropButtons()
|
||||||
|
|
||||||
|
timer.Simple(dur, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:Freeze(false)
|
||||||
|
if IsValid(self.LastPickupWeapon) then
|
||||||
|
local class = self.LastPickupWeapon:GetClass()
|
||||||
|
self:SelectWeapon(class)
|
||||||
|
self.LastPickupWeapon = nil
|
||||||
|
end
|
||||||
|
SuR:MessageOnClient(17, teammate:Nick(), self)
|
||||||
|
|
||||||
|
if !IsValid(teammate) then return end
|
||||||
|
|
||||||
|
SuR:MessageOnClient(16, self:Nick(), teammate)
|
||||||
|
if self:GetPlayerClass() == "medic" and self:GetLevelState() >= 2 then
|
||||||
|
teammate:SetHealth(teammate:GetMaxHealth())
|
||||||
|
else
|
||||||
|
teammate:SetHealth(math.Clamp(teammate:Health()+50, 1, 100))
|
||||||
|
end
|
||||||
|
teammate:PlayVoiceLine("thanks")
|
||||||
|
teammate:SetSVAnimation("")
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or !self:GetNWBool('CanHeal') or self:GetNWFloat("Bandages") <= 0 then return end
|
||||||
|
|
||||||
|
if !IsValid(self.LastPickupWeapon) then
|
||||||
|
self.LastPickupWeapon = self:GetActiveWeapon()
|
||||||
|
end
|
||||||
|
self:SetActiveWeapon(nil)
|
||||||
|
|
||||||
|
local _, dur = self:LookupSequence("sur_healing")
|
||||||
|
self:SetSVAnimation("sur_healing", true, true, true)
|
||||||
|
self:EmitSound("surrounded/player/healing.wav", 70)
|
||||||
|
self:PlayVoiceLine("cover", 10)
|
||||||
|
self:SetNWFloat("Bandages", self:GetNWFloat("Bandages")-1)
|
||||||
|
self:DropButtons()
|
||||||
|
|
||||||
|
timer.Simple(dur, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
if self:GetPlayerClass() == "medic" and self:GetLevelState() >= 2 then
|
||||||
|
self:SetHealth(self:GetMaxHealth())
|
||||||
|
else
|
||||||
|
self:SetHealth(math.Clamp(self:Health()+50, 1, 100))
|
||||||
|
end
|
||||||
|
if IsValid(self.LastPickupWeapon) then
|
||||||
|
local class = self.LastPickupWeapon:GetClass()
|
||||||
|
self:SelectWeapon(class)
|
||||||
|
self.LastPickupWeapon = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:AbilitySpray(teammate)
|
||||||
|
if IsValid(teammate) then
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or !teammate:GetNWBool("IsInfected") or self:GetNWFloat("Sprays") <= 0 then return end
|
||||||
|
|
||||||
|
if !IsValid(self.LastPickupWeapon) then
|
||||||
|
self.LastPickupWeapon = self:GetActiveWeapon()
|
||||||
|
end
|
||||||
|
self:SetActiveWeapon(nil)
|
||||||
|
|
||||||
|
local _, dur = self:LookupSequence("sur_heal_friend")
|
||||||
|
self:SetSVAnimation("sur_heal_friend", true, true, true)
|
||||||
|
self:EmitSound("surrounded/player/spray.mp3", 70)
|
||||||
|
self:PlayVoiceLine("cover", 10)
|
||||||
|
self:SetNWFloat("Sprays", self:GetNWFloat("Sprays")-1)
|
||||||
|
self:Freeze(true)
|
||||||
|
|
||||||
|
teammate:SetSVAnimation("idle_all_scared", false, true, false)
|
||||||
|
teammate:DropButtons()
|
||||||
|
|
||||||
|
timer.Simple(dur, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
self:Freeze(false)
|
||||||
|
if IsValid(self.LastPickupWeapon) then
|
||||||
|
local class = self.LastPickupWeapon:GetClass()
|
||||||
|
self:SelectWeapon(class)
|
||||||
|
self.LastPickupWeapon = nil
|
||||||
|
end
|
||||||
|
SuR:MessageOnClient(17, teammate:Nick(), self)
|
||||||
|
|
||||||
|
if !IsValid(teammate) then return end
|
||||||
|
|
||||||
|
teammate:SetSVAnimation("")
|
||||||
|
teammate:PlayVoiceLine("thanks")
|
||||||
|
SuR:MessageOnClient(16, self:Nick(), teammate)
|
||||||
|
SuR:StopInfection(teammate)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() or !self:GetNWBool("IsInfected") or self:GetNWFloat("Sprays") <= 0 then return end
|
||||||
|
|
||||||
|
if !IsValid(self.LastPickupWeapon) then
|
||||||
|
self.LastPickupWeapon = self:GetActiveWeapon()
|
||||||
|
end
|
||||||
|
self:SetActiveWeapon(nil)
|
||||||
|
|
||||||
|
local _, dur = self:LookupSequence("sur_healing")
|
||||||
|
self:SetSVAnimation("sur_healing", true, true, true)
|
||||||
|
self:EmitSound("surrounded/player/spray.mp3", 70)
|
||||||
|
self:PlayVoiceLine("cover", 10)
|
||||||
|
self:SetNWFloat("Sprays", self:GetNWFloat("Sprays")-1)
|
||||||
|
self:DropButtons()
|
||||||
|
|
||||||
|
timer.Simple(dur, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
SuR:StopInfection(self)
|
||||||
|
if IsValid(self.LastPickupWeapon) then
|
||||||
|
local class = self.LastPickupWeapon:GetClass()
|
||||||
|
self:SelectWeapon(class)
|
||||||
|
self.LastPickupWeapon = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:Stun(nofall, count)
|
||||||
|
if !self:Alive() or self:IsDowned() or self:IsStunned() or self:Health() > 250 or self.ExecutingTarget or self:GetPlayerClass() == "demoman" and self:GetLevelState() >= 1 then return end
|
||||||
|
|
||||||
|
if self:IsZombie() then
|
||||||
|
local anim = "shove_backwards_10"
|
||||||
|
local _, dur = self:LookupSequence(anim)
|
||||||
|
self:SetSVAnimation(anim, false, true, true)
|
||||||
|
self:Freeze(true)
|
||||||
|
self:EmitSound("physics/body/body_medium_impact_hard"..math.random(1,6)..".wav", 70, 90)
|
||||||
|
|
||||||
|
timer.Create("StunAnim"..self:EntIndex(), dur, 1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
if anim == self:GetNWString('SVAnim') then
|
||||||
|
self:SetSVAnimation(sanim, true, true)
|
||||||
|
end
|
||||||
|
local _, dur = self:LookupSequence(sanim)
|
||||||
|
timer.Create("StunAnim"..self:EntIndex(), dur, 1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
|
||||||
|
self:Freeze(false)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
if not count then
|
||||||
|
count = 0
|
||||||
|
end
|
||||||
|
self.FallPressCount = 0
|
||||||
|
self.FallPressMax = count
|
||||||
|
if nofall then
|
||||||
|
if count > 0 then
|
||||||
|
self:SetSVAnimation("sur_fall_idle", false, true)
|
||||||
|
else
|
||||||
|
self:SetSVAnimation("sur_fall_standup", true, true)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local anim = "sur_fall_down"
|
||||||
|
local _, dur = self:LookupSequence(anim)
|
||||||
|
self:SetSVAnimation(anim, false, true)
|
||||||
|
self:EmitSound("physics/body/body_medium_impact_hard"..math.random(1,6)..".wav", 70, 90)
|
||||||
|
timer.Create("StunAnim"..self:EntIndex(), dur, 1, function()
|
||||||
|
if !IsValid(self) then return end
|
||||||
|
if count > 0 then
|
||||||
|
self:SetSVAnimation("sur_fall_idle", false, true)
|
||||||
|
else
|
||||||
|
self:SetSVAnimation("sur_fall_standup", true, true)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("PlayerButtonDown", "SuR_ButtonHookQTEStun", function(ply, but)
|
||||||
|
if ply:IsStunned(true) and but == KEY_SPACE and ply:OnGround() then
|
||||||
|
if ply.FallPressCount < ply.FallPressMax then
|
||||||
|
if ply:GetPlayerClass() == "survivor" and ply:GetLevelState() >= 2 then
|
||||||
|
ply.FallPressCount = ply.FallPressCount + 2
|
||||||
|
else
|
||||||
|
ply.FallPressCount = ply.FallPressCount + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ply:SetSVAnimation("sur_fall_standup", true, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("OnPlayerJump", "SuR.BlockJump", function(ply, speed)
|
||||||
|
if ply:IsDowned() or ply:IsStunned() then
|
||||||
|
ply:SetVelocity(-Vector(0,0,speed))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.SelectPlayerModel", function(len, ply)
|
||||||
|
local model = net.ReadString()
|
||||||
|
if #SuR.Config.Allowed_PlayerModels > 0 then
|
||||||
|
if file.Exists(model, "GAME") and table.HasValue(player_manager.AllValidModels(), model) and table.HasValue(SuR.Config.Allowed_PlayerModels, model) and (not SuR.Wave_Started or !ply:Alive()) then
|
||||||
|
ply:SetNWString('SuR_PlayerModel', model)
|
||||||
|
if not ply:Alive() then
|
||||||
|
ply:SetModel(model)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if file.Exists(model, "GAME") and table.HasValue(player_manager.AllValidModels(), model) and not table.HasValue(SuR.Config.Blocked_PlayerModels, model) and (not SuR.Wave_Started or !ply:Alive()) then
|
||||||
|
ply:SetNWString('SuR_PlayerModel', model)
|
||||||
|
if not ply:Alive() then
|
||||||
|
ply:SetModel(model)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.ChooseVoicePack", function(len, ply)
|
||||||
|
local voice = net.ReadString()
|
||||||
|
if istable(SuR.Config.VoicePacks[voice]) and (not SuR.Wave_Started or !ply:Alive()) then
|
||||||
|
ply:SetNWString('VoicePack', voice)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.RadioSupport", function(len, ply)
|
||||||
|
local fl = net.ReadFloat()
|
||||||
|
if ply:GetNWFloat('CanCallSupport') > 0 then
|
||||||
|
ply:SetNWFloat('CanCallSupport', ply:GetNWFloat('CanCallSupport')-1)
|
||||||
|
SuR:CallSupport(ply, fl)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.ChooseStartWeapon", function(len, ply)
|
||||||
|
local str = net.ReadString()
|
||||||
|
if (table.HasValue(SuR.Config.TierWeapons["Tier1"], str) or table.HasValue(SuR.Config.TierWeapons["Tier2"], str) and ply:GetNWBool("ExtendedStartWeapons")) and (not SuR.Wave_Started or !ply:Alive()) then
|
||||||
|
ply:SetNWString('StartWeapon', str)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function create_item(self, id)
|
||||||
|
local tr = util.TraceLine( {
|
||||||
|
start = self:EyePos(),
|
||||||
|
endpos = self:EyePos() + self:GetAimVector() * 50,
|
||||||
|
filter = self,
|
||||||
|
mask = MASK_SOLID,
|
||||||
|
})
|
||||||
|
|
||||||
|
local ent = ents.Create("sur_loot")
|
||||||
|
ent.LootType = id
|
||||||
|
ent:SetPos(tr.HitPos)
|
||||||
|
ent:Spawn()
|
||||||
|
ent.IsLoot = true
|
||||||
|
end
|
||||||
|
|
||||||
|
concommand.Add("sur_dropweapon", function(ply, cmd, args)
|
||||||
|
if not args[1] or !ply:Alive() or ply:IsLockedAbilities() or ply:IsZombie() then return end
|
||||||
|
|
||||||
|
local arg = args[1]
|
||||||
|
BroadcastLua([[Entity(]]..ply:EntIndex()..[[):AnimRestartGesture(6, ACT_GMOD_GESTURE_ITEM_DROP, true)]])
|
||||||
|
|
||||||
|
local type = "weapon"
|
||||||
|
if arg == "bandage" or arg == "antidote" or arg == "selfrevive" or arg == "radio" then
|
||||||
|
type = arg
|
||||||
|
end
|
||||||
|
|
||||||
|
timer.Simple(0.2, function()
|
||||||
|
if !IsValid(ply) then return end
|
||||||
|
|
||||||
|
if type == "weapon" then
|
||||||
|
ply:CreateDroppedWeapon(arg)
|
||||||
|
if arg == ply:GetNWString('MeleeWeapon') then
|
||||||
|
ply:Give(SuR.Config.EmptyWeapon)
|
||||||
|
ply:SelectWeapon(SuR.Config.EmptyWeapon)
|
||||||
|
ply:SetNWString('MeleeWeapon', SuR.Config.EmptyWeapon)
|
||||||
|
end
|
||||||
|
elseif type == "bandage" and ply:GetNWFloat('Bandages') > 2 then
|
||||||
|
create_item(ply, 8)
|
||||||
|
ply:SetNWFloat('Bandages', ply:GetNWFloat('Bandages')-3)
|
||||||
|
elseif type == "antidote" and ply:GetNWFloat('Sprays') > 0 then
|
||||||
|
create_item(ply, 7)
|
||||||
|
ply:SetNWFloat('Sprays', ply:GetNWFloat('Sprays')-1)
|
||||||
|
elseif type == "selfrevive" and ply:GetNWFloat('SelfRevive') > 0 then
|
||||||
|
create_item(ply, 12)
|
||||||
|
ply:SetNWFloat('SelfRevive', ply:GetNWFloat('SelfRevive')-1)
|
||||||
|
elseif type == "radio" and ply:GetNWFloat('CanCallSupport') > 0 then
|
||||||
|
create_item(ply, 6)
|
||||||
|
ply:SetNWFloat('CanCallSupport', ply:GetNWFloat('CanCallSupport')-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
ply:EmitSound("npc/vort/claw_swing"..math.random(1,2)..".wav", 60, math.random(80,100))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
net.Receive("SuR.BuyMenu", function(len, ply)
|
||||||
|
local item = net.ReadString()
|
||||||
|
if ply:GetNWFloat('CanCallSupport') <= 0 then return end
|
||||||
|
|
||||||
|
local price = 0
|
||||||
|
if table.HasValue(SuR.Config.TierWeapons["Tier2"], item) then price = SuR.Config.Tier2_Price end
|
||||||
|
if table.HasValue(SuR.Config.TierWeapons["Tier3"], item) then price = SuR.Config.Tier3_Price end
|
||||||
|
if table.HasValue(SuR.Config.TierWeapons["Tier4"], item) then price = SuR.Config.Tier4_Price end
|
||||||
|
if table.HasValue(SuR.Config.TierWeapons["Tier5"], item) then price = SuR.Config.Tier5_Price end
|
||||||
|
if price == 0 or ply:GetNWInt('Money') < price then return end
|
||||||
|
|
||||||
|
ply:SetNWFloat('CanCallSupport', ply:GetNWFloat('CanCallSupport')-1)
|
||||||
|
ply:SetNWInt('Money', ply:GetNWInt('Money')-price)
|
||||||
|
ply:Give(item)
|
||||||
|
end)
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
local meta = FindMetaTable("Player")
|
||||||
|
local start_xp = SuR.Config.Start_Level_XP
|
||||||
|
local lvl_mult = SuR.Config.Level_Progress_Mult
|
||||||
|
|
||||||
|
file.CreateDir("surrounded/level/")
|
||||||
|
|
||||||
|
function meta:SetPlayerClass(id)
|
||||||
|
id = id or "survivor"
|
||||||
|
self:SetNWString("PlayerClass", id)
|
||||||
|
|
||||||
|
local lvl, xp = unpack(self.LevelTab[id])
|
||||||
|
local class = self:GetPlayerClass()
|
||||||
|
self:SetLevel(lvl)
|
||||||
|
self:AddXP(xp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:SetLevel(lvl)
|
||||||
|
if !isnumber(lvl) or lvl < 1 then return end
|
||||||
|
|
||||||
|
self:SetNWFloat("PlayerLevel", math.min(lvl, 21))
|
||||||
|
self:SetNWFloat("PlayerXP", 0)
|
||||||
|
|
||||||
|
local class = self:GetPlayerClass()
|
||||||
|
local lvl, cur_xp = self:GetLevel()
|
||||||
|
self.LevelTab[class] = {lvl, cur_xp}
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:AddXP(num)
|
||||||
|
if !isnumber(num) or self:GetLevel() >= 21 then return end
|
||||||
|
|
||||||
|
local lvl, cur_xp = self:GetLevel()
|
||||||
|
self:SetNWFloat("PlayerXP", math.max(cur_xp+num, 0))
|
||||||
|
|
||||||
|
local need = self:GetXPToLevel()
|
||||||
|
if need == 0 then
|
||||||
|
self:SetLevel(lvl+1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local class = self:GetPlayerClass()
|
||||||
|
local lvl, cur_xp = self:GetLevel()
|
||||||
|
self.LevelTab[class] = {lvl, cur_xp}
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:LoadLevelProgress()
|
||||||
|
local id = self:SteamID64()
|
||||||
|
local f = file.Read("surrounded/level/"..id..".json", "DATA")
|
||||||
|
local tab = {
|
||||||
|
["survivor"] = {1, 0},
|
||||||
|
["scout"] = {1, 0},
|
||||||
|
["medic"] = {1, 0},
|
||||||
|
["engineer"] = {1, 0},
|
||||||
|
["marksman"] = {1, 0},
|
||||||
|
["berserker"] = {1, 0},
|
||||||
|
["demoman"] = {1, 0},
|
||||||
|
cur_class = "survivor"
|
||||||
|
}
|
||||||
|
if isstring(f) then
|
||||||
|
f = util.JSONToTable(f)
|
||||||
|
tab = f
|
||||||
|
end
|
||||||
|
self.LevelTab = tab
|
||||||
|
self:SetPlayerClass(tab.cur_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
function meta:SaveLevelProgress()
|
||||||
|
local id = self:SteamID64()
|
||||||
|
local lvl, cur_xp = self:GetLevel()
|
||||||
|
local tab = {}
|
||||||
|
for k, v in pairs(self.LevelTab) do
|
||||||
|
tab[k] = v
|
||||||
|
end
|
||||||
|
tab.cur_class = self:GetPlayerClass()
|
||||||
|
|
||||||
|
file.Write("surrounded/level/"..id..".json", util.TableToJSON(tab, true))
|
||||||
|
end
|
||||||
|
|
||||||
|
hook.Add("PlayerDisconnected", "SuR.SaveProgress", function(ply)
|
||||||
|
ply:SaveLevelProgress()
|
||||||
|
end)
|
||||||
|
|
||||||
|
hook.Add("ShutDown", "SuR.SaveProgress", function()
|
||||||
|
for _, ply in ipairs(player.GetAll()) do
|
||||||
|
ply:SaveLevelProgress()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
concommand.Add("sur_selectclass", function(ply, cmd, args)
|
||||||
|
local str = args[1]
|
||||||
|
if not str or ply:Alive() then return end
|
||||||
|
if not SuR.Config.ClassIcons[str] then return end
|
||||||
|
|
||||||
|
ply:SetPlayerClass(str)
|
||||||
|
end)
|
||||||
|
|
||||||
|
net.Receive("SuR.OpenClassMenu", function(len, ply)
|
||||||
|
net.Start("SuR.OpenClassMenu")
|
||||||
|
net.WriteTable(ply.LevelTab)
|
||||||
|
net.Send(ply)
|
||||||
|
end)
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user