commit e71aa5716820159818101c4be3e7e13294d983ef Author: Refosel Date: Tue Apr 14 20:55:58 2026 +0300 Залив diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/backgrounds/ashevile.png b/garrysmod/addons/surrounded/gamemodes/surrounded/backgrounds/ashevile.png new file mode 100644 index 0000000..ab6be12 Binary files /dev/null and b/garrysmod/addons/surrounded/gamemodes/surrounded/backgrounds/ashevile.png differ diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/base.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/base.lua new file mode 100644 index 0000000..0333cfb --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/base.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/dof_node.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/dof_node.lua new file mode 100644 index 0000000..38604d1 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/dof_node.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/tooltracer.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/tooltracer.lua new file mode 100644 index 0000000..53ee1e9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/effects/tooltracer.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/aoc_spawnpoint.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/aoc_spawnpoint.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/aoc_spawnpoint.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/cl_init.lua new file mode 100644 index 0000000..7b2452c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/cl_init.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/init.lua new file mode 100644 index 0000000..f2c2295 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/init.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/schedules.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/schedules.lua new file mode 100644 index 0000000..96ca880 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/schedules.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/shared.lua new file mode 100644 index 0000000..cdcf8b9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/tasks.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/tasks.lua new file mode 100644 index 0000000..091bdb9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_ai/tasks.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_anim.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_anim.lua new file mode 100644 index 0000000..e6d4a1c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_anim.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_brush.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_brush.lua new file mode 100644 index 0000000..4eb4274 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_brush.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/cl_init.lua new file mode 100644 index 0000000..41327c7 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/cl_init.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/init.lua new file mode 100644 index 0000000..5eb772a --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/init.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/outputs.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/outputs.lua new file mode 100644 index 0000000..35cd4c0 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/outputs.lua @@ -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("",",,,,") +-- 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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/shared.lua new file mode 100644 index 0000000..a31a702 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_entity/shared.lua @@ -0,0 +1,6 @@ + +ENT.Base = "base_entity" +ENT.Type = "anim" + +ENT.Spawnable = false +ENT.AdminOnly = false diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_filter.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_filter.lua new file mode 100644 index 0000000..f4a226b --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_filter.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_gmodentity.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_gmodentity.lua new file mode 100644 index 0000000..c1fedde --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_gmodentity.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/shared.lua new file mode 100644 index 0000000..8340126 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/sv_nextbot.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/sv_nextbot.lua new file mode 100644 index 0000000..5ea6116 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_nextbot/sv_nextbot.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_point.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_point.lua new file mode 100644 index 0000000..1bf1f8c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/base_point.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_blue.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_blue.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_blue.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_red.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_red.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/diprip_start_team_red.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/dys_spawn_point.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/dys_spawn_point.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/dys_spawn_point.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/env_skypaint.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/env_skypaint.lua new file mode 100644 index 0000000..bfabe96 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/env_skypaint.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_hands.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_hands.lua new file mode 100644 index 0000000..7c858e1 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_hands.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_player_start.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_player_start.lua new file mode 100644 index 0000000..8c4641c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/gmod_player_start.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_allies.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_allies.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_allies.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_axis.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_axis.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_axis.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_blue.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_blue.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_blue.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_coop.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_coop.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_coop.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_counterterrorist.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_counterterrorist.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_counterterrorist.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_deathmatch.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_deathmatch.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_deathmatch.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_desperado.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_desperado.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_desperado.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_fof.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_fof.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_fof.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_human.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_human.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_human.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_knight.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_knight.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_knight.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_pirate.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_pirate.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_pirate.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_red.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_red.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_red.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_survivor.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_survivor.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_survivor.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_terrorist.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_terrorist.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_terrorist.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_vigilante.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_vigilante.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_vigilante.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_viking.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_viking.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_viking.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombie.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombie.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombie.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombiemaster.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombiemaster.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_player_zombiemaster.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_spawnpoint.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_spawnpoint.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_spawnpoint.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_position.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_position.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_position.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_rescue.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_rescue.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/info_survivor_rescue.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ins_spawnpoint.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ins_spawnpoint.lua new file mode 100644 index 0000000..ff5d67c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ins_spawnpoint.lua @@ -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" diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/lua_run.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/lua_run.lua new file mode 100644 index 0000000..18735ce --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/lua_run.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/npc_tf2_ghost.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/npc_tf2_ghost.lua new file mode 100644 index 0000000..5d7a29a --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/npc_tf2_ghost.lua @@ -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" +} ) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/obj_vj_grenade_sur.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/obj_vj_grenade_sur.lua new file mode 100644 index 0000000..52169de --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/obj_vj_grenade_sur.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/prop_effect.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/prop_effect.lua new file mode 100644 index 0000000..86152a3 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/prop_effect.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ragdoll_motion.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ragdoll_motion.lua new file mode 100644 index 0000000..fc4d241 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/ragdoll_motion.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/cl_init.lua new file mode 100644 index 0000000..2a91bc2 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/cl_init.lua @@ -0,0 +1,4 @@ +include('shared.lua') + +function ENT:Draw() self:DrawModel() end +function ENT:DrawTranslucent() self:Draw() end \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/init.lua new file mode 100644 index 0000000..faf48f2 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/init.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/shared.lua new file mode 100644 index 0000000..97da133 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_anim/shared.lua @@ -0,0 +1,4 @@ +ENT.Base = "base_anim" +ENT.Type = "anim" +ENT.RenderGroup = RENDERGROUP_BOTH +ENT.AutomaticFrameAdvance = true \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/init.lua new file mode 100644 index 0000000..c930145 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/init.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/shared.lua new file mode 100644 index 0000000..6317f42 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_barricade/shared.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/init.lua new file mode 100644 index 0000000..a18827f --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/init.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/shared.lua new file mode 100644 index 0000000..db67001 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_helo/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/init.lua new file mode 100644 index 0000000..2d351a5 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/init.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/shared.lua new file mode 100644 index 0000000..0fcf52c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_exfil_point/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_gas_zone.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_gas_zone.lua new file mode 100644 index 0000000..1d62c15 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_gas_zone.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_generator/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_generator/shared.lua new file mode 100644 index 0000000..caa5792 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_generator/shared.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_landmine.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_landmine.lua new file mode 100644 index 0000000..5fd2876 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_landmine.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_loot/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_loot/shared.lua new file mode 100644 index 0000000..e9cccb4 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_loot/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24/shared.lua new file mode 100644 index 0000000..fbfad26 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24_rocket/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24_rocket/shared.lua new file mode 100644 index 0000000..7b1c4b4 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_mi24_rocket/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/cl_init.lua new file mode 100644 index 0000000..926d058 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/cl_init.lua @@ -0,0 +1,5 @@ +include("shared.lua") + +function ENT:DrawTranslucent(flags) + self:DrawModel(flags) +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/init.lua new file mode 100644 index 0000000..8f6d403 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/init.lua @@ -0,0 +1,4 @@ +AddCSLuaFile("cl_init.lua") +AddCSLuaFile("shared.lua") + +include("shared.lua") \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/shared.lua new file mode 100644 index 0000000..44c707d --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_npc_infil/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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_resupply/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_resupply/shared.lua new file mode 100644 index 0000000..0692b64 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_resupply/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/init.lua new file mode 100644 index 0000000..5348c87 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/init.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/shared.lua new file mode 100644 index 0000000..c8e61c2 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_support_npc/shared.lua @@ -0,0 +1,3 @@ +ENT.Base = "npc_vj_human_base" +ENT.Type = "ai" +ENT.PrintName = "Human" \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_zone.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_zone.lua new file mode 100644 index 0000000..9dd29c6 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/entities/sur_zone.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_claws.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_claws.lua new file mode 100644 index 0000000..f768604 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_claws.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_fuel.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_fuel.lua new file mode 100644 index 0000000..7f66256 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_fuel.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_hammer.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_hammer.lua new file mode 100644 index 0000000..d86ad88 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_hammer.lua @@ -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 \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_mine.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_mine.lua new file mode 100644 index 0000000..ee5958e --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/sur_mine.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/ai_translations.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/ai_translations.lua new file mode 100644 index 0000000..36c91d5 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/ai_translations.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/cl_init.lua new file mode 100644 index 0000000..84c0df9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/cl_init.lua @@ -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 = "" + local text_color = "" + + str = "" + if ( self.Author != "" ) then str = str .. title_color .. "Author:\t" .. text_color .. self.Author .. "\n" end + if ( self.Contact != "" ) then str = str .. title_color .. "Contact:\t" .. text_color .. self.Contact .. "\n\n" end + if ( self.Purpose != "" ) then str = str .. title_color .. "Purpose:\n" .. text_color .. self.Purpose .. "\n\n" end + if ( self.Instructions != "" ) then str = str .. title_color .. "Instructions:\n" .. text_color .. self.Instructions .. "\n" end + str = str .. "" + + 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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/init.lua new file mode 100644 index 0000000..c716b53 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/init.lua @@ -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" ) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/sh_anim.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/sh_anim.lua new file mode 100644 index 0000000..d22e2ed --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/sh_anim.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/shared.lua new file mode 100644 index 0000000..750b446 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/entities/weapons/weapon_base/shared.lua @@ -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 diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/cl_init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/cl_init.lua new file mode 100644 index 0000000..1ed4d22 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/cl_init.lua @@ -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") \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_abilities.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_abilities.lua new file mode 100644 index 0000000..eeed7ad --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_abilities.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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_buymenu.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_buymenu.lua new file mode 100644 index 0000000..7d268a9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_buymenu.lua @@ -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 + diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_cutscenes.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_cutscenes.lua new file mode 100644 index 0000000..22711c9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_cutscenes.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_hud.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_hud.lua new file mode 100644 index 0000000..f63a273 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_hud.lua @@ -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) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_menu.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_menu.lua new file mode 100644 index 0000000..04c3182 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_menu.lua @@ -0,0 +1,1134 @@ +local radio_bgMat = Material("surrounded/radio_bg.png") +local radioMat = Material("surrounded/radio.png") +local bgMat = Material("surrounded/ammo_bg.png") +local bg = Material('surrounded/vgui_bg.png') +local bg2 = Material('surrounded/vgui_bg2.png') +local voiceMat = Material('surrounded/voice.png') +local def_bg_mat = Material("surrounded/tips/default.png", "noclamp smooth") +local lang = SuR.Language + +local buttons = { + lang["radio_1"], + lang["radio_2"], + lang["radio_3"], + lang["radio_4"], + lang["radio_5"], + lang["radio_6"], + lang["radio_7"], +} + +function SuR:OpenRadioMenu() + local ply = LocalPlayer() + if ply:GetNWFloat('CanCallSupport') <= 0 or ply:IsLockedAbilities() then return end + + surface.PlaySound("surrounded/other/radio/radiomenu_0"..math.random(1,3)..".mp3") + + local df = vgui.Create("DFrame") + df:SetSize(We(600), He(420)) + df:SetPos(We(50),He(200)) + df:SetTitle("") + df:ShowCloseButton(false) + df:MakePopup() + + local radionum = 0 + local force = false + function df:Paint(w, h) + surface.SetMaterial(radio_bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + if force then + radionum = math.min(radionum+FrameTime()/0.01, 20) + if radionum == 20 then + force = false + end + else + radionum = math.max(radionum-FrameTime()/0.01, -20) + if radionum == -20 then + force = true + end + end + + surface.SetMaterial(radioMat) + surface.SetDrawColor(255,255,255) + surface.DrawTexturedRectRotated(We(60), He(45), We(72), He(72), radionum) + + draw.SimpleText(lang["radio_main"], "SuR_MediumFont1", We(120), He(32), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + + local db = vgui.Create("DButton", df) + db:SetSize(We(32), He(32)) + db:SetPos(We(375),He(30)) + 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() + df:Remove() + end + + for k, v in ipairs(buttons) do + local db = vgui.Create("DButton", df) + db:SetSize(We(320), He(40)) + db:SetPos(We(25),He(60)+(k*He(45))) + db:SetText("") + function db:OnCursorEntered() + surface.PlaySound("surrounded/tick.wav") + end + function db:DoClick() + if k == 6 and (#SuR.Config.Exfil_Points == 0 or SuR.Config.Objective_Mode) then + chat.AddText(Color(255,255,255), string.format(SuR.Language["radio_6_disable"], SuR.Config.Exfil_Wave)) + chat.PlaySound() + df:Remove() + return + elseif k == 6 and (SuR.Data["ExfilWave"] or not SuR.Data["WaveState"] or SuR.Data["Wave"] < SuR.Config.Exfil_Wave) then + chat.AddText(Color(255,255,255), string.format(SuR.Language["radio_6_warn"], SuR.Config.Exfil_Wave)) + chat.PlaySound() + df:Remove() + return + end + surface.PlaySound("surrounded/other/radio/radiosend.mp3") + net.Start("SuR.RadioSupport") + net.WriteFloat(k) + net.SendToServer() + df:Remove() + end + function db:Paint(w, h) + surface.SetMaterial(bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + if db:IsHovered() then + draw.SimpleText("- "..v, "SuR_SmallFont1", We(25), h/2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + else + draw.SimpleText(v, "SuR_SmallFont1", We(25), h/2, Color(150,150,150), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + end + end +end + +CreateConVar("sur_viewmod", 2, {FCVAR_ARCHIVE, FCVAR_USERINFO}, "", 0, 2) +CreateConVar("sur_viewmod_cutscene", 1, {FCVAR_ARCHIVE, FCVAR_USERINFO}, "", 0, 1) +CreateConVar("sur_viewmod_deathanims", 0, {FCVAR_ARCHIVE, FCVAR_USERINFO}, "", 0, 1) +CreateConVar("sur_music_volume", 1, FCVAR_ARCHIVE, "", 0.00, 2.00) +CreateConVar("sur_disable_hud", 0, FCVAR_ARCHIVE, "", 0, 1) +CreateConVar("sur_disable_hints", 0, FCVAR_ARCHIVE, "", 0, 1) +function SuR:OpenSettingsMenu() + local df = vgui.Create("DFrame") + df:SetSize(We(400), 210) + 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["settings_main"], "SuR_SmallFont1", We(20), He(10), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + + local db = vgui.Create("DButton", df) + db:SetSize(We(32), He(32)) + db:SetPos(We(345),He(10)) + 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 DermaCheckbox = df:Add("DCheckBoxLabel") + DermaCheckbox:SetText(lang["settings_zc"]) + DermaCheckbox:SetConVar("sur_disable_hud") + DermaCheckbox:Dock(TOP) + DermaCheckbox:DockMargin(We(20), 5, 0, 10) + DermaCheckbox:SizeToContents() + + local DermaCheckbox = df:Add("DCheckBoxLabel") + DermaCheckbox:SetText(lang["settings_dh"]) + DermaCheckbox:SetConVar("sur_disable_hints") + DermaCheckbox:Dock(TOP) + DermaCheckbox:DockMargin(We(20), 0, 0, 10) + DermaCheckbox:SizeToContents() + + local DermaCheckbox = df:Add("DCheckBoxLabel") + DermaCheckbox:SetText(lang["settings_vmc"]) + DermaCheckbox:SetConVar("sur_viewmod_cutscene") + DermaCheckbox:Dock(TOP) + DermaCheckbox:DockMargin(We(20), 0, 0, 10) + DermaCheckbox:SizeToContents() + + local DermaCheckbox = df:Add("DCheckBoxLabel") + DermaCheckbox:SetText(lang["settings_vmd"]) + DermaCheckbox:SetConVar("sur_viewmod_deathanims") + DermaCheckbox:Dock(TOP) + DermaCheckbox:DockMargin(We(20), 0, 0, 10) + DermaCheckbox:SizeToContents() + + local DermaNumSlider = df:Add("DNumSlider") + DermaNumSlider:SetText(lang["settings_vm"]) + DermaNumSlider:SetMin(0) + DermaNumSlider:SetMax(2) + DermaNumSlider:SetDecimals(0) + DermaNumSlider:SetConVar("sur_viewmod") + DermaNumSlider:DockMargin(We(20), 0, 0, 0) + DermaNumSlider:Dock(TOP) + DermaNumSlider:SizeToContents() + + local DermaNumSlider = df:Add("DNumSlider") + DermaNumSlider:SetText(lang["settings_mv"]) + DermaNumSlider:SetMin(0) + DermaNumSlider:SetMax(2) + DermaNumSlider:SetDecimals(2) + DermaNumSlider:SetConVar("sur_music_volume") + DermaNumSlider:DockMargin(We(20), 0, 0, 0) + DermaNumSlider:Dock(TOP) + DermaNumSlider:SizeToContents() +end + +function SuR:OpenAdminMenu() + local ply = LocalPlayer() + if !ply:IsAdmin() then return end + + local df = vgui.Create("DFrame") + df:SetSize(We(400), He(180)) + 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["adminsettings_main"], "SuR_SmallFont1", We(10), He(10), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + + local db = vgui.Create("DButton", df) + db:SetSize(We(32), He(32)) + db:SetPos(We(345),He(10)) + 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 DermaButton = df:Add("DButton") + DermaButton:SetText(lang["adminsettings_startgame"]) + DermaButton:Dock(TOP) + DermaButton:SetSize(0, He(30)) + DermaButton:DockMargin(0, He(20), 0, He(10)) + DermaButton.DoClick = function() + RunConsoleCommand("sur_startgame") + df:Remove() + end + + local DermaButton = df:Add("DButton") + DermaButton:SetText(lang["adminsettings_skipwave"]) + DermaButton:Dock(TOP) + DermaButton:SetSize(0, He(30)) + DermaButton:DockMargin(0, 0, 0, He(10)) + DermaButton.DoClick = function() + RunConsoleCommand("sur_skipwave") + df:Remove() + end + + local DermaButton = df:Add("DButton") + DermaButton:SetText(lang["adminsettings_spawnmenu"]) + DermaButton:Dock(TOP) + DermaButton:SetSize(0, He(30)) + DermaButton:DockMargin(0, 0, 0, He(10)) + DermaButton.DoClick = function() + RunConsoleCommand("sur_spawnmenu") + df:Remove() + end +end + +function SuR:OpenPMMenu() + local ply = LocalPlayer() + local modcur = ply:GetModel() + local selectedweapon = ply:GetNWString('StartWeapon') + local selectedvoice = ply:GetNWString('VoicePack', 'English 1') + + local DermaPanel = vgui.Create("DFrame") + DermaPanel:SetSize(We(1100), He(730)) + DermaPanel:Center() + DermaPanel:SetTitle("") + DermaPanel:SetDraggable(false) + DermaPanel:MakePopup() + DermaPanel:ShowCloseButton(false) + + local sp = vgui.Create("DScrollPanel", DermaPanel) + sp:SetSize(We(320), He(250)) + sp:SetPos(We(50),He(125)) + + local List = vgui.Create("DIconLayout", sp) + List:Dock(FILL) + List:SetSpaceY(He(5)) + List:SetSpaceX(We(5)) + + local icon = vgui.Create("DModelPanel", DermaPanel) + icon:SetSize(We(160),He(250)) + icon:SetPos(We(390),He(125)) + icon:SetModel(modcur) + local eyepos = icon.Entity:GetBonePosition(icon.Entity:LookupBone("ValveBiped.Bip01_Head1")) + icon:SetCamPos(eyepos-Vector(40,0,20)) + icon:SetLookAt(eyepos-Vector(0,0,25)) + + for k, v in pairs(player_manager.AllValidModels()) do + if table.HasValue(SuR.Config.Blocked_PlayerModels, v) then continue end + if #SuR.Config.Allowed_PlayerModels > 0 and not table.HasValue(SuR.Config.Allowed_PlayerModels, v) then continue end + + local SpawnI = List:Add("SpawnIcon") + SpawnI:SetSize(We(72), He(72)) + SpawnI:SetModel(v) + SpawnI:SetTooltip(k) + SpawnI.DoClick = function(self) + modcur = v + surface.PlaySound("weapons/357/357_spin1.wav") + end + end + + DermaPanel.Paint = function(self, w, h) + surface.SetMaterial(bg) + surface.SetDrawColor(0,0,0,240) + surface.DrawTexturedRect(0,0,w,h) + + surface.SetDrawColor(200,200,200,200) + surface.DrawOutlinedRect(We(390),He(123),We(160),He(254),2) + + surface.SetDrawColor(200,200,200,200) + surface.DrawOutlinedRect(We(48),He(123),We(324),He(254),2) + + draw.SimpleText(lang["main_menu_2"], "SuR_MediumFont1", We(50), He(50), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["pmsettings_main"], "SuR_SmallFont2", We(50), He(100), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["pmsettings_wep"], "SuR_SmallFont2", We(50), He(420), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + + draw.SimpleText(lang["pmsettings_voice"], "SuR_SmallFont2", We(610), He(100), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + + draw.SimpleText(lang["pmsettings_info"], "SuR_SmallFont1", We(810), He(520), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + + icon:SetModel(modcur) + end + DermaPanel.OnRemove = function(self) + if SuR.Data["WaveState"] and ply:Alive() then + chat.AddText(Color(255,255,255), lang["pmsettings_mes1"]) + return + else + if modcur != ply:GetModel() or selectedweapon != ply:GetNWString('StartWeapon') or selectedvoice != ply:GetNWString('VoicePack') then + chat.AddText(Color(255,255,255), lang["pmsettings_mes2"]) + end + end + net.Start("SuR.SelectPlayerModel") + net.WriteString(modcur) + net.SendToServer() + net.Start("SuR.ChooseVoicePack") + net.WriteString(selectedvoice) + net.SendToServer() + end + + local but = vgui.Create("DButton", DermaPanel) + but:SetSize(We(30), He(30)) + but:SetPos(We(1000), He(40)) + but:SetText("") + but.Paint = function(self, 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 + but.DoClick = function() + surface.PlaySound("surrounded/click.mp3") + DermaPanel:Remove() + end + but.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + + --- + + local tab = {} + for _, wep in ipairs(SuR.Config.TierWeapons["Tier1"]) do + local info = weapons.Get(wep) + tab[info.PrintName] = {icon = Material("entities/"..wep..".png"), class = wep} + end + if ply:GetNWBool("ExtendedStartWeapons") then + for _, wep in ipairs(SuR.Config.TierWeapons["Tier2"]) do + local info = weapons.Get(wep) + tab[info.PrintName] = {icon = Material("entities/"..wep..".png"), class = wep} + end + end + + local df1 = vgui.Create("DPanel", DermaPanel) + df1:SetPos(We(49), He(400)) + df1:SetSize(We(500), He(350)) + df1.Paint = function(self, w, h) + + end + df1.PaintOver = function(self, w, h) + surface.SetDrawColor(200,200,200,100) + surface.DrawOutlinedRect(0, He(40), We(500), He(240), 2) + end + df1.OnRemove = function() + net.Start("SuR.ChooseStartWeapon") + net.WriteString(selectedweapon) + net.SendToServer() + end + + local df2 = vgui.Create("DPanel", df1) + df2:SetPos(0, He(40)) + df2:SetSize(We(500), He(240)) + df2.Paint = function(self, w, h) end + + local DScrollPanel = vgui.Create( "DScrollPanel", df2 ) + DScrollPanel:Dock( FILL ) + + local down = -1 + for k, v in pairs(tab) do + down = down+1 + local DButton = DScrollPanel:Add( "DButton" ) + DButton:SetText("") + DButton:SetSize(We(500), He(60)) + DButton:SetPos(We(5), He(65)*down) + DButton.Paint = function(self, w, h) + surface.SetMaterial(radio_bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + surface.SetDrawColor(255,255,255) + surface.SetMaterial(v.icon) + surface.DrawTexturedRect(12, 0, 64, 64) + + if selectedweapon == v.class then + draw.SimpleText(k, "SuR_SmallFont2", We(96), h/2, Color(200,200,100), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + elseif self:IsHovered() then + draw.SimpleText(k, "SuR_SmallFont2", We(96), h/2, Color(200,255,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + else + draw.SimpleText(k, "SuR_SmallFont2", We(96), h/2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + end + DButton.DoClick = function(self) + selectedweapon = v.class + surface.PlaySound("surrounded/click.mp3") + end + DButton.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + end + + ----- + + local tab = {} + for k, v in pairs(SuR.Config.VoicePacks) do + tab[#tab+1] = {k, v["enemyspotted"]} + end + + local df1 = vgui.Create("DPanel", DermaPanel) + df1:SetPos(We(609), He(83)) + df1:SetSize(We(400), He(300)) + df1.Paint = function(self, w, h) end + df1.PaintOver = function(self, w, h) + surface.SetDrawColor(200,200,200,100) + surface.DrawOutlinedRect(0, He(40), We(400), He(254), 2) + end + + local df2 = vgui.Create("DPanel", df1) + df2:SetPos(0, He(40)) + df2:SetSize(We(400), He(254)) + df2.Paint = function(self, w, h) end + + local DScrollPanel = vgui.Create( "DScrollPanel", df2 ) + DScrollPanel:Dock( FILL ) + + local down = -1 + for k, v in ipairs(tab) do + down = down+1 + local DButton = DScrollPanel:Add( "DButton" ) + DButton:SetText("") + DButton:SetSize(We(500), He(60)) + DButton:SetPos(We(5), He(65)*down) + DButton.Paint = function(self, w, h) + surface.SetMaterial(radio_bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + surface.SetDrawColor(255,255,255) + surface.SetMaterial(voiceMat) + surface.DrawTexturedRect(16, 8, 48, 48) + + if selectedvoice == v[1] then + draw.SimpleText(v[1], "SuR_SmallFont2", We(96), He(32), Color(200,200,100), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + elseif self:IsHovered() then + draw.SimpleText(v[1], "SuR_SmallFont2", We(96), He(32), Color(200,255,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + else + draw.SimpleText(v[1], "SuR_SmallFont2", We(96), He(32), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + end + DButton.DoClick = function(self) + selectedvoice = v[1] + if not self.Delay or self.Delay < CurTime() then + surface.PlaySound(SuR:GetRandomSound(v[2])) + self.Delay = CurTime()+3 + end + end + DButton.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + end +end + +function SuR:OpenPlayerClassMenu(tables) + local ply = LocalPlayer() + local selectedclass = ply:GetPlayerClass() + + local DermaPanel = vgui.Create("DFrame") + DermaPanel:SetSize(We(600), He(730)) + DermaPanel:Center() + DermaPanel:SetTitle("") + DermaPanel:SetDraggable(false) + DermaPanel:MakePopup() + DermaPanel:ShowCloseButton(false) + + local sp = vgui.Create("DScrollPanel", DermaPanel) + sp:SetSize(We(320), He(250)) + sp:SetPos(We(50),He(125)) + + DermaPanel.Paint = function(self, w, h) + surface.SetMaterial(bg) + surface.SetDrawColor(0,0,0,240) + surface.DrawTexturedRect(0,0,w,h) + + draw.SimpleText(lang["main_menu_3"], "SuR_MediumFont1", We(50), He(50), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + + draw.SimpleText(lang["classmenu_current"]..lang["class_"..ply:GetPlayerClass()], "SuR_PixelFont", We(50), He(75), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(string.format(lang["classmenu_choose"], lang["class_"..selectedclass], lang["class_lvl_"..tables[selectedclass][1]]), "SuR_SmallFont1", w/2, He(310), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["classmenu_info"], "SuR_SmallFont2", w/2, He(390), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + end + DermaPanel.OnRemove = function(self) + if selectedclass == ply:GetPlayerClass() then return end + if ply:Alive() then + chat.AddText(Color(255,255,255), lang["pmsettings_mes3"]) + return + else + chat.AddText(Color(255,255,255), lang["pmsettings_mes2"]) + end + RunConsoleCommand("sur_selectclass", selectedclass) + end + + local but = vgui.Create("DButton", DermaPanel) + but:SetSize(We(30), He(30)) + but:SetPos(We(520), He(30)) + but:SetText("") + but.Paint = function(self, 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 + but.DoClick = function() + surface.PlaySound("surrounded/click.mp3") + DermaPanel:Remove() + end + but.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + + local tab = {} + for k, v in pairs(SuR.Config.ClassIcons) do + local info = weapons.Get(wep) + tab[k] = v + end + + local df1 = vgui.Create("DPanel", DermaPanel) + df1:SetPos(We(49), He(50)) + df1:SetSize(We(500), He(250)) + df1.Paint = function(self, w, h) end + df1.PaintOver = function(self, w, h) + surface.SetDrawColor(200,200,200,100) + surface.DrawOutlinedRect(0, He(40), We(500), He(190), 2) + end + + local df2 = vgui.Create("DPanel", df1) + df2:SetPos(0, He(40)) + df2:SetSize(We(500), He(190)) + df2.Paint = function(self, w, h) end + + local DScrollPanel = vgui.Create( "DScrollPanel", df2 ) + DScrollPanel:Dock( FILL ) + + local down = -1 + for k, v in pairs(tab) do + down = down+1 + local DButton = DScrollPanel:Add( "DButton" ) + DButton:SetText("") + DButton:SetSize(We(500), He(60)) + DButton:SetPos(We(5), He(65)*down) + DButton.Paint = function(self, w, h) + surface.SetMaterial(radio_bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + surface.SetDrawColor(255,255,255) + surface.SetMaterial(v) + surface.DrawTexturedRect(16, 8, 48, 48) + + if selectedclass == k then + draw.SimpleText(lang["class_"..k], "SuR_SmallFont2", We(96), He(25), Color(200,200,100), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["class_lvl_"..tables[k][1]], "SuR_SmallFont1", We(96), He(45), Color(200,200,100), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + elseif self:IsHovered() then + draw.SimpleText(lang["class_"..k], "SuR_SmallFont2", We(96), He(25), Color(200,255,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["class_lvl_"..tables[k][1]], "SuR_SmallFont1", We(96), He(45), Color(200,255,200), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + else + draw.SimpleText(lang["class_"..k], "SuR_SmallFont2", We(96), He(25), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + draw.SimpleText(lang["class_lvl_"..tables[k][1]], "SuR_SmallFont1", We(96), He(45), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + end + DButton.DoClick = function(self) + selectedclass = k + surface.PlaySound("surrounded/click.mp3") + end + DButton.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + end + + --- + + local df1 = vgui.Create("DPanel", DermaPanel) + df1:SetPos(We(49), He(380)) + df1:SetSize(We(500), He(300)) + df1.Paint = function(self, w, h) end + df1.PaintOver = function(self, w, h) + surface.SetDrawColor(200,200,200,100) + surface.DrawOutlinedRect(0, He(40), We(500), He(250), 2) + end + + local df2 = vgui.Create("DPanel", df1) + df2:SetPos(0, He(40)) + df2:SetSize(We(500), He(250)) + df2.Paint = function(self, w, h) end + + local DScrollPanel = vgui.Create( "DScrollPanel", df2 ) + DScrollPanel:Dock( FILL ) + + local down = -1 + for i=1,5 do + down = down+1 + local dp = DScrollPanel:Add( "DPanel" ) + dp:SetText("") + dp:SetSize(We(475), He(100)) + dp:SetPos(We(5), He(105)*down) + dp:SetContentAlignment(5) + dp.id = i + dp.Paint = function(self, w, h) + surface.SetDrawColor(0,0,0,200) + surface.DrawRect(0, 0, w, h) + if self.label then + self.label:SetText(lang["class_"..selectedclass.."_state_"..self.id]) + end + end + + local dl = vgui.Create("DLabel", dp) + dl:Dock(FILL) + dl:DockMargin(5,5,5,5) + dl:SetContentAlignment(5) + dl:SetFont("SuR_SmallFont1") + dl:SetWrap(true) + local num = 1+(5*(i-1)) + dl:SetText("") + dl.Paint = function(self, w, h) + local lvl = tables[selectedclass][1] + if lvl >= num then + self:SetText("✓ "..lang["classmenu_state"]..lang["class_lvl_"..num].."\n\n"..lang["class_"..selectedclass.."_state_"..i]) + self:SetTextColor(Color(50,200,50)) + else + self:SetText(lang["classmenu_state"]..lang["class_lvl_"..num]) + self:SetTextColor(Color(200,50,50)) + end + end + end +end +net.Receive("SuR.OpenClassMenu", function(len, ply) + local tab = net.ReadTable() + SuR:OpenPlayerClassMenu(tab) +end) + +--------------------------MAIN MENU + +local mainpanel = nil + +hook.Add("Think", "SuR_MainMenu", function(ply, but) + if input.IsKeyDown(KEY_ESCAPE) then + SuR:OpenMainMenu() + end +end) + +function SuR:OpenMainMenu() + if IsValid(mainpanel) then return end + + mainpanel = vgui.Create("DFrame") + mainpanel:SetSize(ScrW(), ScrH()) + mainpanel:SetTitle("") + mainpanel:SetDraggable(false) + mainpanel:MakePopup() + mainpanel:ShowCloseButton(false) + mainpanel:AlphaTo(0, 0) + mainpanel:AlphaTo(255, 0.2) + mainpanel.OnRemove = function() + SuR.Data["DrawHUD"] = true + end + mainpanel.Paint = function(self, w, h) + surface.SetDrawColor(0,0,0,100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(0,0,0,200) + surface.SetMaterial(radio_bgMat) + surface.DrawTexturedRect(0, 0, We(550), h) + + SuR.Data["DrawHUD"] = false + end + + local secpanel = vgui.Create("DPanel", mainpanel) + secpanel:SetPos(0, 0) + secpanel:SetSize(We(400), ScrH()) + secpanel.Paint = function(self, w, h) + gui.HideGameUI() + + draw.SimpleText("Surrounded", "SuR_MediumFont2", We(200), He(20), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP) + end + + local scr1 = vgui.Create("DScrollPanel", secpanel) + scr1:Dock(FILL) + + local main_menu_buttons = { + { + Name = lang["main_menu_1"], + CustomDock = {We(150),He(5)}, + ClickFunc = function(self) end, + }, + { + Name = lang["main_menu_2"], + ClickFunc = function(self) + SuR:OpenPMMenu() + end, + }, + { + Name = lang["main_menu_3"], + ClickFunc = function(self) + net.Start("SuR.OpenClassMenu") + net.SendToServer() + end, + }, + { + Name = lang["main_menu_4"], + ClickFunc = function(self) + SuR:OpenSettingsMenu() + end, + }, + { + Name = lang["main_menu_discord"], + ClickFunc = function(self) + gui.OpenURL("https://discord.gg/ACVMgAfKKt") + end, + }, + { + Name = lang["main_menu_site"], + ClickFunc = function(self) + gui.OpenURL("https://refoseltw.ru") + end, + }, + { + Name = lang["main_menu_5"], + CustomDock = {We(50),He(5)}, + ClickFunc = function(self) + timer.Simple(0.01, function() + gui.ActivateGameUI() + end) + end, + }, + } + + for k, v in ipairs(main_menu_buttons) do + local but = scr1:Add("DButton") + but:SetText("") + but:Dock( TOP ) + but:SetSize(0, He(40)) + but:DockMargin(We(10), 0, We(10), He(5)) + if v.CustomDock then + but:DockMargin(We(10), He(v.CustomDock[1]), We(10), He(v.CustomDock[2])) + end + but.DoClick = function() + surface.PlaySound("surrounded/click.mp3") + mainpanel:AlphaTo(0, 0.2, 0, function(tab, pnl) + mainpanel:Remove() + v.ClickFunc() + end) + end + but.Paint = function(self, w, h) + surface.SetMaterial(bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + local hov = self:IsHovered() + if hov then + draw.SimpleText(v.Name, "SuR_SmallFont2", w/2, h/2-He(2), Color(200,255,200), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + else + draw.SimpleText(v.Name, "SuR_SmallFont2", w/2, h/2-He(2), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + end + + end + but.OnCursorEntered = function() + surface.PlaySound("surrounded/tick.wav") + end + end +end + +function SuR:OpenDropMenu() + local ply = LocalPlayer() + local weapons = {} + for _, w in ipairs(ply:GetWeapons()) do + if w:GetClass() == SuR.Config.EmptyWeapon then continue end + local name = w:GetPrintName() or w.PrintName + if name then + weapons[#weapons+1] = {w:GetClass(), name} + end + end + if ply:GetNWFloat('Bandages') > 2 then + weapons[#weapons+1] = {"bandage", lang["loot_bandages"].." x"..ply:GetNWFloat('Bandages')} + end + if ply:GetNWFloat('Sprays') > 0 then + weapons[#weapons+1] = {"antidote", lang["loot_antidote"].." x"..ply:GetNWFloat('Sprays')} + end + if ply:GetNWFloat('SelfRevive') > 0 then + weapons[#weapons+1] = {"selfrevive", lang["loot_selfrevive"].." x"..ply:GetNWFloat('SelfRevive')} + end + if ply:GetNWFloat('CanCallSupport') > 0 then + weapons[#weapons+1] = {"radio", lang["loot_radio"].." x"..ply:GetNWFloat('CanCallSupport')} + end + + local df = vgui.Create("DFrame") + df:SetSize(We(380), He(90)+(#weapons*He(45))) + 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) + + if #weapons > 0 then + draw.SimpleText(lang["menu_drop"], "SuR_SmallFont1", We(25), He(25), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + else + draw.SimpleText(lang["menu_nodrop"], "SuR_SmallFont1", We(25), He(25), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + end + + local db = vgui.Create("DButton", df) + db:SetSize(We(32), He(32)) + db:SetPos(We(305),He(25)) + 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 + + for k, v in ipairs(weapons) do + local db = vgui.Create("DButton", df) + db:SetSize(We(320), He(40)) + db:SetPos(We(25),He(20)+(k*He(45))) + db:SetText("") + function db:OnCursorEntered() + surface.PlaySound("surrounded/tick.wav") + end + function db:DoClick() + RunConsoleCommand("sur_dropweapon", v[1]) + df:Remove() + end + function db:Paint(w, h) + surface.SetMaterial(bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + if db:IsHovered() then + draw.SimpleText("- "..v[2], "SuR_SmallFont1", We(25), h/2, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + else + draw.SimpleText(v[2], "SuR_SmallFont1", We(25), h/2, Color(150,150,150), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + end + end +end + +function SuR:OpenSpawnMenu() + if !LocalPlayer():IsSuperAdmin() then return end + + local frame = vgui.Create("DFrame") + frame:SetSize(400, 300) + frame:SetTitle("Admin Spawnmenu") + frame:SetVisible(true) + frame:SetDraggable(true) + frame:ShowCloseButton(true) + frame:Center() + frame:MakePopup() + frame.Paint = function(self, w, h) + surface.SetDrawColor(0,0,0,240) + surface.DrawRect(0,0,w,h) + end + + local categoryTabs = vgui.Create("DPropertySheet", frame) + categoryTabs:Dock(FILL) + + local weaponPanel = vgui.Create("DPanel") + categoryTabs:AddSheet("Weapons", weaponPanel, "icon16/gun.png") + + local weaponList = vgui.Create("DListView", weaponPanel) + weaponList:Dock(FILL) + weaponList:AddColumn("Weapons") + + local entityPanel = vgui.Create("DPanel") + categoryTabs:AddSheet("Entities", entityPanel, "icon16/brick.png") + + local entityList = vgui.Create("DListView", entityPanel) + entityList:Dock(FILL) + entityList:AddColumn("Entities") + + local npcPanel = vgui.Create("DPanel") + categoryTabs:AddSheet("NPCs", npcPanel, "icon16/user.png") + + local npcList = vgui.Create("DListView", npcPanel) + npcList:Dock(FILL) + npcList:AddColumn("NPCs") + + local function AddItemToCategory(pnl, name, cmd) + local itemLine = pnl:AddLine(name) + itemLine.OnSelect = function() + surface.PlaySound("buttons/combine_button1.wav") + LocalPlayer():ConCommand(cmd) + end + end + + for k, v in pairs(list.Get("NPC")) do + if not v.Name or v.Name == "" then return end + local cmd = "sur_spawn "..v.Class + AddItemToCategory(npcList, v.Name, cmd) + end + + for k, v in pairs(list.Get("Weapon")) do + if not v.ClassName or v.ClassName == "" then return end + local cmd = "sur_spawn "..v.ClassName + AddItemToCategory(weaponList, v.PrintName, cmd) + end + + for k, v in pairs(list.Get("SpawnableEntities")) do + if not v.ClassName or v.ClassName == "" then return end + local cmd = "sur_spawn "..v.ClassName + AddItemToCategory(entityList, v.PrintName, cmd) + end +end +concommand.Add("sur_spawnmenu", SuR.OpenSpawnMenu) + +function SuR:OpenClassMenu() + local ply = LocalPlayer() + local tab = table.Copy(SuR.Config.Zombie_Unlock_Wave) + + local df = vgui.Create("DFrame") + df:SetSize(ScrW(), He(300)) + df:SetPos(0, ScrH()/2-He(150)) + df:SetTitle("") + df:MakePopup() + df:ShowCloseButton(false) + df:SetDraggable(false) + df.Paint = function(self, w, h) + surface.SetDrawColor(20,20,20,200) + surface.DrawRect(0, 0, w, h) + + draw.SimpleText(lang["zombiemenu_choose"], "SuR_SmallFont1", w/2, He(25), color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP) + end + + local db = vgui.Create("DButton", df) + db:SetSize(We(32), He(32)) + db:SetPos(ScrW()-We(200),He(25)) + 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 num = -1 + for k, v in SortedPairsByValue(tab) do + num = num+1 + local db = vgui.Create("DButton", df) + db:SetSize(We(220), He(200)) + db:SetPos(We(50)+(num*We(230)),He(60)) + db:SetText("") + function db:OnCursorEntered() + surface.PlaySound("surrounded/tick.wav") + end + function db:DoClick() + RunConsoleCommand("sur_zombieclass", k) + df:Remove() + end + function db:Paint(w, h) + local wave = SuR.Data["Wave"] + if not SuR.Data["WaveState"] then + wave = wave + 1 + end + + surface.SetMaterial(bgMat) + surface.SetDrawColor(0,0,0,200) + surface.DrawTexturedRect(0, 0, w, h) + + if v <= wave then + draw.SimpleText(k, "SuR_SmallFont1", w/2, h-56, Color(255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + draw.SimpleText(lang["zombiemenu_unlocked"], "SuR_SmallFont1", w/2, h-32, Color(150,150,150), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + else + draw.SimpleText(k, "SuR_SmallFont1", w/2, h-56, Color(255,0,0), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + draw.SimpleText(string.format(lang["zombiemenu_unlock"], v), "SuR_SmallFont1", w/2, h-32, Color(150,150,150), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + end + end + + local mod = vgui.Create("SpawnIcon", db) + mod:SetSize(We(72), He(72)) + mod:SetPos(We(76), He(36)) + mod:SetModel(table.Random(SuR.Config.Zombie_PlayerModels[k])) + function mod:DoClick() + RunConsoleCommand("sur_zombieclass", k) + df:Remove() + end + end +end +concommand.Add("sur_zombiemenu", SuR.OpenClassMenu) + +local showed_tips = {} +function SuR:ShowTip(type) + if showed_tips[type] or GetConVar("sur_disable_hints"):GetBool() then return end + showed_tips[type] = true + SuR.Data["DrawHUD"] = false + surface.PlaySound("surrounded/sfx/tips.mp3") + local tip_mat = def_bg_mat + local tip_title = lang["tip_"..type] or "" + local tip_text = lang["tip_"..type.."_desc"] or "" + if file.Exists("materials/surrounded/tips/"..type..".png", "GAME") then + tip_mat = Material("surrounded/tips/"..type..".png", "noclamp smooth") + end + + local df = vgui.Create("DFrame") + df:SetSize(ScrW(), ScrH()) + df:SetTitle("") + df:MakePopup() + df:ShowCloseButton(false) + df:AlphaTo(0, 0) + df:AlphaTo(255, 0.2) + df:SetDraggable(false) + df.Paint = function(self, w, h) + surface.SetDrawColor(0,0,0,150) + surface.DrawRect(0, 0, w, h) + end + + local sec = vgui.Create("DPanel", df) + sec:SetSize(We(1800), He(1000)) + sec:Center() + sec.Paint = function(self, w, h) + surface.SetMaterial(bg2) + surface.SetDrawColor(0,0,0,250) + surface.DrawTexturedRect(0, 0, w, h) + + draw.SimpleText(lang["tip_main"], "SuR_SmallFont2", We(100), He(40), Color(200,200,0), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + draw.SimpleText(tip_title, "SuR_MediumFont2", We(100), He(70), color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + + -------------------- + + surface.SetMaterial(tip_mat) + surface.SetDrawColor(255,255,255) + surface.DrawTexturedRect(We(320), He(150), We(1920*0.6), He(1080*0.6)) + + surface.SetDrawColor(200,200,200,250) + surface.DrawOutlinedRect(We(320), He(150), We(1920*0.6), He(1080*0.6)) + end + + local function dis() + gui.EnableScreenClicker(false) + df:AlphaTo(0, 0.2, 0, function() + df:Remove() + SuR.Data["DrawHUD"] = true + end) + end + + local dl = vgui.Create("DLabel", df) + dl:SetPos(We(150), He(760)) + dl:SetSize(We(1600), He(200)) + dl:SetText(tip_text) + dl:SetTextColor(color_white) + dl:SetFont("SuR_SmallFont2") + dl:SetWrap(true) + dl:SetContentAlignment(1) + + local db = vgui.Create("DButton", sec) + db:SetSize(We(32), He(32)) + db:SetPos(We(1650),He(70)) + 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") + dis() + end + function db:OnCursorEntered() + surface.PlaySound("surrounded/tick.wav") + end +end +net.Receive("SuR.ShowTips", function() + local str = net.ReadString() + SuR:ShowTip(str) +end) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_other.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_other.lua new file mode 100644 index 0000000..c1aacfa --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_other.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_outline.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_outline.lua new file mode 100644 index 0000000..d6f9bbc --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/client/cl_outline.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/init.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/init.lua new file mode 100644 index 0000000..84bf8f9 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/init.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/en.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/en.lua new file mode 100644 index 0000000..385bed1 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/en.lua @@ -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", +} diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/ru.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/ru.lua new file mode 100644 index 0000000..7d44a3c --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/lang/ru.lua @@ -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"] = "Купить", +} diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_abilities.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_abilities.lua new file mode 100644 index 0000000..3cf0c4f --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_abilities.lua @@ -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) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_buymenu.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_buymenu.lua new file mode 100644 index 0000000..9b1e318 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_buymenu.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_classes.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_classes.lua new file mode 100644 index 0000000..979a6bd --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_classes.lua @@ -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) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_executions.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_executions.lua new file mode 100644 index 0000000..98f7883 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_executions.lua @@ -0,0 +1,6055 @@ +local function PlayRandomSound(ent, min, max, str) + if !IsValid(ent) then return end + sound.Play(str..math.random(min,max)..".wav", ent:GetPos(), 75) +end + +local function effects_takedown(ply, targetModel, animName) + local targetHeadBone = targetModel:LookupBone("ValveBiped.Bip01_Head1") + if animName == "killmove_leatherface_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/Cin_Execution_LF_01_Saw.wav", targetModel:GetPos()) + sound.Play("tcm/chainsaw/sfx_chainsaw_start_01.wav", targetModel:GetPos()) + end) + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/Cin_Execution_LF_01_Gore.wav", targetModel:GetPos()) + end) + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 3, "tcm/swing_foley/sfx_giant_grab_swing_sweet_0") + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_start_0") + sound.Play("tcm/chainsaw/sfx_chainsaw_gore_loop.wav", targetModel:GetPos()) + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_end_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_end_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/death/sfx_survivor_incapped_bodyfall_right_01.wav", targetModel:GetPos()) + end) + timer.Simple(5.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/death/sfx_survivor_incapped_bodyfall_forward_01.wav", targetModel:GetPos()) + end) + end + + if animName == "killmove_leatherface_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/chainsaw/sfx_chainsaw_start_01.wav", targetModel:GetPos()) + PlayRandomSound(targetModel, 1, 3, "tcm/cloth_foley/sfx_cloth_backpack_jump_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 3, "tcm/swing_foley/sfx_giant_grab_swing_sweet_0") + end) + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/Cin_Execution_LF_02_Saw.wav", targetModel:GetPos()) + sound.Play("tcm/executions/Cin_Execution_LF_02_Gore.wav", targetModel:GetPos()) + end) + timer.Simple(1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_start_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 3, "tcm/swing_foley/sfx_giant_grab_swing_sweet_0") + end) + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_start_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 1, "tcm/death/sfx_survivor_incapped_bodyfall_forward_0") + end) + timer.Simple(7.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 3, "tcm/cloth_foley/sfx_cloth_backpack_jump_0") + sound.Play("tcm/misc/sfx_survivor_get_up_strangler.wav", targetModel:GetPos()) + end) + timer.Simple(9.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_start_0") + --PlayRandomSound(targetModel, 2, 16, "tcm/misc/Static_Design_0") + sound.Play("tcm/chainsaw/sfx_chainsaw_gore_loop.wav", targetModel:GetPos()) + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(9.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(10.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(11, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(11.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(11.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(11.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(11.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(12, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(12.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_gore_end_0") + PlayRandomSound(targetModel, 1, 3, "tcm/chainsaw/sfx_chainsaw_end_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(12.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/death/sfx_survivor_incapped_bodyfall_right_01.wav", targetModel:GetPos()) + end) + end + + if animName == "killmove_cook_01" then + timer.Simple(0.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/AK_Play_Cin_Execution_Cook_01_Gore.wav", targetModel:GetPos()) + end) + timer.Simple(4.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 5, "tcm/impact/sfx_melee_impact_baby_spider_0") + end) + timer.Simple(4.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/death/sfx_survivor_incapped_bodyfall_right_01.wav", targetModel:GetPos()) + end) + timer.Simple(6.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/death/sfx_survivor_incapped_bodyfall_back_01.wav", targetModel:GetPos()) + end) + end + + if animName == "killmove_cook_03" then + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/Cin_Execution_Cook_03_Gore.wav", targetModel:GetPos()) + end) + timer.Simple(0.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + end) + timer.Simple(1.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + end) + timer.Simple(1.85, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/misc/sfx_adrenaline_effect_heartbeat_loop.wav", targetModel:GetPos()) + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(6.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(8.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 4, "tcm/impact/sfx_weapons_generic_impact_body_0") + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_johnny_01" then + timer.Simple(0.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/AK_Play_Cin_Execution_Johnny_01_Gore.wav", targetModel:GetPos()) + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + end) + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_leather_0") + end) + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 8, "tcm/impact/sfx_pipe_hit_gore_0") + end) + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_leather_0") + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 8, "tcm/impact/sfx_pipe_hit_gore_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_leather_0") + end) + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 8, "tcm/impact/sfx_pipe_hit_gore_0") + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/misc/sfx_survivor_get_up_strangler.wav", targetModel:GetPos()) + end) + end + + if animName == "killmove_hiker_01" then + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("tcm/executions/AK_Play_Cin_Execution_Hitch_01_Gore.wav", targetModel:GetPos()) + PlayRandomSound(targetModel, 1, 10, "tcm/cloth_foley/sfx_cloth_jeans1_walk_0") + end) + timer.Simple(0.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_cloth_0") + end) + timer.Simple(1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_cloth_0") + end) + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_cloth_0") + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(targetModel, 1, 6, "tcm/swing_foley/sfx_melee_foley_swing_cloth_0") + end) + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_slasher_front" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/sfx_slasher_execution_front_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(5.6, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_slasher_front_unused" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/front_slasher_unused.wav", targetModel:GetPos()) + end) + timer.Simple(1.4, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_strangler_front" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/sfx_strangler_execution_front_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(2.2, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.2, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5.1, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_giant_front" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + end) + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/sfx_giant_execution_front_E56FEEA2.wav", targetModel:GetPos()) + end) + timer.Simple(3.3, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_giant_front_unused" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/giant_front_unused.wav", targetModel:GetPos()) + end) + timer.Simple(3.6, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_giant_ambush" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/giant_ambush.wav", targetModel:GetPos()) + end) + timer.Simple(3.3, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(7, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_slasher_fallback" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/sfx_slasher_execution_fallback_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(2, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_giant_back" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + sound.Play("executions/sfx_giant_execution_hulk_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(1.8, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.3, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(5, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_giant_backstomp" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + + end) + timer.Simple(0.68, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("executions/sfx_giant_execution_back_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(1.9, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(3.2, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + timer.Simple(4.8, function() + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_slasher_back" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + + sound.Play("executions/LY_DC_Stinger_SurvivorWitnessExecution_F5818CF0.wav", targetModel:GetPos()) + end) + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + + sound.Play("executions/sfx_slasher_execution_back_3D2108D6.wav", targetModel:GetPos()) + end) + timer.Simple(5.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + + if targetHeadBone != nil then + local effectdata = EffectData() + effectdata:SetOrigin(targetModel:GetBonePosition(targetHeadBone)) + util.Effect("BloodImpact", effectdata) + end + end) + end + + if animName == "killmove_evildead_shovel_01" or animName == "killmove_evildead_etool_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + + -- ShovelImpactLight | BodyParts + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Main + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/shovel/a1839_Shovel_Finisher_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + + -- ShovelImpactHeavy | BodyParts + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BloodSplash + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_shovel_02" or animName == "killmove_evildead_etool_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + + -- ShovelImpactLight | BodyParts + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/shovel/a1839_Shovel_Finisher_C.wav", ply:GetPos()) + end) + + -- BodyParts | HeadSmash + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- BodyFall + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Swing + timer.Simple(2.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + end + + if animName == "killmove_evildead_shovel_03" or animName == "killmove_evildead_etool_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Swing + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + + -- ShovelImpactLight | BodyParts + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/shovel/Shovel_Swing_2D_0") + end) + + -- HeadSmash | BodyParts + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_01") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Swing + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- HeadSmash | BodyParts + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_01") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Swing + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- HeadOff + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/Head_Off.wav", ply:GetPos()) + end) + + -- HeadSmash | BodyParts + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_01") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Main + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/shovel/a1839_Shovel_Finisher_B.wav", ply:GetPos()) + end) + + -- BodyFall + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_machete_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2206_Machete_Finisher_01_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Grab + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- BodyFall + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Main + timer.Simple(1.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2206_Machete_Finisher_01_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake | HeadSmash + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Swing + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake | BloodSplash + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + end + + if animName == "killmove_evildead_machete_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2745_Machete_Finisher_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake | HeadSmash + timer.Simple(0.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Main + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2745_Machete_Finisher_02_B.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Swing + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake | HeadSmash + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- BloodShake + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BloodShake + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Swing + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BloodSplash + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_machete_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2751_Machete_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Swing + timer.Simple(1.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + + -- BodyParts | BloodShake | HeadSmash + timer.Simple(1.23, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Main + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2751_Machete_Finisher_03_B.wav", ply:GetPos()) + end) + + -- BodyFall + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- BloodSplash | BloodShake + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BloodShake + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Swing + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/machete/Machete_Swing_0") + end) + end + + if animName == "killmove_evildead_butcherknife_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/machete/a2751_Machete_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- ImpactEgg + timer.Simple(1.05, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Swing + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeRip + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- BloodSplash | BloodShake + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Main + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_C.wav", ply:GetPos()) + end) + + -- BodyFall + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_butcherknife_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeWoosh + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/Knife_Whoosh.wav", ply:GetPos()) + end) + + -- KnifeCut + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a2698_ButcherKnife_Finisher_04_B.wav", ply:GetPos()) + end) + + -- GrabKnife + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/knife/o0013_HuntingKnife_PickUp_0") + end) + + -- HandSlap + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/Hand_Slap.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeRip + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- BloodSplash | BloodShake + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BodyFall + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_butcherknife_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a2698_ButcherKnife_Finisher_04_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Swing + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a2698_ButcherKnife_Finisher_04_B.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- KnifeRip + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Rip_2D_0") + end) + + -- BloodSplash | BloodShake + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BodyFall + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_sword_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a1928_Sword_Finisher_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordLight + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Light_2D_0") + end) + + -- Main + timer.Simple(1.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a1928_Sword_Finisher_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- Swing + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordLight + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Light_2D_0") + end) + + -- BloodShake + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BloodShake + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- Main + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a1928_Sword_Finisher_C.wav", ply:GetPos()) + end) + + -- BloodShake + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- SwordHeavy + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Heavy_2D_0") + end) + + -- Swing + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- BloodSplash + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_sword_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a2697_Sword_Finisher_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordLight + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Light_2D_0") + end) + + -- Main + timer.Simple(1.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a2697_Sword_Finisher_02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordLight + timer.Simple(1.65, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Light_2D_0") + end) + + -- Swing + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordHeavy + timer.Simple(2.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Heavy_2D_0") + end) + + -- BloodSplash + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_sword_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a2783_Sword_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordLight + timer.Simple(0.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Light_2D_0") + end) + + -- Main + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a2783_Sword_Finisher_03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordHeavy + timer.Simple(1.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Heavy_2D_0") + end) + + -- Main + timer.Simple(1.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sword/a2783_Sword_Finisher_03_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Swing_2D_0") + end) + + -- SwordHeavy + timer.Simple(2.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sword/Sword_Flesh_Heavy_2D_0") + end) + + -- BloodSplash + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_mace_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2925_Mace_01_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact + timer.Simple(0.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2925_Mace_01_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2925_Mace_01_C.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(2.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Swing + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- Swing + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact | BloodSplash + timer.Simple(3.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_mace_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2933_Mace_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BloodShake + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- BloodShake + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 2, "bsmod/EvilDead/Blood_Shake_0") + end) + + -- GrabMace + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/knife/o0013_HuntingKnife_PickUp_0") + end) + + -- Main + timer.Simple(2.65, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2933_Mace_02_B.wav", ply:GetPos()) + end) + + -- HeadSmash + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Swing + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- Swing + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact | BloodSplash + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(4.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_mace_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2945_Mace_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Swing_0") + end) + + -- MaceImpact + timer.Simple(0.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Main + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2945_Mace_03_B.wav", ply:GetPos()) + end) + + -- MaceImpact | BloodSplash + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- GrabMace + timer.Simple(4.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/knife/o0013_HuntingKnife_PickUp_0") + end) + + -- Main + timer.Simple(4.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/mace/a2945_Mace_03_C.wav", ply:GetPos()) + end) + end + + if animName == "killmove_evildead_sledge_01" or animName == "killmove_evildead_fubar_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a2238_Sledgehammer_Finisher_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactEgg + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Main + timer.Simple(0.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a2238_Sledgehammer_Finisher_02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Swing_2D_0") + end) + + -- MaceImpact | BloodSplash + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_sledge_02" or animName == "killmove_evildead_fubar_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a1407_SledgeHammer_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- SledgeHit + timer.Simple(0.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + end) + + -- BodyFall + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Main + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a1407_SledgeHammer_03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Swing_2D_0") + end) + + -- MaceImpact | BloodSplash + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + end + + if animName == "killmove_evildead_sledge_03" or animName == "killmove_evildead_fubar_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a2752_SledgeHammer_Finisher_04_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- SledgeHit + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- BodyFall + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Main + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/sledge/a2752_SledgeHammer_Finisher_04_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Swing_2D_0") + end) + + -- MaceImpact | BloodSplash + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/mace/Mace_Impact_Crunch_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/sledge/o0003_SledgeHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + end + + if animName == "killmove_evildead_bat_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1135_BatNails_Finisher_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Swing_2D_0") + end) + + -- BatHit + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Main + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1135_BatNails_Finisher_02_B.wav", ply:GetPos()) + end) + + -- BodyFall + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Swing + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Swing_2D_0") + end) + + -- BatHit + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + end) + + -- Main + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1135_BatNails_Finisher_02_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Swing_2D_0") + end) + + -- BatHit + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + end) + + -- Main + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1135_BatNails_Finisher_02_D.wav", ply:GetPos()) + end) + + -- BatHit | BloodSplash + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + end + + if animName == "killmove_evildead_bat_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1135_BatNails_Finisher_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_01") + end) + + -- ImpactEgg + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Main + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a1330_BatNails_Finisher_03_B.wav", ply:GetPos()) + end) + + -- BodyFall + timer.Simple(0.65, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- BatHit | BloodSplash + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + end + + if animName == "killmove_evildead_bat_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a2754_BatNails_Finisher_04_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Swing_2D_0") + end) + + -- BatHit + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + --PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Main + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a2754_BatNails_Finisher_04_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Swing_2D_0") + end) + + -- BatHit + timer.Simple(1.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + end) + + -- Main + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/bat/a2754_BatNails_Finisher_04_C.wav", ply:GetPos()) + end) + + -- BatHit | BloodSplash + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/bat/o0012_BatNails_Flesh_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(3.67, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_knife_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Stab_2D_0") + end) + + -- Main + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Rip_2D_0") + end) + + -- BloodSplash + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Grab + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- BodyFall + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_knife_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1374_HuntingKnife_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1374_HuntingKnife_Finisher_03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- HeadSmash + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- BloodSplash + timer.Simple(1.34, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_knife_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- KnifeCut + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- HeadSmash + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/knife/o0013_HuntingKnife_Cut_2D_0") + end) + + -- Main + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_C.wav", ply:GetPos()) + end) + + -- KnifeRip | BloodSplash + timer.Simple(2.12, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Rip_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Swing_2D_0") + end) + + -- BodyFall + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_handaxe_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2762_HandAxe_Finisher_06_A.wav", ply:GetPos()) + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + end) + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2743_HandAxe_Finisher_05_A.wav", ply:GetPos()) + end) + timer.Simple(2.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(2.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/knife/o0013_HuntingKnife_Rip_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_handaxe_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2762_HandAxe_Finisher_06_A.wav", ply:GetPos()) + end) + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(1.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2762_HandAxe_Finisher_06_B.wav", ply:GetPos()) + end) + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_handaxe_03" then + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2743_HandAxe_Finisher_05_A.wav", ply:GetPos()) + end) + timer.Simple(0.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(0.65, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + end) + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2762_HandAxe_Finisher_06_C.wav", ply:GetPos()) + end) + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + timer.Simple(2.85, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_hands_01" then + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/a2133_hands_finisher_01_a.wav", ply:GetPos()) + end) + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/fall_middle_0") + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_swing_2d_0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/punch_impact_face_2d_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/head_smash_0") + end) + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_swing_2d_0") + end) + timer.Simple(3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/punch_impact_face_2d_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/head_smash_0") + end) + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_swing_2d_0") + end) + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/punch_impact_face_2d_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/head_smash_0") + end) + end + + if animName == "killmove_evildead_hands_02" then + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/a2133_hands_finisher_01_b.wav", ply:GetPos()) + end) + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_impact_body_2d_0") + end) + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/punch_impact_face_2d_0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_impact_body_2d_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/blood_splash_0") + end) + end + + if animName == "killmove_evildead_hands_03" then + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/a2133_hands_finisher_01_c.wav", ply:GetPos()) + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_impact_body_2d_0") + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/punch_swing_2d_0") + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/punch_impact_face_2d_0") + end) + end + + if animName == "killmove_evildead_axe_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1219_LumberjackAxe_01_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- AxeLight + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1219_LumberjackAxe_01_B.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- AxeHeavy | BloodSplash + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- BodyFall + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_axe_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1432_LumberjackAxe_02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- AxeLight | BloodSplash + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- Main + timer.Simple(1.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1432_LumberjackAxe_02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- PunchImpact + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Impact_Body_2D_0") + end) + + -- BodyFall + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_axe_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1102_Axe_Finisher03_A.wav", ply:GetPos()) + end) + + + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- PunchImpact + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Impact_Body_2D_0") + end) + + -- Main + timer.Simple(1.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("bsmod/EvilDead/handaxe/a1432_LumberjackAxe_02_B.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1102_Axe_Finisher03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- AxeLight | BloodSplash + timer.Simple(1.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + end) + + -- Main + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1102_Axe_Finisher03_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- PunchImpact + timer.Simple(2.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Impact_Body_2D_0") + end) + + -- Main + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a1102_Axe_Finisher03_D.wav", ply:GetPos()) + end) + + -- AxeHeavy | BloodSplash + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- BodyFall + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_axe_04" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/handaxe/a2758_LumberjackAxe_05_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/handaxe/o0002_HandAxe_Swing_2D_0") + end) + + -- AxeLight + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- AxeHeavy | BloodSplash + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/handaxe/o0002_HandAxe_Flesh_Heavy_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_hammer_01" or animName == "killmove_evildead_wrench_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1226_MeatHammer_Finisher_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.15, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactBody + timer.Simple(0.25, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Impact_Body_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1226_MeatHammer_Finisher_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + end) + + -- Main + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1226_MeatHammer_Finisher_D.wav", ply:GetPos()) + end) + + -- ImpactBody | BloodSplash + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + end) + + -- BodyFall + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_hammer_02" or animName == "killmove_evildead_wrench_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1340_MeatHammer_Finisher_A.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1340_MeatHammer_Finisher_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Swing + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(0.65, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Main + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1340_MeatHammer_Finisher_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Swing + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Main + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1340_MeatHammer_Finisher_D.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- ImpactBody | BloodSplash + timer.Simple(2.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + end) + + -- BodyFall + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_hammer_03" or animName == "killmove_evildead_wrench_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1342_MeatHammer_Finisher_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Main + timer.Simple(0.35, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1342_MeatHammer_Finisher_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- HammerTime + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_2D_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Swing + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- KnifeGrab + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/knife/o0013_HuntingKnife_PickUp_0") + end) + + -- Main + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/hammer/a1342_MeatHammer_Finisher_D.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.75, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Swing_2D_0") + end) + + -- ImpactBody | BloodSplash + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/hammer/o0064_MeatHammer_Flesh_3D_0") + end) + + -- BodyFall + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_chainsaw_01" or animName == "killmove_evildead_abrasivechainsaw_01" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a1863_Chainsaw_Finisher_A.wav", ply:GetPos()) + end) + + -- ChainsawStart + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_PickUp_0") + end) + + -- ChainsawIdle + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_0") + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactFace + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/punch/Punch_Impact_Face_2D_0") + end) + + -- Main + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a1863_Chainsaw_Finisher_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Scrape + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Scrape.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(2.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- StopSaw + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Stop_0") + end) + + -- Swing + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- BodyFall + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_chainsaw_02" or animName == "killmove_evildead_abrasivechainsaw_02" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a1863_Chainsaw_Finisher_A.wav", ply:GetPos()) + end) + + -- ChainsawStart + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_PickUp_0") + end) + + -- ChainsawIdle + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- ChainsawIdle + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_02.wav", ply:GetPos()) + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(0.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- Swing + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- Swing + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(3.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- Swing + timer.Simple(4.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- StopSaw + timer.Simple(5.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Stop_0") + end) + + -- BodyFall + timer.Simple(5.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + end + + if animName == "killmove_evildead_chainsaw_03" or animName == "killmove_evildead_abrasivechainsaw_03" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2699_Chainsaw_Finisher_06_A.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2270_Chainsaw_Finisher_A.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2699_Chainsaw_Finisher_06_B.wav", ply:GetPos()) + end) + + -- ChainsawStart + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_PickUp_0") + end) + + -- ChainsawIdle + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_03.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(0.45, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- ChainsawAttack + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- ChainsawAttack + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- BodyFall + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Swing + timer.Simple(3.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- StopSaw + timer.Simple(4.55, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Stop_0") + end) + end + + if animName == "killmove_evildead_chainsaw_04" or animName == "killmove_evildead_abrasivechainsaw_04" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a1863_Chainsaw_Finisher_A.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(1.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2717_Chainsaw_Finisher_07.wav", ply:GetPos()) + end) + + -- ChainsawStart + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_PickUp_0") + end) + + -- ChainsawIdle + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- BodyFall + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- StopSaw + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Stop_0") + end) + end + + if animName == "killmove_evildead_chainsaw_05" or animName == "killmove_evildead_abrasivechainsaw_05" then + timer.Simple(0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + end) + + -- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2820_Chainsaw_Finisher_08_A.wav", ply:GetPos()) + end) + + -- Main + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2820_Chainsaw_Finisher_08_B.wav", ply:GetPos()) + end) + + -- ChainsawStart + timer.Simple(0.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_PickUp_0") + end) + + -- ChainsawIdle + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(1.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- ChainsawIdle + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/chainsaw/Chainsaw_Idle_Loop_01.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(0.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- Swing + timer.Simple(1.85, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/chainsaw/Chainsaw_Swing_0") + end) + + -- ChainsawAttack + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- ChainsawAttack + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 9, "bsmod/EvilDead/chainsaw/Chainsaw_Attack_2D_0") + end) + + -- Blade | Flesh | ChainsawEndChain + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 1, 7, "bsmod/EvilDead/chainsaw/Chainsaw_Blade_0") + end) + timer.Simple(2.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 16, "bsmod/EvilDead/chainsaw/Chainsaw_Flesh_0") + PlayRandomSound(ply, 4, 9, "bsmod/EvilDead/chainsaw/Chainsaw_End_Chain_0") + end) + + -- BodyFall + timer.Simple(3.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- StopSaw + timer.Simple(4.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "bsmod/EvilDead/chainsaw/Chainsaw_Stop_0") + end) + end + + ------------------------------------------------------------ + if animName == "executions_angrystrangler_killer_front" then + + ---------------------------- Main + timer.Simple(0.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_AngryStrangler.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(1.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ----------------------------------------------------------- + if animName == "executions_angrystrangler_killer_back" then + + ---------------------------- Main + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_AngryStrangler.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ----------------------------------------------------------- + if animName == "executions_angrystrangler_killer_left" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_AngryStrangler.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ----------------------------------------------------------- + if animName == "executions_angrystrangler_killer_right" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_AngryStrangler.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_footschoke_killer_front" then + + ---------------------------- Main + timer.Simple(0.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_FootChoke.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_footschoke_killer_back" then + + ---------------------------- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_FootChoke.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_footschoke_killer_right" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_FootChoke.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_footschoke_killer_left" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_FootChoke.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + timer.Simple(2.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 7, "trials/step/FS_NPC_LeatherBoot_Walk0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_quietchoke_killer_back" then + + ---------------------------- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_ChokeQuiet.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_quietchoke_killer_front" then + + ---------------------------- Main + timer.Simple(0.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_ChokeQuiet.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.9, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(3.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_quietchoke_killer_left" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_ChokeQuiet.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_quietchoke_killer_right" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_ChokeQuiet.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(9.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_electricpoke_killer_back" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Coyle_Murder_Electricpoke_front.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(7.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_electricpoke_killer_front" then + + ---------------------------- Main + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Coyle_Murder_Electricpoke_front.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(7.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_electricpoke_killer_left" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Coyle_Murder_Electricpoke_front.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(7.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if animName == "executions_electricpoke_killer_right" then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Coyle_Murder_Electricpoke_front.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(7.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if string.match(animName, "executions_smashupguitar_killer_") then + + ---------------------------- Main + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_15sec.wav", ply:GetPos()) + end) + timer.Simple(3.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_BigGrunt_SmashUp.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Guitar + timer.Simple(4.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "vj_lnrspecials/weapons/guitar/melee_guitar_0") + end) + timer.Simple(6.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "vj_lnrspecials/weapons/guitar/melee_guitar_0") + end) + timer.Simple(8.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 5, "vj_lnrspecials/weapons/guitar/melee_guitar_0") + end) + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(6.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(8.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(11.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + if string.match(animName, "executions_knifeeat_killer_") then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_KnifeEat.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + + end + + if string.match(animName, "executions_berserkergutting_killer_") then + + ---------------------------- Main + timer.Simple(0.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_15sec.wav", ply:GetPos()) + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Berserker_Gutted.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + timer.Simple(4.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(6.4, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(8.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + timer.Simple(12.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 6, "trials/foley/FOL_BigGrunt_Torso_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(11.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + ------------------------------------------------------------ + if string.match(animName, "executions_gutting_killer_") then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_Gutting.wav", ply:GetPos()) + end) + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + end + + if string.match(animName, "executions_stabcutthroat_killer_") then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_StabCutThroat.wav", ply:GetPos()) + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + end + + if string.match(animName, "executions_forcefeed_killer_") then + ---------------------------- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_15sec.wav", ply:GetPos()) + end) + timer.Simple(3.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Pusher_ForceFeed.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(2.6, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + timer.Simple(11.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + if string.match(animName, "executions_brainscrambleacid_killer_") then + + ---------------------------- Main + timer.Simple(0.2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/music/MU_Fatalities_Riser_15sec.wav", ply:GetPos()) + end) + timer.Simple(2.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_burn_loop_light.wav", ply:GetPos()) + end) + timer.Simple(4.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_burn_loop_light.wav", ply:GetPos()) + end) + timer.Simple(10.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_spray_start_FP.wav", ply:GetPos()) + end) + timer.Simple(10.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_spray_loop.wav", ply:GetPos()) + end) + timer.Simple(10.3, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_burn_loop_heavy.wav", ply:GetPos()) + end) + timer.Simple(10.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_impact_01.wav", ply:GetPos()) + end) + timer.Simple(11.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_impact_01.wav", ply:GetPos()) + end) + timer.Simple(11.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_impact_02.wav", ply:GetPos()) + end) + timer.Simple(12.0, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_impact_03.wav", ply:GetPos()) + end) + timer.Simple(12.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/acid/sfx_spider_venom_impact_01.wav", ply:GetPos()) + end) + ---------------------------- + + ---------------------------- Foley + timer.Simple(0.8, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 4, "trials/foley/FOL_BigGrunt_Legs_Long0") + end) + ---------------------------- + + ---------------------------- Footsteps + timer.Simple(1.7, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + PlayRandomSound(ply, 1, 3, "vj_Lnrhl2/shared/footstep/zombie_footstep_m_0") + end) + ---------------------------- + + end + + if string.match(animName, "executions_stampy_killer_") then + + ---------------------------- Main + timer.Simple(0.1, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Murder_IntroKick.wav", ply:GetPos()) + end) + timer.Simple(3.5, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + sound.Play("trials/executions/SFX_Scripted_Murder_Grunt_Stampy.wav", ply:GetPos()) + end) + timer.Simple(2, function() + if !IsValid(targetModel) or !IsValid(ply) then return end + --sound.Play("trials/music/MU_Fatalities_Riser_10sec.wav", ply:GetPos()) + end) + end + + if animName == "killmove_evildead_pickaxe_01" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1370_PickAxe_01.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeLight + timer.Simple(0.65, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Grab + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Swing + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeHeavy + timer.Simple(1.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Heavy_2D_0") + end) + + -- BodyFall + timer.Simple(2.0, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Swing + timer.Simple(2.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- BloodSplash + timer.Simple(2.75, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + end + + if animName == "killmove_evildead_pickaxe_02" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1409_PickAxe_Finisher_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeLight + timer.Simple(0.65, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Grab + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Swing + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeHeavy + timer.Simple(1.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Heavy_2D_0") + end) + + -- BodyFall + timer.Simple(1.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + -- Swing + timer.Simple(2.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- Main + timer.Simple(2.5, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1409_PickAxe_Finisher_B.wav", ply:GetPos()) + end) + + -- PickaxeLight + timer.Simple(2.75, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- BloodSplash + timer.Simple(3.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- PickaxeHeavy + timer.Simple(3.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Heavy_2D_0") + end) + end + + if animName == "killmove_evildead_pickaxe_03" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1461_Pickaxe_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.2, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeLight + timer.Simple(0.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1461_Pickaxe_Finisher_03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- PickaxeLight + timer.Simple(1.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Light_2D_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Grab + timer.Simple(2.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Main + timer.Simple(2.4, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/pickaxe/a1461_Pickaxe_Finisher_03_C.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(2.7, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Swing_2D_0") + end) + + -- BloodSplash + timer.Simple(2.75, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- PickaxeHeavy + timer.Simple(2.75, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/pickaxe/PickAxe_Flesh_Heavy_2D_0") + end) + + -- BodyFall + timer.Simple(3.1, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_pipe_01" or animName == "killmove_evildead_crowbar_01" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/bat/a1123_BatNails_Finisher01_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactEgg + timer.Simple(0.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Main + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/bat/a1330_BatNails_Finisher_03_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- LeadPipeImpact + timer.Simple(1.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BloodSplash + timer.Simple(1.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(4.9, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_pipe_02" or animName == "killmove_evildead_crowbar_02" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/bat/a1123_BatNails_Finisher01_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactEgg + timer.Simple(0.2, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Main + timer.Simple(0.9, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.23, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- LeadPipeImpact + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(1.9, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- Main + timer.Simple(1.9, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_A.wav", ply:GetPos()) + end) + + -- BodyParts + timer.Simple(1.9, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(2.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- Main + timer.Simple(2.5, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_C.wav", ply:GetPos()) + end) + + -- LeadPipeImpact + timer.Simple(2.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BloodSplash + timer.Simple(1.6, function() + if !IsValid(targetModel) then return end + -- PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- BodyFall + timer.Simple(4.1, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_pipe_03" or animName == "killmove_evildead_crowbar_03" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.4, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- ImpactEgg + timer.Simple(0.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/ImpactEgg_0") + end) + + -- Main + timer.Simple(1.7, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1374_HuntingKnife_Finisher_03_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.9, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- LeadPipeImpact + timer.Simple(2.0, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(3.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1374_HuntingKnife_Finisher_03_C.wav", ply:GetPos()) + end) + + -- Grab + timer.Simple(3.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- BloodSplash + timer.Simple(3.8, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- LeadPipeImpact + timer.Simple(3.8, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(3.9, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- BodyFall + timer.Simple(4.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_pipe_04" or animName == "killmove_evildead_crowbar_04" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.4, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- BodyParts + timer.Simple(0.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/Head_Smash_0") + end) + + -- Main + timer.Simple(1.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_B.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(1.7, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- LeadPipeImpact + timer.Simple(1.8, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Grab + timer.Simple(2.8, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Grab_0") + end) + + -- Main + timer.Simple(3.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1129_Knife_Finisher04_C.wav", ply:GetPos()) + end) + + -- LeadPipeImpact + timer.Simple(3.3, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Swing + timer.Simple(3.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/leadpipe/LeadPipe_Swing_0") + end) + + -- BodyFall + timer.Simple(5.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + + if animName == "killmove_evildead_pipe_05" or animName == "killmove_evildead_crowbar_05" then + timer.Simple(0, function() + if !IsValid(targetModel) then return end + end) + + -- Main + timer.Simple(0.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/knife/a1104_Knife_Finisher02_A.wav", ply:GetPos()) + end) + + -- Swing + timer.Simple(0.1, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 6, "bsmod/EvilDead/punch/Punch_Swing_2D_0") + end) + + -- LeadPipeImpact + timer.Simple(0.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(0.3, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2820_Chainsaw_Finisher_08_B.wav", ply:GetPos()) + end) + + -- LeadPipeImpact + timer.Simple(1.4, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- Main + timer.Simple(3.0, function() + if !IsValid(targetModel) then return end + sound.Play("bsmod/EvilDead/chainsaw/a2820_Chainsaw_Finisher_08_A.wav", ply:GetPos()) + end) + + -- BloodSplash + timer.Simple(3.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Blood_Splash_0") + end) + + -- LeadPipeImpact + timer.Simple(3.6, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 5, "bsmod/EvilDead/leadpipe/LeadPipe_Flesh_0") + PlayRandomSound(ply, 1, 8, "bsmod/EvilDead/BodyParts_0") + end) + + -- BodyFall + timer.Simple(1.5, function() + if !IsValid(targetModel) then return end + PlayRandomSound(ply, 1, 4, "bsmod/EvilDead/Fall_Middle_0") + end) + + end + +end + +local meta = FindMetaTable("Player") +function meta:AbilityTakedown() + if !self:Alive() or self:GetNWString('SVAnim') != "" or self:IsLockedAbilities() then return end + + local wep = self:GetNWString('MeleeWeapon') + local owep = self:GetNWString('OtherWeapon') + local rnd, rnd2 = "hands", math.random(1,3) + if isstring(wep) and self:HasWeapon(wep) then + if table.HasValue(SuR.Config.Weapons_Executions_Anims["chainsaw"], wep) then + rnd, rnd2 = "chainsaw", math.random(1,5) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["abrasivechainsaw"], wep) then + rnd, rnd2 = "abrasivechainsaw", math.random(1,5) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["axe"], wep) then + rnd, rnd2 = "axe", math.random(1,4) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["hammer"], wep) then + rnd, rnd2 = "hammer", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["shovel"], wep) then + rnd, rnd2 = "shovel", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["etool"], wep) then + rnd, rnd2 = "etool", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["wrench"], wep) then + rnd, rnd2 = "wrench", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["fubar"], wep) then + rnd, rnd2 = "fubar", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["crowbar"], wep) then + rnd, rnd2 = "crowbar", math.random(1,5) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["machete"], wep) then + rnd, rnd2 = "machete", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["butcherknife"], wep) then + rnd, rnd2 = "butcherknife", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["pickaxe"], wep) then + rnd, rnd2 = "pickaxe", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["pipe"], wep) then + rnd, rnd2 = "pipe", math.random(1,5) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["sledge"], wep) then + rnd, rnd2 = "sledge", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["bat"], wep) then + rnd, rnd2 = "bat", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["knife"], wep) then + rnd, rnd2 = "knife", math.random(1,3) + + elseif table.HasValue(SuR.Config.Weapons_Executions_Anims["handaxe"], wep) then + rnd, rnd2 = "handaxe", math.random(1,3) + + end + end + + if rnd == "hands" and isstring(owep) and owep == "sur_hammer" and self:HasWeapon(owep) then + rnd, rnd2 = "hammer", math.random(1,3) + end + + local movepos = 0 + local rotateang = 0 + local anim1, anim2 = "sur_killanim_evildead_"..rnd.."_0"..rnd2, "killmove_evildead_"..rnd.."_0"..rnd2 + local tr = self:GetEyeTrace().Entity + if IsValid(tr) and not tr.ExecutingTarget and tr.IsZombie and tr:GetPos():DistToSqr(self:GetPos()) < 10000 and tr:GetNWBool('flinching', false) and tr:Health() <= 200 then + local _, dur = self:LookupSequence(anim1) + self:SetSVAnimation(anim1, true, true, true) + self:Freeze(true) + self:GodEnable() + self:SetVelocity(-self:GetVelocity()) + self:SetRenderMode(10) + self.NoGrab = true + if !IsValid(self.LastPickupWeapon) then + self.LastPickupWeapon = self:GetActiveWeapon() + end + self:SetActiveWeapon(nil) + + local ent1 = ents.Create("sur_anim") + ent1:SetModel("models/surrounded/animations/evildead/evildead_killer_nmrih.mdl") + ent1:SetPos(self:GetPos()+self:GetForward()*movepos) + ent1:SetAngles(self:GetAngles()-Angle(0,rotateang,0)) + ent1:Spawn() + ent1:ResetSequence(anim2) + ent1.push = true + + local bd1 = ents.Create("sur_anim") + SuR:TransferModelData(self, bd1) + bd1:SetPos(self:GetPos()) + bd1:SetParent(ent1) + bd1:AddEffects(1) + bd1:Spawn() + ent1:DeleteOnRemove(bd1) + self:SetNWEntity("CameraEnt", bd1) + + local ent = ents.Create("sur_anim") + ent:SetModel("models/surrounded/animations/evildead/evildead_killed_nmrih.mdl") + ent:SetPos(self:GetPos()+self:GetForward()*movepos) + ent:SetAngles(self:GetAngles()-Angle(0,rotateang,0)) + ent:Spawn() + ent:ResetSequence(anim2) + + local bd = ents.Create("sur_anim") + SuR:TransferModelData(tr, bd) + bd:SetPos(self:GetPos()) + bd:SetParent(ent) + bd:AddEffects(1) + bd:Spawn() + ent:DeleteOnRemove(bd) + + local long1 = select(2, ent:LookupSequence(anim2)) + effects_takedown(self, ent, anim2) + + tr:Remove() + timer.Simple(long1, function() + if IsValid(ent) then + SuR:TransferBones(ent, bd, true) + end + if IsValid(self) then + net.Start("SuR.KillStatus") + net.WriteBool(true) + net.Send(self) + self:AddXP(SuR.Config.XP_Giving["execution"]) + self:PlayVoiceLine("enemydown", 50) + end + end) + + timer.Simple(dur-0.1, function() + if IsValid(ent1) and IsValid(self) then + local bone = ent1:LookupBone("root") or ent1:LookupBone("ValveBiped.Bip01_Pelvis") + local pos = ent1:GetBonePosition(bone) + if IsValid(self) then + pos.z = self:GetPos().z+4 + local bool = self:CheckHitbox(pos) + if bool then + self:SetPos(pos) + end + end + end + end) + + timer.Simple(dur, function() + if IsValid(self) then + self:Freeze(false) + self:GodDisable() + self:SetRenderMode(0) + self.NoGrab = false + self:SetNWEntity("CameraEnt", NULL) + if IsValid(self.LastPickupWeapon) then + local class = self.LastPickupWeapon:GetClass() + self:SelectWeapon(class) + self.LastPickupWeapon = nil + end + end + if IsValid(ent1) then + ent1:Remove() + end + end) + end +end + +local function AbilityTakedown(self, ent, amod, vmod, anim, vanim, playerpos) + if self.ExecutingTarget or ent.ExecutingTarget or ent.Grabbed then return end + + local yaw = 0 + local movex = 0 + local movey = 0 + local animv = anim + if isstring(vanim) then + animv = vanim + end + if anim == "killmove_giant_front" then + yaw = 90 + elseif anim == "killmove_giant_front_unused" or anim == "killmove_giant_backstomp" or anim == "killmove_giant_back" or anim == "killmove_slasher_back" then + yaw = 180 + end + + local angz = self:GetAngles():SnapTo("y", 45) + local posz = ent:GetPos() + if playerpos then + angz = ent:GetAngles():SnapTo("y", 45) + yaw = 180 + end + local isnpc = ent:IsNPC() + + local ent1 = ents.Create("sur_anim") + ent1.ent = self + ent1.enable_ent = true + ent1:SetModel(amod) + ent1:SetPos(posz-Vector(0,0,0)) + ent1:SetAngles(angz) + ent1:Spawn() + ent1:ResetSequence(anim) + ent1:ResetSequenceInfo() + ent1:SetCycle(0) + + local bd = ents.Create("base_anim") + SuR:TransferModelData(self, bd) + bd:SetPos(posz-Vector(0,0,0)) + bd:SetParent(ent1) + bd:AddEffects(1) + bd:Spawn() + + local ent2 = ent + if isnpc then + ent2 = ents.Create("sur_anim") + ent2:SetModel(vmod) + ent2:SetPos(posz-Vector(0,0,0)) + ent2:SetAngles(angz+Angle(0,yaw,0)) + ent2:Spawn() + ent2:ResetSequence(animv) + ent2:ResetSequenceInfo() + ent2:SetCycle(0) + + local bd2 = ents.Create("base_anim") + SuR:TransferModelData(ent, bd2) + bd2:SetPos(posz) + bd2:SetParent(ent2) + bd2:AddEffects(1) + bd2:Spawn() + ent2.bd = bd2 + end + + if ent:IsPlayer() then + ent2 = ent + end + effects_takedown(ent1, ent2, anim) + + self:RemoveAllDecals() + self:AddEFlags(EFL_NO_THINK_FUNCTION) + self:SetMaterial("null") + self:SetNoDraw(true) + self:SetVelocity(-self:GetVelocity()) + self.ExecutingPos = posz + self:SetPos(posz) + self:SetAngles(angz) + self.ExecutingTarget = true + self.ExecutingModel = ent1 + for i, ent in ipairs(self:GetChildren()) do + ent:SetMaterial("null") + end + timer.Simple(ent1:SequenceDuration(ent1:LookupSequence(anim)), function() + if IsValid(ent1) then + ent1:Remove() + end + if IsValid(self) then + self:RemoveEFlags(EFL_NO_THINK_FUNCTION) + self:SetNoDraw(false) + self:SetMaterial("") + self.ExecutingTarget = false + self:SetState() + self:SetPos(posz) + for i, ent in ipairs(self:GetChildren()) do + ent:SetMaterial("") + end + end + end) + + if not ent.ExecutingAttempt then + ent.ExecutingAttempt = 0 + end + if ent2:IsPlayer() then + animv = "sur_"..animv + end + local attempt = ent.ExecutingAttempt+1 + ent.ExecutingAttempt = attempt + + timer.Simple(ent2:SequenceDuration(ent2:LookupSequence(animv)), function() + if IsValid(ent2) and !ent2:IsPlayer() then + SuR:TransferBones(ent2, ent2.bd, true) + end + if IsValid(ent) and ent:IsPlayer() and ent.ExecutingTarget and ent.ExecutingAttempt == attempt then + ent:Freeze(false) + ent:GodDisable() + ent:SetNoTarget(false) + ent:Kill() + ent:SetNotSolid(false) + ent.ExecutingTarget = false + ent.ExecutingEnt = nil + end + end) + + if ent:IsPlayer() then + ent:Freeze(true) + ent:GodEnable() + ent:SetNoTarget(true) + ent:SetNotSolid(true) + ent:SetPos(posz) + ent:SetEyeAngles(angz+Angle(0,yaw+180,0)) + ent:SetVelocity(Vector(50,0,0)) + ent:SetSVAnimation(animv, true, true, true) + ent:SetActiveWeapon(nil) + ent.ExecutingEnt = self + ent.ExecutingPos = posz + ent.ExecutingTarget = true + ent.Grabbed = false + else + ent:Remove() + end +end + +local walker_tab = {"killmove_johnny_01", "killmove_cook_01", "killmove_cook_03", "killmove_hiker_01"} +local jumper_tab = {"killmove_giant_front_unused", "killmove_giant_front", "killmove_giant_ambush", "killmove_giant_back", "killmove_giant_backstomp"} +local berserk_tab = {"killmove_evildead_hands_01", "killmove_evildead_hands_02", "killmove_evildead_hands_03"} +local evil_tab = { + "killmove_evildead_shovel_01", + "killmove_evildead_shovel_02", + "killmove_evildead_shovel_03", + "killmove_evildead_machete_01", + "killmove_evildead_machete_02", + "killmove_evildead_machete_03", + "killmove_evildead_butcherknife_01", + "killmove_evildead_butcherknife_02", + "killmove_evildead_butcherknife_03", + "killmove_evildead_sword_01", + "killmove_evildead_sword_02", + "killmove_evildead_sword_03", + "killmove_evildead_mace_01", + "killmove_evildead_mace_02", + "killmove_evildead_mace_03", + "killmove_evildead_sledge_01", + "killmove_evildead_sledge_02", + "killmove_evildead_sledge_03", + "killmove_evildead_bat_01", + "killmove_evildead_bat_02", + "killmove_evildead_bat_03", + "killmove_evildead_knife_01", + "killmove_evildead_knife_02", + "killmove_evildead_knife_03", + "killmove_evildead_handaxe_01", + "killmove_evildead_handaxe_02", + "killmove_evildead_handaxe_03", + "killmove_evildead_axe_01", + "killmove_evildead_axe_02", + "killmove_evildead_axe_03", + "killmove_evildead_axe_04", + "killmove_evildead_hammer_01", + "killmove_evildead_hammer_02", + "killmove_evildead_hammer_03" +} + +function SuR:Takedown(att, tar, type) + local side = "front" + if tar:IsPlayer() then + side = tar.SideToEntity and tar:SideToEntity(att) or "front" + end + if type == "walker" then + AbilityTakedown(att, tar, "models/weapons/tcm_family.mdl", "models/tcm_victim.mdl", table.Random(walker_tab)) + elseif type == "berserk" then + AbilityTakedown(att, tar, "models/surrounded/animations/evildead/evildead_killer.mdl", "models/surrounded/animations/evildead/evildead_killed.mdl", table.Random(berserk_tab)) + elseif type == "jumper" then + AbilityTakedown(att, tar, "models/weapons/slasher_executions.mdl", "models/slasher_victim.mdl", table.Random(jumper_tab)) + elseif type == "chainsaw" then + AbilityTakedown(att, tar, "models/weapons/tcm_family.mdl", "models/tcm_victim.mdl", "killmove_leatherface_0"..math.random(1,2)) + elseif type == "downed_guitar" then + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", "executions_smashupguitar_killer_"..side, "executions_smashupguitar_victim_"..side, true) + elseif type == "downed_gas" then + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", "executions_forcefeed_killer_"..side, "executions_forcefeed_victim_"..side, true) + elseif type == "downed_electro" then + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", "executions_electricpoke_killer_"..side, "executions_electricpoke_victim_"..side, true) + elseif type == "downed_acid" then + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", "executions_brainscrambleacid_killer_"..side, "executions_brainscrambleacid_victim_"..side, true) + elseif type == "downed_big" then + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", "executions_berserkergutting_killer_"..side, "executions_berserkergutting_victim_"..side, true) + elseif type == "downed_unarmed" then + local rnd = math.random(1,4) + local a_anim, v_anim = "", "" + if rnd == 1 then + a_anim, v_anim = "executions_angrystrangler_killer_"..side, "executions_angrystrangler_victim_"..side + elseif rnd == 2 then + a_anim, v_anim = "executions_footschoke_killer_"..side, "executions_footschoke_victim_"..side + elseif rnd == 3 then + a_anim, v_anim = "executions_quietchoke_killer_"..side, "executions_quietchoke_victim_"..side + elseif rnd == 4 then + a_anim, v_anim = "executions_stampy_killer_"..side, "executions_stampy_victim_"..side + end + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", a_anim, v_anim, true) + elseif type == "downed_machete" then + local rnd = math.random(1,3) + local a_anim, v_anim = "", "" + if rnd == 1 then + a_anim, v_anim = "executions_gutting_killer_"..side, "executions_gutting_victim_"..side + elseif rnd == 2 then + a_anim, v_anim = "executions_knifeeat_killer_"..side, "executions_knifeeat_victim_"..side + elseif rnd == 3 then + a_anim, v_anim = "executions_stabcutthroat_killer_"..side, "executions_stabcutthroat_victim_"..side + end + AbilityTakedown(att, tar, "models/surrounded/test/trials_executions.mdl", "models/surrounded/test/trials_executions.mdl", a_anim, v_anim, true) + end +end + +local function check_height(ent) + local tr = util.TraceLine({ + start = ent:GetPos(), + endpos = ent:GetPos()-Vector(0,0,8), + filter = ent, + mask = MASK_SOLID, + }) + return tr.Hit +end + +hook.Add("EntityTakeDamage", "SuR_Executions", function(tar, dmg) + local att = dmg:GetAttacker() + if att:IsNPC() and check_height(tar) then + if not tar.NoGrab and att.IsZombie and table.HasValue(SuR.Config.Zombies_Executions["chainsaw"], att:GetClass()) and (tar:IsNPC() or tar:IsPlayer() and tar:IsSurvivor()) then + SuR:Takedown(att, tar, "chainsaw") + dmg:SetDamage(0) + return true + end + if not tar.NoGrab and att.IsZombie and !att.IsSpecial and not att.LNR_Crawler and (tar:IsNPC() or tar:IsPlayer() and tar:IsSurvivor() and !tar:IsDowned()) and (tar:Health() <= dmg:GetDamage()) and (tar:IsPlayer() and SuR:CurrentFighters() == 1 and tar:GetNWFloat('SelfRevive') <= 0 or tar:Health() <= dmg:GetDamage() and tar:IsNPC()) then + SuR:Takedown(att, tar, "walker") + dmg:SetDamage(0) + return true + end + if not tar.NoGrab and att.IsZombie and table.HasValue(SuR.Config.Zombies_Executions["berserk"], att:GetClass()) and (tar:IsNPC() or tar:IsPlayer() and tar:IsSurvivor()) and (tar:Health() <= dmg:GetDamage() and tar:IsNPC()) then + SuR:Takedown(att, tar, "berserk") + dmg:SetDamage(0) + return true + end + if not tar.NoGrab and att.IsZombie and table.HasValue(SuR.Config.Zombies_Executions["jumper"], att:GetClass()) and (tar:IsNPC() or tar:IsPlayer() and tar:IsSurvivor()) and (tar:Health() <= dmg:GetDamage()) then + SuR:Takedown(att, tar, "jumper") + dmg:SetDamage(0) + return true + end + if not tar.NoGrab and att.IsZombie and not att.LNR_Crawler and tar:IsPlayer() and tar:IsSurvivor() and tar:IsDowned() and !tar:IsFlagSet(FL_NOTARGET) and att:GetPos():DistToSqr(tar:GetPos()) < 20000 then + local id = "" + if table.HasValue(SuR.Config.Zombies_Executions["downed_machete"], att:GetClass()) then + id = "downed_machete" + elseif table.HasValue(SuR.Config.Zombies_Executions["downed_electro"], att:GetClass()) then + id = "downed_electro" + elseif table.HasValue(SuR.Config.Zombies_Executions["downed_guitar"], att:GetClass()) then + id = "downed_guitar" + elseif table.HasValue(SuR.Config.Zombies_Executions["downed_gas"], att:GetClass()) then + id = "downed_gas" + elseif table.HasValue(SuR.Config.Zombies_Executions["downed_big"], att:GetClass()) then + id = "downed_big" + elseif table.HasValue(SuR.Config.Zombies_Executions["downed_acid"], att:GetClass()) then + id = "downed_acid" + elseif !att.IsSpecial or table.HasValue(SuR.Config.Zombies_Executions["downed_unarmed"], att:GetClass()) then + id = "downed_unarmed" + end + if id != "" then + SuR:Takedown(att, tar, id) + dmg:SetDamage(0) + return true + end + end + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_exfil.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_exfil.lua new file mode 100644 index 0000000..1f0c8c8 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_exfil.lua @@ -0,0 +1,132 @@ +function SuR:StartExfil() + hook.Call("SuR.ExfilStarted", nil, SuR.Current_Wave) + local ptab = SuR.Config.Exfil_Points + if !SuR.Game_Started or !SuR.Wave_Started or #ptab == 0 or SuR.Config.Exfil_Wave > SuR.Current_Wave or SuR.ExfilWave or SuR.Config.Objective_Mode then return end + + SuR.ExfilWave = true + + local point = table.Random(ptab) + + net.Start("SuR.ExfilIcon") + net.WriteBool(false) + net.Broadcast() + + SuR:MessageOnClient(13) + SuR:ShowTips("evac") + timer.Simple(1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/helidepart_0"..math.random(1,3)..".mp3") + end) + + timer.Create("ExfilLine1", 60, 1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/heli60_0"..math.random(1,3)..".mp3") + end) + + timer.Create("ExfilLine2", 90, 1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/heli30_0"..math.random(1,3)..".mp3") + end) + + timer.Create("ExfilStart", 120, 1, function() + for _, ply in pairs(player.GetAll()) do + ply:SetJumpPower(240) + end + local he = ents.Create("sur_exfil_helo") + he.Points = point + he.WaitTime = 45 + he:Spawn() + hook.Call("SuR.ExfilHeliSpawned", nil, he) + SuR:SetMarker(point["Main"], player.GetAll(), "Evacuation") + end) +end + +function SuR:StartObjectiveExfil() + if !SuR.Game_Started or SuR.ExfilWave then return end + + hook.Call("SuR.ExfilStarted", nil, SuR.Current_Wave) + + net.Start("SuR.ExfilIcon") + net.WriteBool(false) + net.Broadcast() + + SuR:ShowTips("evac") + for _, ply in pairs(player.GetAll()) do + ply:SetJumpPower(240) + end + + local ptab = SuR.Config.Exfil_Points + local point = table.Random(ptab) + local he = ents.Create("sur_exfil_helo") + he.Points = point + he.WaitTime = 60 + he:Spawn() + hook.Call("SuR.ExfilHeliSpawned", nil, he) + SuR:SetMarker(point["Main"], player.GetAll(), "Evacuation Point") + timer.Simple(1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/helidepart_0"..math.random(1,3)..".mp3") + end) +end + +function SuR:StartGasExfil() + hook.Call("SuR.ExfilStarted", nil, SuR.Current_Wave) + local ptab = SuR.Config.Exfil_Points + if !SuR.Game_Started or !SuR.Wave_Started or #ptab == 0 or SuR.ExfilWave then return end + + SuR.ExfilWave = true + + local point = table.Random(ptab) + + SuR:ShowTips("evac") + timer.Simple(1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/gas"..math.random(1,4)..".mp3") + + local pos = nil + if #SuR.Config.Gas_SpawnPositions > 0 then + pos = table.Random(SuR.Config.Gas_SpawnPositions) + else + pos = SuR:GetRandomPos(false, 100, 10000) + if !isvector(pos) then + pos = SuR:GetRandomPos(true, 100, 10000) + end + end + if isvector(pos) then + local gas = ents.Create("sur_gas_zone") + gas:SetPos(pos) + gas.Dist = math.max(pos:Distance(point[3].pos)-200, 100) + gas:Spawn() + SuR.Gas_Entity = gas + end + end) + + timer.Create("ExfilLine1", 50, 1, function() + SuR:PlaySoundOnClient("surrounded/other/pilot1/heli30_0"..math.random(1,3)..".mp3") + end) + + timer.Create("ExfilLine2", 60, 1, function() + net.Start("SuR.ExfilIcon") + net.WriteBool(true) + net.Broadcast() + + SuR.DisableMusic = true + BroadcastLua([[SuR:PlayMusicOther(table.Random(SuR.Config.MusicWave["Countdown"]))]]) + SuR:SetMarker(point["Main"], player.GetAll(), "Last Exfil") + end) + + timer.Create("ExfilStart", 75, 1, function() + for _, ply in pairs(player.GetAll()) do + ply:SetJumpPower(240) + end + local he = ents.Create("sur_exfil_helo") + he.Points = point + he.WaitTime = 30 + he.LastExfil = true + he:Spawn() + hook.Call("SuR.ExfilHeliSpawned", nil, he) + end) +end + +function SuR:StopExfil() + SuR:Countdown(0) + SuR.ExfilWave = false + timer.Remove("ExfilLine1") + timer.Remove("ExfilLine2") + timer.Remove("ExfilStart") +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_functions.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_functions.lua new file mode 100644 index 0000000..665faea --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_functions.lua @@ -0,0 +1,1807 @@ +LootItems = { + { + id = 1, + name = "loot_pistol", + model = "models/Items/BoxSRounds.mdl", + chance = 50, + usefunc = function(self, ply) + ply:GiveAmmo(40, 3, true) + ply:GiveAmmo(20, 5, true) + end + }, + { + id = 2, + name = "loot_bucks", + model = "models/Items/BoxBuckshot.mdl", + chance = 25, + usefunc = function(self, ply) + ply:GiveAmmo(20, 7, true) + end + }, + { + id = 3, + name = "loot_smg", + model = "models/Items/BoxMRounds.mdl", + chance = 25, + usefunc = function(self, ply) + ply:GiveAmmo(90, 4, true) + end + }, + { + id = 4, + name = "loot_ar", + model = "models/Items/BoxMRounds.mdl", + chance = 25, + usefunc = function(self, ply) + ply:GiveAmmo(90, 1, true) + end + }, + { + id = 5, + name = "loot_sr", + model = "models/Items/BoxMRounds.mdl", + chance = 20, + usefunc = function(self, ply) + ply:GiveAmmo(20, 13, true) + ply:GiveAmmo(20, 14, true) + end + }, + { + id = 6, + name = "loot_radio", + tier = 4, + model = "models/surrounded/skilllem_radio.mdl", + chance = 4, + usefunc = function(self, ply) + ply:SetNWFloat('CanCallSupport', ply:GetNWFloat('CanCallSupport')+1) + SuR:PlaySoundOnClient("surrounded/other/radio/radiopick_0"..math.random(1,3)..".mp3", ply) + SuR:MessageOnClient(15, ply:Nick()) + SuR:ShowTips("radio", ply) + end + }, + { + id = 7, + name = "loot_antidote", + model = "models/props_lab/box01a.mdl", + chance = 15, + usefunc = function(self, ply) + ply:SetNWFloat('Sprays', ply:GetNWFloat('Sprays')+1) + end + }, + { + id = 8, + name = "loot_bandages", + model = "models/props_junk/cardboard_box004a.mdl", + chance = 20, + usefunc = function(self, ply) + ply:SetNWFloat('Bandages', ply:GetNWFloat('Bandages')+3) + end + }, + { + id = 9, + name = "loot_fak", + tier = 3, + model = "models/Items/HealthKit.mdl", + chance = 10, + usefunc = function(self, ply) + ply:SetNWFloat('Sprays', ply:GetNWFloat('Sprays')+2) + ply:SetNWFloat('Bandages', ply:GetNWFloat('Bandages')+6) + end + }, + { + id = 10, + name = "loot_gr", + tier = 3, + model = "models/weapons/w_missile_closed.mdl", + chance = 10, + usefunc = function(self, ply) + if ply:GetPlayerClass() == "demoman" and ply:GetLevelState() >= 2 then + ply:GiveAmmo(6, 8, true) + ply:GiveAmmo(12, 11, true) + else + ply:GiveAmmo(3, 8, true) + ply:GiveAmmo(6, 11, true) + end + end + }, + { + id = 11, + name = "loot_nails", + model = "models/Items/CrossbowRounds.mdl", + chance = 20, + usefunc = function(self, ply) + ply:SetNWFloat('buildercost', ply:GetNWFloat('buildercost')+3) + end + }, + { + id = 12, + name = "loot_selfrevive", + tier = 3, + model = "models/Items/battery.mdl", + chance = 10, + usefunc = function(self, ply) + ply:SetNWFloat('SelfRevive', ply:GetNWFloat('SelfRevive')+1) + end + }, + { + id = 13, + name = "loot_ammocrate", + tier = 3, + model = "models/Items/item_item_crate.mdl", + chance = 4, + usefunc = function(self, ply) + ply:GiveAmmo(80, 3, true) + ply:GiveAmmo(40, 5, true) + ply:GiveAmmo(3, 8, true) + ply:GiveAmmo(6, 11, true) + ply:GiveAmmo(40, 13, true) + ply:GiveAmmo(40, 14, true) + ply:GiveAmmo(180, 1, true) + ply:GiveAmmo(180, 4, true) + ply:GiveAmmo(40, 7, true) + end + }, + { + id = 14, + name = "loot_capsule", + tier = 5, + model = "models/maxofs2d/hover_rings.mdl", + chance = 1, + usefunc = function(self, ply) + ply:AddXP(SuR.Config.XP_Giving["capsule_item"]) + ply:EmitSound("buttons/combine_button_locked.wav") + + local wep = ents.Create("sur_loot") + wep.LootType = math.random(1,13) + wep:SetPos(self:WorldSpaceCenter()) + wep:Spawn() + end + }, + { + id = 15, + name = "loot_grenades", + tier = 3, + model = "models/Items/item_item_crate.mdl", + chance = 4, + usefunc = function(self, ply) + ply:SetNWInt('Grenades', ply:GetNWInt('Grenades')+6) + end + }, + { + id = 16, + name = "loot_money", + model = "models/surrounded/equipment/small blue cash bundle.mdl", + chance = 20, + usefunc = function(self, ply) + ply:SetNWInt('Money', ply:GetNWInt('Money')+25) + end + }, +} + +local meta = FindMetaTable('Player') + +local files = file.Find("surrounded/scripts/*", "LUA") +if istable(files) and #files > 0 then + for k, f in pairs(files) do + local scr = file.Read("surrounded/scripts/"..f, "LUA") + RunString(scr) + net.Start("SuR.ClientRunString") + net.WriteString(scr) + net.Broadcast() + MsgC(Color(200,200,20), "[Surrounded] ", Color(250,250,250), "surrounded/scripts/"..f.." has been loaded!\n") + end +end + +local config = file.Read("surrounded/"..game.GetMap()..".lua", "LUA") +if config then + RunString(config) + net.Start("SuR.ClientRunString") + net.WriteString(config) + net.Broadcast() +else + hook.Add("Think", "SuR_BlockConfig", function() + SuR:SendDataToClient("GameplayBlockConfig", true) + SuR.Game_Started = false + SuR.DeployTime = CurTime()+SuR.Config.Delay_Before_Deploy + end) +end + +function SuR:FindSpawnPositions(pos, dist, attempts) + attempts = attempts or 5 + local try = 0 + local spawnPositions = {} + while try < attempts and #spawnPositions <= 0 do + try = try + 1 + + local trace = {} + trace.start = pos + trace.mask = MASK_PLAYERSOLID + trace.filter = function(ent) + if ent:IsPlayer() or ent:IsNPC() then + return false + end + end + + trace.endpos = pos - Vector(0, 0, 1000) + local result = util.TraceLine(trace) + + if result.Hit then + local floorPos = result.HitPos + + trace.start = floorPos + trace.endpos = floorPos + Vector(0, 0, 1000) + result = util.TraceLine(trace) + + if result.Hit then + local ceilingPos = result.HitPos + + for i = 0, 360 do + local offset = Vector(math.random(-dist, dist), math.random(-dist, dist), 0) + local spawnPos = ceilingPos + offset + + trace.start = spawnPos + trace.endpos = spawnPos - Vector(0, 0, 1000) + result = util.TraceLine(trace) + + if result.Hit then + debugoverlay.Line(ceilingPos, result.HitPos, 45, Color( 255, 255, 255 ), true) + + if result.HitPos.z-pos.z >= SuR.Config.Loot_HeightLimit then + local visible = false + local tab = player.GetAll() + for i=1,#tab do + local ply = tab[i] + if ply:Alive() and ply:VisibleVec(result.HitPos) then + visible = true + break + end + end + + if visible then continue end + + table.insert(spawnPositions, result.HitPos) + end + end + end + end + end + end + + return table.Random(spawnPositions) +end + +function SuR:InfectPlayer(ply) + if ply:GetNWBool("IsInfected") or !ply:Alive() then return end + ply:SetNWBool("IsInfected", true) + timer.Simple(math.random(15,45), function() + if IsValid(ply) and ply:GetNWBool("IsInfected") then + timer.Create("InfectionProgress" .. ply:EntIndex(), 1, 0, function() + if IsValid(ply) and ply:GetNWBool("IsInfected") and ply:Alive() then + if math.random(1,10) == 1 then + ply:PlayVoiceLine("infected") + BroadcastLua([[ + local tab = {ACT_FLINCH_HEAD, ACT_FLINCH_STOMACH, ACT_FLINCH_PHYSICS} + Entity(]]..ply:EntIndex()..[[):AnimRestartGesture(6, tab[math.random(1,#tab)], true) + ]]) + end + ply:SetNWFloat('InfectionProgress', ply:GetInfection() + 0.01) + if ply:GetInfection() >= 1 then + ply:SuR_MakeZombie() + end + else + timer.Remove("InfectionProgress" .. ply:EntIndex()) + SuR:StopInfection(ply) + end + end) + end + end) +end + +function SuR:StopInfection(ply) + if !IsValid(ply) then return end + if ply:GetNWBool("IsInfected") then + timer.Remove("InfectionProgress" .. ply:EntIndex()) + ply:SetNWBool("IsInfected", false) + ply:SetNWFloat('InfectionProgress', 0) + end +end + +function SuR:DeleteLogic() + for _, ent in ipairs(ents.GetAll()) do + if ent:GetClass() == "func_tracktrain" or ent:GetClass() == "func_train" or ent:GetClass() == "func_tanktrain" or ent:GetClass() == "env_fade" or ent:GetClass() == "env_shake" or string.match(ent:GetClass(), "trigger_") then + ent:Remove() + elseif ent:GetClass() == "ambient_generic" then + ent:Fire("StopSound") + ent:Remove() + end + end +end + +function SuR:DeleteItems() + for _, ent in ipairs(ents.GetAll()) do + if ent:IsWeapon() or ent:IsNPC() or string.match(ent:GetClass(), "item_") then + ent:Remove() + end + end +end + +function SuR:TransferModelData(base, model) + local ent1Model = base:GetModel() + local ent1Skin = base:GetSkin() + local ent1BodyGroups = base:GetNumBodyGroups() + model:SetModel(ent1Model) + model:SetSkin(ent1Skin) + for i = 0, ent1BodyGroups - 1 do + model:SetBodygroup(i, base:GetBodygroup(i)) + end +end + +function SuR:TransferBoneData(base, ragdoll) + if !IsValid( base ) or !IsValid( ragdoll ) then return end + for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do + local bone = ragdoll:GetPhysicsObjectNum( i ) + if ( IsValid( bone ) ) then + local pos, ang = base:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) ) + if ( pos ) then bone:SetPos( pos ) end + if ( ang ) then bone:SetAngles( ang ) end + end + end +end + +function SuR:CallSupport(ply, float) + local tab = SuR.Config.Support_SpawnPositions + local pos = tab[math.random(1,#tab)] + if isvector(pos) then + if float == 1 then + if IsValid(ply) then + SuR:SetMarker(pos+Vector(0,0,128), ply, "Supply") + end + + SuR:PlaySoundOnClient("surrounded/other/radio/radiosupply_0"..math.random(1,3)..".mp3", ply, 3) + + timer.Simple(20, function() + local ent = ents.Create("prop_dynamic") + ent:SetModel("models/surrounded/mh53.mdl") + ent:SetPos(pos) + ent:SetAngles(Angle(0,math.random(-180,180),0)) + ent:Spawn() + ent:ResetSequence("yes") + + SuR:PlaySoundOnClient("surrounded/other/support_heli.mp3") + + timer.Simple(8, function() + if !IsValid(ent) then return end + + local tr = util.TraceLine({ + start = pos, + endpos = pos+Vector(0,0,1300), + mask = MASK_SOLID_BRUSHONLY + }) + + local ent = ents.Create("sur_resupply") + ent:SetPos(tr.HitPos-Vector(0,0,32)) + ent:Spawn() + end) + + timer.Simple(15, function() + if !IsValid(ent) then return end + + ent:Remove() + end) + end) + + SuR:MessageOnClient(9) + elseif float == 2 then + ply:Give("sur_artillery_strike") + ply:SelectWeapon("sur_artillery_strike") + SuR:MessageOnClient(7) + SuR:PlaySoundOnClient("surrounded/other/radio/radioshelling_0"..math.random(1,3)..".mp3", ply, 3) + elseif float == 3 then + if IsValid(ply) then + SuR:SetMarker(pos+Vector(0,0,128), ply, "Reinforcement") + end + for _, ply in ipairs(player.GetAll()) do + if !ply:Alive() then + ply.AllowSpawn = true + ply:Spawn() + ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0) + end + end + local ent = ents.Create("sur_npc_infil") + ent:SetPos(pos) + ent:SetAngles(Angle(0,math.random(-180,180),0)) + ent:Spawn() + SuR:MessageOnClient(6) + SuR:PlaySoundOnClient("surrounded/other/radio/radioreinforce_0"..math.random(1,3)..".mp3", ply, 3) + elseif float == 4 then + if IsValid(ply) then + SuR:SetMarker(pos+Vector(0,0,128), ply, "Bait") + end + SuR:PlaySoundOnClient("surrounded/other/radio/radiobait_0"..math.random(1,3)..".mp3", ply, 3) + + timer.Simple(7, function() + local ent = ents.Create("prop_dynamic") + ent:SetModel("models/surrounded/mh53.mdl") + ent:SetPos(pos) + ent:SetAngles(Angle(0,math.random(-180,180),0)) + ent:Spawn() + ent:ResetSequence("yes") + + SuR:PlaySoundOnClient("surrounded/other/support_heli.mp3") + + timer.Simple(15, function() + if !IsValid(ent) then return end + + ent:Remove() + end) + + timer.Simple(8, function() + for _, ply in ipairs(player.GetAll()) do + ply:SetNoTarget(true) + end + timer.Create("RemoveNoTarget", 30, 1, function() + for _, ply in ipairs(player.GetAll()) do + ply:SetNoTarget(false) + end + end) + timer.Create("RemoveNoTarget"..ply:EntIndex(), 1, 30, function() + for _, npc in ipairs(ents.FindByClass("npc_vj_*")) do + npc:SetLastPosition(pos) + npc:VJ_TASK_GOTO_LASTPOS() + end + end) + + if !IsValid(ent) then return end + + local tr = util.TraceLine({ + start = pos, + endpos = pos+Vector(0,0,1300), + mask = MASK_SOLID_BRUSHONLY + }) + + local ent = ents.Create("prop_ragdoll") + ent:SetCollisionGroup(COLLISION_GROUP_DEBRIS) + ent:SetModel("models/Humans/Charple04.mdl") + ent:SetPos(tr.HitPos-Vector(0,0,64)) + ent:Spawn() + SafeRemoveEntityDelayed(ent, 30) + end) + end) + + SuR:MessageOnClient(8) + elseif float == 5 then + if IsValid(ply) then + SuR:SetMarker(pos+Vector(0,0,128), ply, "Gunner") + end + timer.Simple(25, function() + local ent = ents.Create("sur_mi24") + ent:SetPos(pos) + ent:SetAngles(Angle(0,math.random(-180,180),0)) + ent:Spawn() + end) + SuR:PlaySoundOnClient("surrounded/other/radio/radiogunner_0"..math.random(1,3)..".mp3", ply, 3) + SuR:MessageOnClient(10) + elseif float == 6 then + timer.Simple(2, function() + if !SuR.Game_Started or !SuR.Wave_Started or SuR.Config.Exfil_Wave > SuR.Current_Wave then return end + SuR:StartExfil() + end) + elseif float == 7 then + ply:SetNWFloat('CanCallSupport', ply:GetNWFloat('CanCallSupport')+1) + ply:SendLua([[SuR:OpenBuyMenu()]]) + end + end +end + +function SuR:SendDataToClient(string, value, delay) + if delay then + timer.Simple(delay, function() + net.Start("SuR.SendDataToClient") + net.WriteString(string) + net.WriteTable({value}) + net.Broadcast() + end) + else + net.Start("SuR.SendDataToClient") + net.WriteString(string) + net.WriteTable({value}) + net.Broadcast() + end +end + +function SuR:SetMarker(pos, ply, text) + if not text then + text = "" + end + net.Start("SuR.PointMarker") + net.WriteVector(pos) + net.WriteString(text) + if ply then + net.Send(ply) + else + net.Broadcast() + end +end + +function SuR:ShowTips(type, ply) + net.Start("SuR.ShowTips") + net.WriteString(type) + if ply then + net.Send(ply) + else + net.Broadcast() + end +end + +function SuR:MessageOnClient(f, extra, ply) + net.Start("SuR.MessageOnClient") + net.WriteFloat(f) + net.WriteTable({extra}) + if ply then + net.Send(ply) + else + net.Broadcast() + end +end + +function SuR:PlaySoundOnClient(string, ply, delay) + delay = delay or 0 + timer.Simple(delay, function() + net.Start("SuR.PlaySoundOnClient") + net.WriteString(string) + if ply then + net.Send(ply) + else + net.Broadcast() + end + end) +end + +function SuR:Countdown(num) + net.Start("SuR.Countdown") + net.WriteFloat(num) + net.Broadcast() +end + +function SuR:ShowDeployCutscene(ply, bool) + if not SuR.Config.Deploy_Cutscene.cam then return end + net.Start("SuR.DeployCutscene") + net.WriteBool(bool) + net.Send(ply) + + if !istable(ply) then + ply = {ply} + end + for k, v in pairs(ply) do + if v:Alive() then continue end + v:SetPos(SuR.Config.Deploy_Cutscene.cam[#SuR.Config.Deploy_Cutscene.cam].pos) + end +end + +function SuR:SpawnTierWeapon(tier, pos) + local weapon = table.Random(SuR.Config.TierWeapons["Melee"]) + if tier == 1 then + weapon = table.Random(SuR.Config.TierWeapons["Tier1"]) + elseif tier == 2 then + weapon = table.Random(SuR.Config.TierWeapons["Tier2"]) + elseif tier == 3 then + weapon = table.Random(SuR.Config.TierWeapons["Tier3"]) + elseif tier == 4 then + weapon = table.Random(SuR.Config.TierWeapons["Tier4"]) + elseif tier == 5 then + weapon = table.Random(SuR.Config.TierWeapons["Tier5"]) + end + + if isvector(pos) then + local wep = ents.Create(weapon) + wep:SetPos(pos) + wep:SetAngles(AngleRand()) + wep:Spawn() + return wep + elseif IsEntity(pos) and pos:IsPlayer() then + local wep = pos:Give(weapon) + return wep + end +end + +function SuR:GiveRandomTableWithChance(tab, extra) + local totalChance = 0 + local tab2 = table.Copy(tab) + local t = {} + if isfunction(extra) then + for i, subtable in pairs(tab2) do + if extra(subtable) then + table.insert(t, subtable) + end + end + else + t = table.Copy(tab2) + end + + if #t == 0 then return end + + for _, subtable in pairs(t) do + totalChance = totalChance + subtable.chance + end + + local randomValue = math.random(totalChance) + local currentChance = 0 + for i, subtable in pairs(t) do + currentChance = currentChance + subtable.chance + if randomValue <= currentChance then + return subtable, i + end + end +end + +function SuR:EnablePropDamage() + for _, ent in ipairs(ents.FindByClass("prop_physics*")) do + local phys = ent:GetPhysicsObject() + if ent:GetMoveType() == MOVETYPE_VPHYSICS and IsValid(phys) then + ent:SetHealth(phys:GetMass()*5) + ent:SetMaxHealth(phys:GetMass()*5) + ent.PropDestroyable = true + end + end +end + +hook.Add("EntityTakeDamage", "EnablePropDamageSuR", function(ent, dmg) + if ent.PropDestroyable then + local new_health = ent:Health() - dmg:GetDamage() + ent:SetHealth(new_health) + + if new_health <= 0 then + ent:EmitSound("physics/metal/metal_box_break"..math.random(1,2)..".wav") + ent:Remove() + end + end +end) + +hook.Add("Think", "EnablePropDamageSuR", function() + for _, npc in ipairs(ents.FindByClass("*lnr*")) do + if !npc.IsZombie then continue end + + local trace = util.TraceHull({ + start = npc:GetPos()+ npc:GetForward() * 32, + endpos = npc:GetPos() + npc:GetForward() * 32, + filter = function(ent) + if ent:GetClass():find("prop_physics") then + return true + elseif ent:IsNPC() or ent:IsPlayer() then + return false + else + return ent:IsWorld() == false + end + end, + mins = npc:OBBMins(), + maxs = npc:OBBMaxs(), + }) + if trace.Hit then + local phys = trace.Entity:GetPhysicsObject() + if trace.Entity:GetClass():find("prop_physics") and IsValid(phys) and phys:IsMotionEnabled() then + if phys:GetMass() <= 400 then + phys:AddVelocity(npc:GetForward()*16) + end + trace.Entity:TakeDamage(1) + end + end + end +end) + +function meta:SideToEntity(ent2) + local vec = (ent2:GetPos() - self:GetPos()):GetNormal():Angle().y + local targetAngle = self:GetAngles().y + if targetAngle > 360 then + targetAngle = targetAngle - 360 + end + if targetAngle < 0 then + targetAngle = targetAngle + 360 + end + + local angleAround = vec - targetAngle + if angleAround > 360 then + angleAround = angleAround - 360 + end + if angleAround < 0 then + angleAround = angleAround + 360 + end + + if angleAround <= 45 or angleAround > 315 then + return "front" + end + if angleAround > 45 and angleAround <= 135 then + return "left" + end + if angleAround > 135 and angleAround <= 225 then + return "back" + end + if angleAround > 225 and angleAround <= 315 then + return "right" + end +end + +function meta:DropButtons() + self:ConCommand("-forward") + self:ConCommand("-back") + self:ConCommand("-moveright") + self:ConCommand("-moveleft") +end + +function meta:SetSVAnimation(anim, autostop, stopmove, cutscene, loop) + self:SetNWString('SVAnim', anim) + self:SetNWFloat('SVAnimDelay', select(2, self:LookupSequence(anim))) + self:SetNWFloat('SVAnimStartTime', CurTime()) + self:SetCycle(0) + if loop and not autostop then + self:SetNWBool('SVAnimLoop', true) + else + self:SetNWBool('SVAnimLoop', false) + end + if not stopmove then + stopmove = false + end + self:SetNWBool('SVAnimStopMoving', stopmove) + if not cutscene then + cutscene = false + else + self:ConCommand("-attack") + self:ConCommand("-attack2") + end + self:SetNWBool('SVAnimStopCutscene', cutscene) + if autostop then + local delay = select(2, self:LookupSequence(anim)) + timer.Simple(delay, function() + if !IsValid(self) then return end + + local anim2 = self:GetNWString('SVAnim') + + if anim == anim2 then + self:SetSVAnimation("") + end + end) + timer.Simple(delay, function() + if !IsValid(self) then return end + + local anim2 = self:GetNWString('SVAnim') + + if anim == anim2 then + self:SetSVAnimation("") + end + end) + end +end + +function meta:PlayFastGesture(seq, isactivity) + local id = self:LookupSequence(seq) + if id == -1 and not isactivity then return end + + local ind = self:EntIndex() + if isactivity then + BroadcastLua([[ + Entity(]]..ind..[[):AnimRestartGesture(6, ]]..seq..[[, true) + ]]) + else + BroadcastLua([[ + Entity(]]..ind..[[):AddVCDSequenceToGestureSlot(6, ]]..id..[[, 0, true) + ]]) + end +end + +function meta:CheckReachingNPC() + if !SuR.Config.Enable_Out_Of_Bounds_Check or self:IsZombie() then return true end + if IsValid(ents.FindByClass("sur_exfil_helo")[1]) then return true end + local count_z, count_r = 0, 0 + local tab = ents.FindByClass("*vj*") + for i=1,#tab do + local ent = tab[i] + if !ent:IsNPC() then continue end + count_z = count_z + 1 + if !ent:IsUnreachable(self) then + count_r = count_r + 1 + end + end + return count_r > count_z-count_r or count_z == 0 +end + +hook.Add("PlayerButtonDown", "SuR_ButtonHook", function(ply, but) + if but == KEY_F4 then + ply:SendLua([[SuR:OpenAdminMenu()]]) + end + if but == KEY_F1 and ply:IsSurvivor() then + ply:SendLua([[SuR:OpenDropMenu()]]) + elseif but == KEY_F1 and ply:IsZombie() then + ply:SendLua([[SuR:OpenClassMenu()]]) + end + + if ply:IsZombie() then return end + + if but == KEY_E and ply:IsDowned() then + ply:SuR_SelfRevive() + end + + if but == KEY_G then + ply:AbilityKick() + elseif but == KEY_E then + ply:AbilityTakedown() + elseif but == KEY_L then + ply:AbilityGrenade() + elseif but == KEY_V then + ply:AbilityVault() + elseif but == KEY_B then + local tr = util.TraceLine({ + start = ply:EyePos(), + endpos = ply:EyePos() + ply:GetAimVector() * 72, + filter = ply, + }) + if IsValid(tr.Entity) and tr.Entity:IsPlayer() and not tr.Entity:IsDowned() and tr.Entity:Health() < 100 then + ply:AbilityHealing(tr.Entity) + else + ply:AbilityHealing() + end + elseif but == KEY_H then + local tr = util.TraceLine({ + start = ply:EyePos(), + endpos = ply:EyePos() + ply:GetAimVector() * 72, + filter = ply, + }) + if IsValid(tr.Entity) and tr.Entity:IsPlayer() and not tr.Entity:IsDowned() and tr.Entity:GetNWBool("IsInfected") then + ply:AbilitySpray(tr.Entity) + else + ply:AbilitySpray() + end + elseif but == KEY_M then + ply:SendLua([[SuR:OpenRadioMenu()]]) + elseif but == KEY_1 then + ply:SelectWeapon(ply:GetNWString('MainWeapon')) + elseif but == KEY_2 then + ply:SelectWeapon(ply:GetNWString('SecWeapon')) + elseif but == KEY_3 then + ply:SelectWeapon(ply:GetNWString('MeleeWeapon')) + elseif but == KEY_4 then + ply:SelectWeapon(ply:GetNWString('OtherWeapon')) + elseif but == KEY_F2 then + ply:PlaceMark() + end +end) + +function meta:CreateDroppedWeapon(str) + local hwep = self:GetWeapon(str) + if str == SuR.Config.EmptyWeapon then return end + if !IsValid(hwep) then return end + + local tr = util.TraceLine( { + start = self:EyePos(), + endpos = self:EyePos() + self:GetAimVector() * 50, + filter = self, + mask = MASK_SOLID, + }) + + local clip1 = hwep:Clip1() + local ent = ents.Create("sur_loot") + ent.Weapon = { + name = hwep.PrintName, + class = str, + model = hwep.WorldModel, + usefunc = function(sel, self) + local weps = self:Give(str) + if IsValid(weps) then + self:RemoveAmmo(weps:Clip1()+weps.Primary.DefaultClip, weps:GetPrimaryAmmoType()) + weps:SetClip1(clip1) + end + end + } + ent:SetPos(tr.HitPos) + ent:Spawn() + ent.IsLoot = true + + self:StripWeapon(str) +end + +hook.Add("PlayerCanPickupWeapon", "SuR_Weapons", function(ply, weapon) + if ply:HasWeapon(weapon:GetClass()) then + return false + end +end) + +hook.Add("WeaponEquip", "SuR_Weapons", function(weapon, ply) + if table.HasValue(SuR.Config.SecondaryWeapons, weapon:GetClass()) then + local str = ply:GetNWString('SecWeapon') + ply:CreateDroppedWeapon(str) + ply:SetNWString('SecWeapon', weapon:GetClass()) + elseif table.HasValue(SuR.Config.TierWeapons["Melee"], weapon:GetClass()) then + local str = ply:GetNWString('MeleeWeapon') + if str == SuR.Config.EmptyWeapon then + ply:StripWeapon(str) + else + ply:CreateDroppedWeapon(str) + end + ply:SetNWString('MeleeWeapon', weapon:GetClass()) + elseif table.HasValue(SuR.Config.OtherWeapons, weapon:GetClass()) then + local str = ply:GetNWString('OtherWeapon') + ply:CreateDroppedWeapon(str) + ply:SetNWString('OtherWeapon', weapon:GetClass()) + elseif weapon:GetClass() != SuR.Config.EmptyWeapon then + local str = ply:GetNWString('MainWeapon') + ply:CreateDroppedWeapon(str) + ply:SetNWString('MainWeapon', weapon:GetClass()) + end +end) + +hook.Add("OnNPCKilled", "SuR_GameLogic", function(npc, att) + if npc.IsZombie and att:IsPlayer() then + net.Start("SuR.KillStatus") + net.WriteBool(false) + net.Send(att) + timer.Simple(0.2, function() + if !IsValid(att) then return end + + att:PlayVoiceLine("enemydown", 30) + end) + if (npc:GetClass() == "npc_vj_lnr_riot_shield" or npc:GetClass() == "npc_vj_lnr_riot") and math.random(1,2) == 1 then + local wep = ents.Create("sur_loot") + wep.LootType = 6 + wep:SetPos(npc:WorldSpaceCenter()) + wep:SetAngles(AngleRand()) + wep:Spawn() + end + if SuR.ActiveMutator == 1 and math.random(1,5) == 1 then + local gr = ents.Create("obj_vj_grenade") + gr:SetPos(npc:WorldSpaceCenter()) + gr:SetAngles(AngleRand()) + gr:Spawn() + elseif SuR.ActiveMutator == 9 and math.random(1,5) == 1 then + SuR:SpawnLoot(npc:WorldSpaceCenter()) + end + + local tab = SuR.Config.XP_Giving + if npc.IsBoss then + att:AddXP(tab["boss_kill"]) + elseif npc.IsSpecial then + att:AddXP(tab["special_kill"]) + else + att:AddXP(tab["zombie_kill"]) + end + end +end) + +hook.Add("EntityTakeDamage", "SuR_DamageHook", function(ent, dmg) + local dc = dmg:GetDamage() + local att = dmg:GetAttacker() + local hlt = ent:Health() + + if ent:IsPlayer() and (att:GetClass() == "obj_vj_grenade_sur" or att:GetClass() == "sur_landmine") then + return true + end + if ent:IsPlayer() and att:GetClass() == "sur_support_npc" or att:IsPlayer() and att:IsSurvivor() and ent:GetClass() == "sur_support_npc" then + return true + end + if att:IsPlayer() and att:IsZombie() and ent:IsNPC() and ent.IsZombie then + return true + end + + if ent:IsPlayer() and att:IsPlayer() and ent != att and ent:Team() == att:Team() then + ent:PlayVoiceLine("friendlyfire", 25) + return true + end + + if ent.IsZombie and att:IsPlayer() then + local inf = att:GetActiveWeapon() + if SuR.ActiveMutator == 5 and IsValid(inf) and inf:IsWeapon() and table.HasValue(SuR.Config.TierWeapons["Melee"], inf:GetClass()) then + dmg:SetDamage(ent:Health()) + end + if IsValid(inf) and inf:IsWeapon() and table.HasValue(SuR.Config.TierWeapons["Melee"], inf:GetClass()) then + if ent.IsVJBaseSNPC and ent:Health() < 400 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 + if not isnumber(animDur) or 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(), animDur, 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 + end + if att:GetPlayerClass() == "survivor" and att:GetLevelState() >= 5 and dmg:IsBulletDamage() then + dmg:ScaleDamage(1.3) + elseif att:GetPlayerClass() == "survivor" and att:GetLevelState() >= 4 and dmg:IsBulletDamage() then + dmg:ScaleDamage(1.2) + elseif att:GetPlayerClass() == "survivor" and att:GetLevelState() >= 3 and dmg:IsBulletDamage() then + dmg:ScaleDamage(1.1) + end + if dmg:IsBulletDamage() and IsValid(inf) and (inf:GetPrimaryAmmoType() == 13 or inf:GetPrimaryAmmoType() == 14) then + if att:GetPlayerClass() == "marksman" and att:GetLevelState() >= 5 then + dmg:ScaleDamage(2) + elseif att:GetPlayerClass() == "marksman" and att:GetLevelState() >= 3 then + dmg:ScaleDamage(1.5) + elseif att:GetPlayerClass() == "marksman" and att:GetLevelState() >= 2 then + dmg:ScaleDamage(1.25) + end + end + if IsValid(inf) and inf:IsWeapon() and table.HasValue(SuR.Config.TierWeapons["Melee"], inf:GetClass()) then + if att:GetPlayerClass() == "berserker" and att:GetLevelState() >= 5 then + dmg:ScaleDamage(3) + elseif att:GetPlayerClass() == "berserker" and att:GetLevelState() >= 3 then + dmg:ScaleDamage(2) + elseif att:GetPlayerClass() == "berserker" and att:GetLevelState() >= 1 then + dmg:ScaleDamage(1.5) + end + end + if dmg:IsExplosionDamage() then + if att:GetPlayerClass() == "demoman" and att:GetLevelState() >= 5 then + dmg:ScaleDamage(2) + elseif att:GetPlayerClass() == "demoman" and att:GetLevelState() >= 4 then + dmg:ScaleDamage(1.5) + end + end + end + + if ent:IsPlayer() and ent:IsZombie() and ent:Alive() then + ent:PlayVoiceLine("zombie_pain", 25) + return + end + + if ent:IsPlayer() and ent:Alive() then + if ent:GetPlayerClass() == "berserker" and ent:GetLevelState() >= 4 then + dmg:ScaleDamage(0.5) + end + if dmg:IsExplosionDamage() and ent:GetPlayerClass() == "demoman" and ent:GetLevelState() >= 1 then + dmg:ScaleDamage(0.1) + end + dc = dmg:GetDamage() + if dc < hlt and not ent:IsDowned() then + ent:PlayVoiceLine("pain", 50) + ent.VoiceLineDelay_LowHP = CurTime()+math.random(15,60) + if dmg:IsExplosionDamage() or dmg:IsFallDamage() or ((att:GetClass() == "npc_vj_lnr_brute" or att:IsPlayer() and att:IsZombie() and att.ZombieClass == "Brute") and math.random(1,2) == 1 or att:GetClass() == "npc_vj_lnr_tyrant" or att:GetClass() == "npc_vj_lnr_tank" or att:GetClass() == "npc_vj_lnr_titan_mini" or att:GetClass() == "npc_vj_lnr_fatso" and math.random(1,5) == 1) and att:GetPos():DistToSqr(ent:GetPos()) < 20000 then + ent:Stun(false, math.random(10,20)) + end + if (att.IsZombie and math.random(1,20) == 1 or SuR.ActiveMutator == 6) or ((att:GetClass() == "npc_vj_lnr_carrier" or att:IsPlayer() and att:IsZombie() and att.ZombieClass == "Carrier") and math.random(1,4) == 1) or (att:GetClass() == "npc_vj_lnr_shambler") then + SuR:InfectPlayer(ent) + end + else + if not ent:IsDowned() and not ent:HasGodMode() and SuR.ActiveMutator != 10 then + ent:SuR_Down() + return true + end + end + end +end) + +hook.Add("PlayerDeathSound", "SuR_CustomPlayerDeath", function(ply) + if ply:IsSurvivor() then + ply:PlayVoiceLine("death") + else + ply:PlayVoiceLine("zombie_death") + end + return true +end) + +hook.Add("PlayerDeath", "SuR_Think", function(ply, inf, att) + local rag = ents.Create("prop_ragdoll") + SuR:TransferModelData(ply, rag) + rag:SetPos(ply:GetPos()) + rag:Spawn() + rag:SetCollisionGroup(1) + SuR:TransferBoneData(ply, rag) + SafeRemoveEntityDelayed(rag, 120) + + if IsValid(ply:GetRagdollEntity()) then + ply:GetRagdollEntity():Remove() + end + + timer.Simple(0.01, function() + if !IsValid(ply) or !IsValid(rag) or ply:GetInfoNum("sur_viewmod_deathanims", 1) != 0 then return end + net.Start("SuR.DeathView") + net.WriteEntity(rag) + net.Send(ply) + end) + + if ply:IsDowned() or ply.ExecutingTarget then + ply:SuR_Revive(true) + ply:Freeze(false) + ply:SetSVAnimation("") + SuR:MessageOnClient(5, ply) + + local ent = SuR:PickRandomPlayer() + if IsValid(ent) then + ent:PlayVoiceLine("frienddied") + end + end + + if ply:IsZombie() then + if ply.ZombieClass == "Hazmat" and IsValid(att) and att != ply and math.random(1,4) == 1 then + ParticleEffect("vj_explosion2",ply:GetPos() + ply:GetUp()*48 + ply:GetForward()*1,Angle(0,0,0),nil) + ParticleEffect("vj_explosion1",ply:GetPos() + ply:GetUp()*15,Angle(0,0,0),nil) + ParticleEffect("vj_explosionfire2",ply:GetPos() + ply:GetUp()*20,Angle(0,0,0),nil) + ParticleEffect("vj_explosionfire1",ply:GetPos() + ply:GetUp()*20,Angle(0,0,0),nil) + util.ScreenShake(ply:GetPos(),100,200,1,2500) + util.VJ_SphereDamage(ply,ply,ply:GetPos(),250,75,DMG_BLAST,false,true,{Force=100}) + ply:EmitSound("ambient/explosions/explode_"..math.random(1,9)..".wav", 90) + end + return + end + if SuR.Config.Versus_Mode then + timer.Simple(0, function() ply:SetTeam(2) end) + end + + local str = ply:GetNWString('MainWeapon') + local hwep = ply:GetWeapon(str) + if IsValid(hwep) then + local ent = ents.Create("sur_loot") + ent.Weapon = { + name = hwep.PrintName, + class = str, + model = hwep.WorldModel, + usefunc = function(self, ply) + local weps = ply:Give(str) + if IsValid(weps) then + ply:RemoveAmmo(weps:Clip1()+weps.Primary.DefaultClip, weps:GetPrimaryAmmoType()) + end + end + } + ent:SetPos(ply:WorldSpaceCenter()) + ent:Spawn() + ent.IsLoot = true + end + + local str = ply:GetNWString('SecWeapon') + local hwep = ply:GetWeapon(str) + if IsValid(hwep) then + local ent = ents.Create("sur_loot") + ent.Weapon = { + name = hwep.PrintName, + class = str, + model = hwep.WorldModel, + usefunc = function(self, ply) + local weps = ply:Give(str) + if IsValid(weps) then + ply:RemoveAmmo(weps:Clip1()+weps.Primary.DefaultClip, weps:GetPrimaryAmmoType()) + end + end + } + ent:SetPos(ply:WorldSpaceCenter()) + ent:Spawn() + ent.IsLoot = true + end + + local str = ply:GetNWString('MeleeWeapon') + local hwep = ply:GetWeapon(str) + if IsValid(hwep) and str != SuR.Config.EmptyWeapon then + local ent = ents.Create("sur_loot") + ent.Weapon = { + name = hwep.PrintName, + class = str, + model = hwep.WorldModel, + usefunc = function(self, ply) + local weps = ply:Give(str) + if IsValid(weps) then + ply:RemoveAmmo(weps:Clip1()+weps.Primary.DefaultClip, weps:GetPrimaryAmmoType()) + end + end + } + ent:SetPos(ply:WorldSpaceCenter()) + ent:Spawn() + ent.IsLoot = true + end + + local str = ply:GetNWString('OtherWeapon') + local hwep = ply:GetWeapon(str) + if IsValid(hwep) then + local ent = ents.Create("sur_loot") + ent.Weapon = { + name = hwep.PrintName, + class = str, + model = hwep.WorldModel, + usefunc = function(self, ply) + local weps = ply:Give(str) + if IsValid(weps) then + ply:RemoveAmmo(weps:Clip1()+weps.Primary.DefaultClip, weps:GetPrimaryAmmoType()) + end + end + } + ent:SetPos(ply:WorldSpaceCenter()) + ent:Spawn() + ent.IsLoot = true + end +end) + +function meta:MovingDirection(threshold, sidethreshold) + threshold = threshold or 0.1 + sidethreshold = sidethreshold or 0.2 + local vel = self:GetVelocity() + local forward = self:GetForward() + local right = self:GetRight() + local forwardDot = vel:Dot(forward) + local rightDot = vel:Dot(right) + + if rightDot > sidethreshold then + return "right" + elseif rightDot < -sidethreshold then + return "left" + end + + if forwardDot > threshold then + return "forward" + elseif forwardDot < -threshold then + return "backward" + end + + return "stand" +end + +hook.Add("Think", "SuR_Think", function() + local tab = player.GetAll() + for i=1, #tab do + local ent = tab[i] + + if ent:Alive() and ent:GetInfoNum("sur_viewmod", 2) == 0 and !ent:GetNWBool("SVAnimStopCutscene") then + local num = 64 + local eyes = ent:LookupAttachment("eyes") + if eyes > 0 then + local att = ent:GetAttachment(eyes) + local dif = math.sqrt(att.Pos:DistToSqr(ent:GetPos())) + num = math.Clamp(dif, 8, 96) + end + ent:SetViewOffset(Vector(0, 0, ent.ViewOffsetZ)) + ent:SetViewOffsetDucked(Vector(0, 0, 36)) + ent.ViewOffsetZ = Lerp(FrameTime()/0.1, ent.ViewOffsetZ, num) + else + ent:SetViewOffset(Vector(0, 0, 64)) + ent:SetViewOffsetDucked(Vector(0, 0, 36)) + ent.ViewOffsetZ = 64 + end + + ent:SetNWString("MoveDirection", ent:MovingDirection()) + if ent:IsZombie() then + ent:SetNoTarget(true) + continue + end + + if ent.ExecutingTarget then + ent:SetPos(ent.ExecutingPos) + + local att = ent.ExecutingEnt + if !IsValid(att) or IsValid(att) and att:Health() <= 0 then + ent:Freeze(false) + ent:GodDisable() + timer.Simple(5, function() + if !IsValid(ent) then return end + ent:SetNoTarget(false) + end) + ent:SetNotSolid(false) + ent:SetSVAnimation("") + ent.ExecutingTarget = false + ent.ExecutingEnt = nil + ent.Grabbed = false + end + + if ent.Grabbed then + if ent:Health() <= 1 then + SuR:StopGrab(ent.ExecutingEnt, ent, true) + elseif not ent.GrabDamage or ent.GrabDamage < CurTime() then + ent.GrabDamage = CurTime()+0.1 + ent:SetHealth(ent:Health()-1) + ent:PlayVoiceLine("pain", 5) + end + end + end + + if ent:IsDowned() and ent:IsStunned(true) then + ent:SetSVAnimation("") + end + + local wep = ent:GetActiveWeapon() + if ent:Alive() and IsValid(wep) and ent:KeyDown(IN_RELOAD) and wep:GetMaxClip1() > 0 and wep:Clip1() < wep:GetMaxClip1() then + ent:PlayVoiceLine("reload", 50) + end + if ent:Alive() and IsValid(wep) and ent:KeyDown(IN_ATTACK) and wep:GetMaxClip1() > 0 and wep:Clip1() == 0 and ent:GetAmmoCount(wep:GetPrimaryAmmoType()) == 0 then + ent:PlayVoiceLine("noammo") + end + if IsValid(wep) and wep:GetHoldType() == "shotgun" then + wep:SetHoldType("rpg") + end + + if IsValid(wep) and ent:HasWeapon("sur_fuel") then + ent:SelectWeapon("sur_fuel") + end + + local tr1 = util.TraceLine({ + start = ent:GetPos(), + endpos = ent:GetPos() + ent:GetForward() * 32, + filter = ent, + mask = MASK_PLAYERSOLID + }) + + local tr2 = util.TraceLine({ + start = ent:EyePos(), + endpos = ent:EyePos() + ent:GetForward() * 32, + filter = ent, + mask = MASK_PLAYERSOLID + }) + + local tr3 = util.TraceHull({ + start = ent:GetPos() + ent:GetForward() * 60, + endpos = ent:GetPos() + ent:GetForward() * 60, + filter = ent, + mins = Vector( -16, -16, 0 ), + maxs = Vector( 16, 16, 72 ), + mask = MASK_PLAYERSOLID + }) + + ent:SetNWBool('CanVault', tr1.Hit and not tr2.Hit and not tr3.Hit) + ent:SetNWBool('CanHeal', ent:Alive() and ent:Health() < ent:GetMaxHealth() and ent:GetNWFloat("Bandages") > 0) + + if ent:Alive() and ent.VoiceLineDelay_EnemyBack < CurTime() then + local tab = ents.FindInSphere(ent:GetPos()-ent:GetForward()*128, 128) + for i=1,#tab do + local npc = tab[i] + if npc:IsNPC() and npc.IsZombie and ent:IsLineOfSightClear(npc) then + ent.VoiceLineDelay_EnemyBack = CurTime()+math.random(15,45) + ent:PlayVoiceLine("enemyback") + break + end + end + end + + if SuR.Config.Enable_Dangerous_Water then + local d = ent.WaterDamageDelay or 0 + if ent:Alive() and d < CurTime() and ent:WaterLevel() > 0 then + ent:TakeDamage(ent:WaterLevel()*5) + ent.WaterDamageDelay = CurTime()+1 + end + end + + if ent:Alive() and ent.VoiceLineDelay_EnemySpotted < CurTime() then + local tab = ents.FindInSphere(ent:GetEyeTrace().HitPos, 128) + for i=1,#tab do + local npc = tab[i] + if npc:IsNPC() and npc.IsZombie and ent:IsLineOfSightClear(npc) then + ent.VoiceLineDelay_EnemySpotted = CurTime()+math.random(20,60) + ent:PlayVoiceLine("enemyspotted") + break + end + end + end + + if !ent:CheckReachingNPC() and SuR:CurrentAliveEnemies()+SuR.Enemy_To_Spawn > 5 then + ent.ResetBuggedPos = CurTime()+5 + ent:SetNWFloat('BuggedPos', math.Clamp(ent:GetNWFloat('BuggedPos')+FrameTime()/10, 0, 1)) + end + + if ent:GetNWFloat('BuggedPos') >= 1 then + ent:SetNWFloat('BuggedPos', 0) + local pos = SuR:GetRandomPos(true, 0, 5000) + if !isvector(pos) then + pos = SuR:GetRandomPos(false, 0, 5000) + end + if isvector(pos) then + ent:ScreenFade(SCREENFADE.IN, color_black, 1, 1) + ent:SetPos(pos) + end + elseif !ent:Alive() or ent.ResetBuggedPos < CurTime() then + ent:SetNWFloat('BuggedPos', 0) + end + + if ent:Alive() and ent.VoiceLineDelay_LowHP < CurTime() and ent:Health() <= 50 then + ent.VoiceLineDelay_LowHP = CurTime()+math.random(10,30) + ent:PlayVoiceLine("lowhp", 75) + end + end +end) + +hook.Add("CanPlayerSuicide", "SuR_Disable", function(ply) + return SuR.Config.Enable_Suicide or ply:IsZombie() +end) + +hook.Add("PlayerDeathThink", "SuR_DeadSpawn", function(ply) + if (SuR.Game_Started and SuR.Wave_Started or !SuR.Game_Started) and ply:IsSurvivor() then + ply:Spectate(6) + return false + elseif (SuR.Game_Started and !SuR.Wave_Started or !SuR.Game_Started) and ply:IsZombie() then + ply:Spectate(6) + return false + end +end) + +hook.Add("PlayerUse", "SuR_ZombieBlock", function( ply, ent ) + if ply:IsZombie() then + return false + end +end) + +hook.Add("PlayerInitialSpawn", "SuR_InitialSpawn", function(ply) + ply:LoadLevelProgress() + ply:SetNWString("StartWeapon", SuR.Config.TierWeapons["Tier1"][1]) + ply:SetModel("models/player/Group03/male_0"..math.random(1,9)..".mdl") + ply:SetNWString("VoicePack", "Default [EN]") + if #SuR.Config.Allowed_PlayerModels > 0 then + ply:SetModel(SuR.Config.Allowed_PlayerModels[math.random(1,#SuR.Config.Allowed_PlayerModels)]) + end + if not SuR.Game_Started and SuR.DeployTime > CurTime()+10 and not SuR.DisableLogic then + timer.Simple(1, function() + if !IsValid(ply) then return end + SuR:ShowDeployCutscene(ply, true) + end) + end + + ------------------------------------ + + local config = file.Read("surrounded/"..game.GetMap()..".lua", "LUA") + if config then + net.Start("SuR.ClientRunString") + net.WriteString(config) + net.Send(ply) + end + + local files = file.Find("surrounded/scripts/*", "LUA") + if istable(files) and #files > 0 then + for k, f in pairs(files) do + local scr = file.Read("surrounded/scripts/"..f, "LUA") + net.Start("SuR.ClientRunString") + net.WriteString(scr) + net.Send(ply) + end + end +end) + +hook.Add("PlayerSpawn", "SuR_MainSpawn", function(ply) + if ply:Team() == 1001 and not SuR.Config.Versus_Mode then + ply:SetTeam(1) + elseif ply:Team() == 1001 and SuR.Game_Started and SuR.Config.Versus_Mode then + ply:SetTeam(2) + end + local cant = ply:IsSurvivor() and SuR.Game_Started and SuR.Wave_Started or !SuR.Game_Started or ply:IsZombie() and SuR.Game_Started and !SuR.Wave_Started or !SuR.Game_Started + if ply.AllowSpawn or SuR.DisableLogic then + cant = false + ply.AllowSpawn = false + end + if cant then + ply:KillSilent() + return + end + ply.ViewOffsetZ = 64 + ply:SetModelScale(1, 0) + ply:SetModel("models/player/Group03/male_0"..math.random(1,9)..".mdl") + if #SuR.Config.Allowed_PlayerModels > 0 then + ply:SetModel(SuR.Config.Allowed_PlayerModels[math.random(1,#SuR.Config.Allowed_PlayerModels)]) + end + if ply:IsSurvivor() then + SuR:StopInfection(ply) + ply:AllowFlashlight(true) + ply:StripWeapons() + ply:StripAmmo() + ply:SetSlowWalkSpeed(50) + ply:SetWalkSpeed(90) + ply:SetRunSpeed(170) + ply:SetJumpPower(150) + ply:SetNoCollideWithTeammates(true) + ply:AllowFlashlight(true) + ply.ResetBuggedPos = 0 + ply:SetNWFloat('BuggedPos', 0) + ply:SetNWFloat('buildercost', 1) + if ply:GetPlayerClass() == "survivor" and ply:GetLevelState() >= 1 then + ply:SetNWFloat('SelfRevive', 1) + else + ply:SetNWFloat('SelfRevive', 0) + end + if ply:GetPlayerClass() == "scout" and ply:GetLevelState() >= 4 then + ply:SetRunSpeed(ply:GetRunSpeed()*1.4) + elseif ply:GetPlayerClass() == "scout" and ply:GetLevelState() >= 2 then + ply:SetRunSpeed(ply:GetRunSpeed()*1.2) + end + + local str = ply:GetNWString('SuR_PlayerModel', '') + if str != '' then + ply:SetModel(str) + end + + ply:SetupHands() + + ply:SetNWFloat('CanCallSupport', 0) + ply:SetNWFloat('Bandages', 0) + ply:SetNWFloat('Sprays', 0) + ply:SetNWInt('Grenades', 0) + ply:SetNWInt('Money', 0) + + if #SuR.Config.Player_SpawnPositions > 0 then + ply:SetPos(table.Random(SuR.Config.Player_SpawnPositions)) + end + + ply.HealingAbilityDelay = 0 + + ply.VoiceLineDelay_LowHP = CurTime()+15 + ply.VoiceLineDelay_EnemySpotted = CurTime()+15 + ply.VoiceLineDelay_EnemyBack = CurTime()+15 + + if ply.ExfilItems then + local wep1 = ply:Give(ply.ExfilItems.main) + local wep2 = ply:Give(ply.ExfilItems.sec) + local wep3 = ply:Give(ply.ExfilItems.melee) + local wep4 = ply:Give(ply.ExfilItems.extra) + ply:SetNWFloat('Bandages', ply.ExfilItems.bandages) + ply:SetNWFloat('Sprays', ply.ExfilItems.sprays) + ply:SetNWFloat('CanCallSupport', 1) + ply.ExfilItems = nil + else + if ply:GetPlayerClass() == "berserker" and ply:GetLevelState() >= 3 then + local wep1 = ply:Give(table.Random(SuR.Config.TierWeapons["Melee"])) + wep1:SetNWFloat('Tier', 1) + else + ply:Give(SuR.Config.EmptyWeapon) + ply:SetNWString('MeleeWeapon', SuR.Config.EmptyWeapon) + end + local wep2 = ply:Give(ply:GetNWString("StartWeapon")) + ply:StripAmmo() + ply:GiveAmmo(wep2:GetMaxClip1()*2, wep2:GetPrimaryAmmoType(), true) + end + if ply:GetPlayerClass() == "demoman" and ply:GetLevelState() >= 3 then + ply:Give("tfa_private_m79") + end + if ply:GetPlayerClass() == "engineer" and ply:GetLevelState() >= 2 then + ply:Give("sur_hammer") + ply:SetNWFloat('buildercost', 10) + end + if ply:GetPlayerClass() == "engineer" and ply:GetLevelState() >= 5 then + ply:Give("sur_mine") + end + if ply:GetPlayerClass() == "marksman" and ply:GetLevelState() >= 4 then + ply:Give(table.Random(SuR.Config.TierWeapons["Tier3"])) + end + if ply:GetPlayerClass() == "marksman" and ply:GetLevelState() >= 1 then + ply:GiveAmmo(160, 3, true) + ply:GiveAmmo(80, 5, true) + ply:GiveAmmo(6, 8, true) + ply:GiveAmmo(12, 11, true) + ply:GiveAmmo(80, 13, true) + ply:GiveAmmo(80, 14, true) + ply:GiveAmmo(300, 1, true) + ply:GiveAmmo(300, 4, true) + ply:GiveAmmo(80, 7, true) + end + + if ply:GetPlayerClass() == "medic" and ply:GetLevelState() >= 5 then + ply:SetNWFloat('Bandages', 100) + ply:SetNWFloat('Sprays', 50) + ply:SetNWFloat('SelfRevive', 5) + elseif ply:GetPlayerClass() == "medic" and ply:GetLevelState() >= 3 then + ply:SetNWFloat('Bandages', 18) + ply:SetNWFloat('Sprays', 6) + ply:SetNWFloat('SelfRevive', 3) + elseif ply:GetPlayerClass() == "medic" and ply:GetLevelState() >= 1 then + ply:SetNWFloat('Bandages', 9) + ply:SetNWFloat('Sprays', 3) + end + + if ply:GetPlayerClass() == "scout" and ply:GetLevelState() >= 5 then + ply:SetNWFloat('CanCallSupport', 5) + elseif ply:GetPlayerClass() == "scout" and ply:GetLevelState() >= 3 then + ply:SetNWFloat('CanCallSupport', 2) + end + + if SuR.Config.Objective_Mode then + ply:GiveAmmo(160, 3, true) + ply:GiveAmmo(80, 5, true) + ply:GiveAmmo(6, 8, true) + ply:GiveAmmo(12, 11, true) + ply:GiveAmmo(80, 13, true) + ply:GiveAmmo(80, 14, true) + ply:GiveAmmo(300, 1, true) + ply:GiveAmmo(300, 4, true) + ply:GiveAmmo(80, 7, true) + end + elseif ply:IsZombie() then + local id = "Walker" + if isstring(ply.SelectZombieClass) and SuR.Config.Zombie_Unlock_Wave[ply.SelectZombieClass] and SuR.Config.Zombie_Unlock_Wave[ply.SelectZombieClass] <= SuR.Current_Wave then + id = ply.SelectZombieClass + end + local model = table.Random(SuR.Config.Zombie_PlayerModels[id]) + local maxhealth = 100 + if id == "Walker" then + ply:SetCrouchedWalkSpeed(0.4) + ply:SetSlowWalkSpeed(25) + ply:SetWalkSpeed(60) + ply:SetRunSpeed(60) + ply:SetJumpPower(240) + maxhealth = 300 + elseif id == "Runner" then + if SuR.Current_Wave >= 10 then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(90) + ply:SetWalkSpeed(250) + ply:SetRunSpeed(250) + ply:SetJumpPower(280) + elseif SuR.Current_Wave >= 6 then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(70) + ply:SetWalkSpeed(200) + ply:SetRunSpeed(200) + ply:SetJumpPower(270) + else + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(50) + ply:SetWalkSpeed(150) + ply:SetRunSpeed(150) + ply:SetJumpPower(260) + end + maxhealth = 150 + elseif id == "Carrier" then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(60) + ply:SetWalkSpeed(160) + ply:SetRunSpeed(160) + ply:SetJumpPower(260) + maxhealth = 250 + elseif id == "Hazmat" then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(50) + ply:SetWalkSpeed(120) + ply:SetRunSpeed(120) + ply:SetJumpPower(200) + maxhealth = 50 + elseif id == "Brute" then + ply:SetCrouchedWalkSpeed(0.5) + ply:SetSlowWalkSpeed(25) + ply:SetWalkSpeed(50) + ply:SetRunSpeed(50) + ply:SetJumpPower(200) + ply:SetModelScale(1.1, 0) + maxhealth = 1000 + elseif id == "Spitter" then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(50) + ply:SetWalkSpeed(100) + ply:SetRunSpeed(100) + ply:SetJumpPower(240) + maxhealth = 100 + elseif id == "Evo" then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(80) + ply:SetWalkSpeed(250) + ply:SetRunSpeed(250) + ply:SetJumpPower(300) + maxhealth = 200 + elseif id == "Bomber" then + ply:SetCrouchedWalkSpeed(0.2) + ply:SetSlowWalkSpeed(40) + ply:SetWalkSpeed(80) + ply:SetRunSpeed(80) + ply:SetJumpPower(200) + maxhealth = 300 + end + + ply.ZombieClass = id + ply:SetModel(model) + ply:Give("sur_claws") + ply:AllowFlashlight(false) + + local hnum = math.max(maxhealth*( SuR.Current_Wave/5 + SuR:CurrentFighters(true)/5 ), 50) + ply:SetHealth(hnum) + ply:SetMaxHealth(hnum) + + local pos = SuR:GetRandomPos(SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + if math.random(1,10) == 1 then + pos = SuR:GetRandomPos(!SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + end + + timer.Simple(0.01, function() + if !IsValid(ply) then return end + local vm = ply:GetHands() + if IsValid(vm) then + vm:SetSkin(2) + end + if isvector(pos) then + ply:SetPos(pos) + end + end) + else + ply:KillSilent() + end +end) + +hook.Add("GetFallDamage", "SuR_FallDamage", function(ply, speed) + if ply:IsZombie() and ply.ZombieClass == "Evo" then + return 0 + 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 + if ply:GetNWBool('SVAnimLoop') and (CurTime()-st)/num > 1 then + ply:SetNWFloat('SVAnimStartTime', CurTime()) + end + ply:SetCycle((CurTime()-st)/num) + return -1, ply:LookupSequence(str) + end + if downed then + 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 + if cr then + return ACT_WALK_AGITATED, -1 + else + return ACT_SPRINT, -1 + end + elseif speed > 75 and not cr or cr and speed > 30 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) + +concommand.Add("sur_spawn", function(ply, cmd, args) + if not args[1] or !ply:IsSuperAdmin() then return end + + local ent = ents.Create(args[1]) + if not ent then return end + + if ent:IsWeapon() then + ent:SetPos(ply:GetPos()) + else + ent:SetPos(ply:GetEyeTrace().HitPos) + end + ent:Spawn() +end) + +concommand.Add("sur_zombieclass", function(ply, cmd, args) + if not args[1] then return end + ply.SelectZombieClass = args[1] + if ply:IsZombie() and ply:Alive() then + ply:Kill() + end +end) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_lnr.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_lnr.lua new file mode 100644 index 0000000..1869286 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_lnr.lua @@ -0,0 +1,169 @@ +local meta = FindMetaTable("Entity") + +local function visiblity(ent, ent2) + local tr = util.TraceLine( { + start = ent:EyePos(), + endpos = ent2:WorldSpaceCenter(), + filter = ent, + mask = MASK_SOLID_BRUSHONLY + }) + print(!tr.Hit , tr.Entity, ent, ent2) + return !tr.Hit +end + +function meta:RewriteLNR(isspecial) + self.TimeOverDeath = 60 + self.RewriteDoorThing = true + self:SetCustomCollisionCheck(true) + + self.DefaultMeleeDistance = {self.MeleeAttackDistance, self.MeleeAttackDamageDistance} + + if self:GetClass() == "npc_vj_lnr_hazmat" then return end + + function self:CustomOnThink() + if self.Zombie_CustomOnThink then + self:Zombie_CustomOnThink() + end + + local en = self:GetEnemy() + if IsValid(en) then + local height = math.abs(en:GetPos().z-self:GetPos().z) + if height > 24 then + self.MeleeAttackDistance = 128 + self.MeleeAttackDamageDistance = 128 + else + self.MeleeAttackDistance = self.DefaultMeleeDistance[1] + self.MeleeAttackDamageDistance = self.DefaultMeleeDistance[2] + end + end + + if self.LNR_Crawler or self.LNR_Crippled or self.Dead or self.DeathAnimationCodeRan or self.Flinching or self:GetSequence() == self:LookupSequence("nz_spawn_climbout_fast") or self:GetSequence() == self:LookupSequence("nz_spawn_jump") or self:GetSequence() == self:LookupSequence("shove_forward_01") or self:GetSequence() == self:LookupSequence("infectionrise") or self:GetSequence() == self:LookupSequence("infectionrise2") or self:GetSequence() == self:LookupSequence("slumprise_a") or self:GetSequence() == self:LookupSequence("slumprise_a2") then + self.LNR_DoorToBreak = NULL + + return + end + + local acti = ACT_OPEN_DOOR + if !VJ_AnimationExists(self, ACT_OPEN_DOOR) then + acti = self.AnimTbl_MeleeAttack[1] + end + + if acti then + if not IsValid(self.LNR_DoorToBreak) then + if (not self.VJ_IsBeingControlled) or (self.VJ_IsBeingControlled and self.VJ_TheController:KeyDown(IN_DUCK)) then + for _, v in pairs(ents.FindInSphere(self:GetPos(), 48)) do + if ( v:GetClass() == "prop_door_rotating" or v:GetClass() == "func_door_rotating" or v:GetClass() == "func_door" or v:GetClass() == "sur_barricade" ) then + self.LNR_DoorToBreak = v + break + end + end + end + else + if self.PlayingAttackAnimation then + self.LNR_DoorToBreak = NULL + + return + end + + if self:GetActivity() ~= ACT_OPEN_DOOR then + local ang = self:GetAngles() + self:SetAngles(Angle(ang.x, (self.LNR_DoorToBreak:GetPos() - self:GetPos()):Angle().y, ang.z)) + self:VJ_ACT_PLAYACTIVITY(ACT_OPEN_DOOR, true, false, false) + self:SetState(VJ_STATE_ONLY_ANIMATION) + end + end + end + + if not IsValid(self.LNR_DoorToBreak) then + self:SetState() + end + end +end + +hook.Add("AcceptInput", "SuR_RewriteInput", function( self, name, activator, caller, data ) + if self.RewriteDoorThing and self.IsZombie and name == "break_door" then + if IsValid(self.LNR_DoorToBreak) then + VJ_CreateSound(self, self.SoundTbl_BeforeMeleeAttack, self.BeforeMeleeAttackSoundLevel, self:VJ_DecideSoundPitch(self.BeforeMeleeAttackSoundPitch.a, self.BeforeMeleeAttackSoundPitch.b)) + VJ_EmitSound(self, "physics/wood/wood_panel_impact_hard1.wav", 75, 100) + local doorDmg = self.MeleeAttackDamage + local door = self.LNR_DoorToBreak + + if door.health == nil then + door.health = 200 - doorDmg + elseif door.health <= 0 then + VJ_EmitSound(self, self.SoundTbl_MeleeAttackMiss, self.MeleeAttackMissSoundLevel, self:VJ_DecideSoundPitch(self.MeleeAttackMissSoundPitch.a, self.MeleeAttackMissSoundPitch.b)) + + return + else + door.health = door.health - doorDmg + end + + if door:GetClass() == "prop_door_rotating" and door.health <= 0 then + door:EmitSound("physics/wood/wood_furniture_break" .. math.random(1, 2) .. ".wav", 75, 100) + door:EmitSound("ambient/materials/door_hit1.wav", 75, 100) + ParticleEffect("door_pound_core", door:GetPos(), door:GetAngles(), nil) + ParticleEffect("door_explosion_chunks", door:GetPos(), door:GetAngles(), nil) + door:Remove() + local doorgib = ents.Create("prop_physics") + doorgib:SetPos(door:GetPos()) + doorgib:SetAngles(door:GetAngles()) + doorgib:SetModel(door:GetModel()) + doorgib:SetSkin(door:GetSkin()) + doorgib:SetBodygroup(1, door:GetBodygroup(1)) + doorgib:SetCollisionGroup(COLLISION_GROUP_DEBRIS) + doorgib:SetSolid(SOLID_NONE) + doorgib:Spawn() + doorgib:GetPhysicsObject():ApplyForceCenter(self:GetForward() * 5000) + SafeRemoveEntityDelayed(doorgib, 30) + elseif door.health <= 0 then + door:EmitSound("physics/wood/wood_furniture_break" .. math.random(1, 2) .. ".wav", 75, 100) + ParticleEffect("door_pound_core", door:GetPos(), door:GetAngles(), nil) + ParticleEffect("door_explosion_chunks", door:GetPos(), door:GetAngles(), nil) + door:Remove() + local doorgibs = ents.Create("prop_dynamic") + doorgibs:SetPos(door:GetPos()) + doorgibs:SetAngles(door:GetAngles()) + doorgibs:SetModel("models/props_c17/FurnitureDresser001a.mdl") + doorgibs:Spawn() + doorgibs:TakeDamage(9999) + doorgibs:Fire("break") + end + end + return true + end +end) + +local function PushApart(npc1, npc2) + local pos1 = npc1:GetPos() + local pos2 = npc2:GetPos() + if pos1:DistToSqr(pos2) > 10000 then return end + local dir = (pos1 - pos2):GetNormalized() + local pushForce = 50 + local npc1allow = npc1:GetClass() != "npc_vj_lnr_hazmat" and !npc1:IsPlayer() + local npc2allow = npc2:GetClass() != "npc_vj_lnr_hazmat" and !npc2:IsPlayer() + + if npc1allow then + npc1:SetVelocity(dir * pushForce) + end + if npc2allow then + npc2:SetVelocity(-dir * pushForce) + end +end + +hook.Add("ShouldCollide", "SuR_NoCollision", function(ent1, ent2) + if ent1 == ent2 then return false end + + local allow1 = ent1:IsNPC() and ent1.IsZombie or ent1:IsPlayer() and ent1:IsZombie() + local allow2 = ent2:IsNPC() and ent2.IsZombie or ent2:IsPlayer() and ent2:IsZombie() + if allow1 and allow2 then + PushApart(ent1, ent2) + return false + end + + local allow1 = ent1:IsNPC() and ent1.IsHuman or ent1:IsPlayer() and ent1:IsSurvivor() + local allow2 = ent2:IsNPC() and ent2.IsHuman or ent2:IsPlayer() and ent2:IsSurvivor() + if allow1 and allow2 then + PushApart(ent1, ent2) + return false + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nets.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nets.lua new file mode 100644 index 0000000..9f85449 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nets.lua @@ -0,0 +1,24 @@ +util.AddNetworkString("SuR.SendDataToClient") +util.AddNetworkString("SuR.PlaySoundOnClient") +util.AddNetworkString("SuR.PlaySoundOnEntity") +util.AddNetworkString("SuR.MessageOnClient") +util.AddNetworkString("SuR.KillStatus") +util.AddNetworkString("SuR.Countdown") +util.AddNetworkString("SuR.RadioSupport") +util.AddNetworkString("SuR.VoiceLines") +util.AddNetworkString("SuR.GameOverScreen") +util.AddNetworkString("SuR.DeathView") +util.AddNetworkString("SuR.DeployCutscene") +util.AddNetworkString("SuR.ClientRunString") +util.AddNetworkString("SuR.SelectPlayerModel") +util.AddNetworkString("SuR.ChooseStartWeapon") +util.AddNetworkString("SuR.ChooseVoicePack") +util.AddNetworkString("SuR.PointMarker") +util.AddNetworkString("SuR.PointMark") +util.AddNetworkString("SuR.Boss") +util.AddNetworkString("SuR.ShowTips") +util.AddNetworkString("SuR.OpenClassMenu") +util.AddNetworkString("SuR.PrecacheModels") +util.AddNetworkString("SuR.BecomeRagdoll") +util.AddNetworkString("SuR.ExfilIcon") +util.AddNetworkString("SuR.BuyMenu") \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nodegraph.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nodegraph.lua new file mode 100644 index 0000000..30e56dc --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_nodegraph.lua @@ -0,0 +1,128 @@ +SuR.AI_Nodes = {} + +local found_ai_nodes = false +local M = {} +local SIZEOF_INT = 4 +local SIZEOF_SHORT = 2 +local AINET_VERSION_NUMBER = 37 +local function toUShort(b) + local i = {string.byte(b,1,SIZEOF_SHORT)} + return i[1] +i[2] *256 +end +local function toInt(b) + local i = {string.byte(b,1,SIZEOF_INT)} + i = i[1] +i[2] *256 +i[3] *65536 +i[4] *16777216 + if(i > 2147483647) then return i -4294967296 end + return i +end +local function ReadInt(f) return toInt(f:Read(SIZEOF_INT)) end +local function ReadUShort(f) return toUShort(f:Read(SIZEOF_SHORT)) end + +if found_ai_nodes then + return +end + +f = file.Open("maps/graphs/"..game.GetMap()..".ain","rb","GAME") +if not f then + return +end + +found_ai_nodes = true +local ainet_ver = ReadInt(f) +local map_ver = ReadInt(f) +if ainet_ver ~= AINET_VERSION_NUMBER then + MsgN("Unknown graph file") + return +end + +local numNodes = ReadInt(f) +if numNodes < 0 then + MsgN("Graph file has an unexpected amount of nodes") + return +end + +for i = 1,numNodes do + local v = Vector(f:ReadFloat(),f:ReadFloat(),f:ReadFloat()) + local yaw = f:ReadFloat() + local flOffsets = {} + for i = 1,NUM_HULLS do + flOffsets[i] = f:ReadFloat() + end + local nodetype = f:ReadByte() + local nodeinfo = ReadUShort(f) + local zone = f:ReadShort() + if nodetype == 4 or nodetype == 3 then + goto cont + end + + local node = { + pos = v, + yaw = yaw, + offset = flOffsets, + type = nodetype, + info = nodeinfo, + zone = zone, + neighbor = {}, + numneighbors = 0, + link = {}, + numlinks = 0 + } + + table.insert(SuR.AI_Nodes,node.pos) + ::cont:: +end + +if #SuR.AI_Nodes == 0 then + hook.Add("Think", "SuR_BlockNode", function() + SuR:SendDataToClient("GameplayBlockNode", true) + SuR.Game_Started = false + SuR.DeployTime = CurTime()+SuR.Config.Delay_Before_Deploy + end) +end + +function SuR:GetRandomPos(underroof, mindist, maxdist) + local newtab = {} + local tab = SuR.AI_Nodes + if #tab > 0 then + for i=1,#tab do + local pos = tab[i] + + local tr = util.TraceLine({ + start = pos, + endpos = pos + Vector(0,0,9999), + }) + if tr.HitSky and underroof or !tr.HitSky and !underroof then continue end + + local visible = false + local tab = player.GetAll() + local rndply = tab[math.random(1,#tab)] + for i=1,#tab do + local ply = tab[i] + if ply:IsZombie() then continue end + if ply:Alive() and ply:IsLineOfSightClear(pos) then + visible = true + break + end + if mindist and maxdist then + local dist = ply:GetPos():DistToSqr(pos) + if dist < mindist^2 then + visible = true + break + end + end + end + if IsValid(rndply) and rndply:GetPos():DistToSqr(pos) > maxdist^2 then + visible = true + end + + if visible then continue end + + table.insert(newtab, pos) + end + end + if #newtab > 0 then + return newtab[math.random(1,#newtab)] + else + return nil + end +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_other.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_other.lua new file mode 100644 index 0000000..1c6df1a --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_other.lua @@ -0,0 +1,47 @@ +local precache_tab = { + "models/surrounded/mh53.mdl", + "models/surrounded/mi24d.mdl", + "models/surrounded/skilllem_radio.mdl", + "models/surrounded/test/tcm_family.mdl", + "models/surrounded/test/tcm_victim.mdl", + "models/surrounded/test/tcm_misc.mdl", + "models/surrounded/test/trials_executions.mdl", + "models/surrounded/obj/QuestGenerator.mdl", + "models/surrounded/obj/w_JerryCanBlue.mdl", + "models/weapons/evildead_killer.mdl", + "models/weapons/slasher_executions.mdl", + "models/weapons/tcm_family.mdl", + "models/slasher_victim.mdl", + "models/tcm_victim.mdl", + "models/evildead_killed.mdl", + "models/exfil/mw22_crew_pm.mdl", + "models/exfil/palfa.mdl", + "models/surrounded/animations/evildead/evildead_killer_nmrih.mdl", + "models/surrounded/animations/evildead/evildead_killed_nmrih.mdl", +} + +for _, cat in pairs(SuR.Config.TierWeapons) do + for _, class in pairs(cat) do + local info = weapons.Get(class) + if !info then continue end + precache_tab[#precache_tab+1] = info.WorldModel + end +end + +local function precache_models(ply) + if istable(ply) or IsValid(ply) then + net.Start("SuR.PrecacheModels") + net.WriteTable(precache_tab) + net.Send(ply) + else + for _, m in ipairs(precache_tab) do + util.PrecacheModel(m) + end + end +end + +hook.Add("PlayerInitialSpawn", "SuR.ErrorModels", function(ply) + precache_models(ply) +end) + +hook.Add("InitPostEntity", "SuR.Precache", precache_models) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_qte.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_qte.lua new file mode 100644 index 0000000..fa452f0 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_qte.lua @@ -0,0 +1,249 @@ +local function sound_effects(ply, anim) + if anim == "sur_closeencounter_johnny_win" then + timer.Simple(0.4, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_swing_2d_0"..math.random(1,6)..".wav", ply:GetPos()) + end) + timer.Simple(0.7, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_impact_face_2d_0"..math.random(1,9)..".wav", ply:GetPos()) + end) + elseif anim == "sur_closeencounter_cook_win" then + timer.Simple(0.6, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_swing_2d_0"..math.random(1,6)..".wav", ply:GetPos()) + end) + timer.Simple(0.9, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_impact_body_2d_0"..math.random(1,6)..".wav", ply:GetPos()) + end) + elseif anim == "sur_closeencounter_hitchhiker_win" then + timer.Simple(0.4, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_swing_2d_0"..math.random(1,6)..".wav", ply:GetPos()) + end) + timer.Simple(0.7, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_impact_face_2d_0"..math.random(1,9)..".wav", ply:GetPos()) + end) + elseif anim == "sur_closeencounter_sissy_win" then + timer.Simple(0.3, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_swing_2d_0"..math.random(1,6)..".wav", ply:GetPos()) + end) + timer.Simple(0.5, function() + if !IsValid(ply) then return end + sound.Play("bsmod/EvilDead/punch/punch_impact_face_2d_0"..math.random(1,9)..".wav", ply:GetPos()) + end) + end +end + +function SuR:StopGrab(self, ent, takedown) + if !IsValid(ent) then return end + + local function dis(dist) + if IsValid(self) then + self:RemoveEFlags(EFL_NO_THINK_FUNCTION) + self:SetNoDraw(false) + self:SetMaterial("") + self.ExecutingTarget = false + self:SetState() + for i, ent in ipairs(self:GetChildren()) do + ent:SetMaterial("") + end + if IsValid(self.grabmodel) then + self.grabmodel:Remove() + end + if dist then + self.Flinching = true + self:StopAttacks(true) + self.PlayingAttackAnimation = false + local animTbl = self.AnimTbl_Flinch + if HitgroupInfo != nil then animTbl = HitgroupInfo.Animation end + local anim = istable(animTbl) and VJ_PICK(animTbl) or animTbl + local animDur = self.NextMoveAfterFlinchTime + if animDur == false and anim then + animDur = self:DecideAnimationLength(anim, false, self.FlinchAnimationDecreaseLengthAmount) + end + animDur = tonumber(animDur) or 0.1 + if animDur <= 0 then + animDur = 0.1 + end + if anim then + self:VJ_ACT_PLAYACTIVITY(anim, true, animDur, false, 0, {SequenceDuration=animDur, PlayBackRateCalculated=true}) + end + timer.Create("timer_act_flinching"..self:EntIndex(), tonumber(animDur) or 0.1, 1, function() self.Flinching = false end) + if isfunction(self.CustomOnFlinch_AfterFlinch) then + self:CustomOnFlinch_AfterFlinch(dmginfo, hitgroup) + end + self.NextFlinchT = CurTime() + (tonumber(self.NextFlinchTime) or 0) + end + end + + ent:Freeze(false) + ent:SetNoTarget(false) + ent:SetSVAnimation("") + ent.GrabDelay = CurTime()+5 + ent.Grabbed = false + ent.ExecutingTarget = false + ent.ExecutingEnt = nil + ent.GrabPressCount = 0 + if IsValid(ent.LastPickupWeapon) then + local class = ent.LastPickupWeapon:GetClass() + ent:SelectWeapon(class) + ent.LastPickupWeapon = nil + end + end + + if takedown and IsValid(self) then + dis() + ent:SuR_Down() + elseif not takedown and IsValid(self) then + SuR:PlaySoundOnClient("surrounded/sfx/qte_success"..math.random(1,3)..".mp3", ent) + + local anim1 = "sur_"..ent.ExecutingEnt.grabanim.."win" + local anim2 = ent.ExecutingEnt.grabanim.."lose" + local long = tonumber(select(2, ent:LookupSequence(anim1))) or 0.1 + + ent.Grabbed = false + ent:SetSVAnimation(anim1, false, true, true) + sound_effects(ent, anim1) + ent.ExecutingEnt.grabmodel:ResetSequence(anim2) + ent.ExecutingEnt.grabmodel:SetCycle(0) + + timer.Simple(long, function() + if !IsValid(ent) then return end + dis(true) + end) + else + dis() + end +end + +local function AbilityGrab(self, ent) + if self.ExecutingTarget or ent.ExecutingTarget or ent.Grabbed or ent:IsDowned() or ent.GrabDelay and ent.GrabDelay > CurTime() or ent:IsZombie() then return end + + local angz = self:GetAngles():SnapTo("y", 45) + local posz = ent:GetPos() + local isnpc = ent:IsNPC() + local startpos = self:GetPos() + + local att_name = "" + local rnd = math.random(1,4) + if rnd == 1 then + att_name = "hitchhiker" + elseif rnd == 2 then + att_name = "sissy" + elseif rnd == 3 then + att_name = "johnny" + else + att_name = "cook" + end + local anim = "closeencounter_"..att_name.."_" + + local ent2 = ent + local ent1 = ents.Create("sur_anim") + ent1.ent = self + ent1.enable_ent = true + ent1:SetModel("models/surrounded/test/tcm_misc.mdl") + ent1:SetAngles(angz) + ent1:SetPos(posz) + ent1:Spawn() + ent1:SetPos(posz-ent1:GetForward()*28) + ent1:ResetSequence(anim.."intro") + ent1:ResetSequenceInfo() + ent1:SetCycle(0) + self.grabmodel = ent1 + self.grabanim = anim + + local bd = ents.Create("base_anim") + SuR:TransferModelData(self, bd) + bd:SetPos(posz) + bd:SetParent(ent1) + bd:AddEffects(1) + bd:Spawn() + + self:RemoveAllDecals() + self:AddEFlags(EFL_NO_THINK_FUNCTION) + self:SetMaterial("null") + self:SetNoDraw(true) + self:SetVelocity(-self:GetVelocity()) + self.ExecutingPos = posz + self:SetPos(posz) + self:SetAngles(angz) + self.ExecutingTarget = true + self.ExecutingModel = ent1 + for i, ent in ipairs(self:GetChildren()) do + ent:SetMaterial("null") + end + + ent:Freeze(true) + ent:SetNoTarget(true) + ent:SetPos(posz) + ent:SetEyeAngles(angz+Angle(0,180,0)) + ent:SetVelocity(-ent:GetVelocity()+Vector(50,0,0)) + ent:SetSVAnimation("sur_"..anim.."intro", false, true, true) + ent.ExecutingTarget = true + ent.ExecutingPos = posz + ent.ExecutingEnt = self + ent.Grabbed = true + ent.GrabPressMax = math.floor(math.Clamp(self:Health()/15, 10, 50)) + ent.GrabPressCount = 0 + if !IsValid(ent.LastPickupWeapon) then + ent.LastPickupWeapon = ent:GetActiveWeapon() + end + ent:SetActiveWeapon(nil) + SuR:PlaySoundOnClient("surrounded/sfx/qte_start"..math.random(1,3)..".mp3", ent) + + timer.Simple(select(2, ent:LookupSequence("sur_"..anim.."intro")), function() + if !IsValid(ent) or !IsValid(self) or !ent.Grabbed or !IsValid(ent1) then return end + + ent:SetSVAnimation("sur_"..anim.."grappleloop", false, true, true, true) + ent1:ResetSequence(anim.."grappleloop") + end) +end + +hook.Add("OnNPCKilled", "SuR_GrabsFixed", function(ent) + if ent.ExecutingTarget then + ent:SetNoDraw(true) + ent:SetMaterial("") + end +end) + +local allow_specials = { + ["npc_vj_lnrhl2_rebel_hvy"] = true, + ["npc_vj_lnr_carrier"] = true, + ["npc_vj_lnr_butcher"] = true, + ["npc_vj_lnr_riot"] = true, + ["npc_vj_lnr_riot_shield"] = true, + ["npc_vj_lnr_evo"] = true, + ["npc_vj_lnr_bomber"] = true, + ["npc_vj_lnr_tesla"] = true, + ["npc_vj_lnr_healer"] = true, + ["npc_vj_lnr_hazmat"] = true, +} + +hook.Add("EntityTakeDamage", "SuR_Grabs", function(tar, dmg) + local att = dmg:GetAttacker() + if not tar.NoGrab and att:IsNPC() and att:GetPos():DistToSqr(tar:GetPos()) < 20000 and att.IsZombie and not att.LNR_Crawler and (!att.IsSpecial and math.random(1,100) <= SuR.Config.Zombie_Grab_Chance or allow_specials[att:GetClass()] and math.random(1,100) <= SuR.Config.Zombie_Special_Grab_Chance or SuR.ActiveMutator == 3 and math.random(1,100) <= SuR.Config.Zombie_Special_Grab_Chance*2) and tar:IsPlayer() then + AbilityGrab(att, tar) + dmg:SetDamage(0) + end + if tar:IsPlayer() and tar.Grabbed and dmg:GetDamage() >= tar:Health() then + dmg:SetDamage(0) + end +end) + +hook.Add("PlayerButtonDown", "SuR_ButtonHookQTE", function(ply, but) + if ply.Grabbed and ply:Alive() and but == KEY_SPACE and string.match(ply:GetSVAnim(), "grappleloop") then + if ply.GrabPressCount < ply.GrabPressMax then + if ply:GetPlayerClass() == "survivor" and ply:GetLevelState() >= 2 then + ply.GrabPressCount = ply.GrabPressCount + 4 + else + ply.GrabPressCount = ply.GrabPressCount + 1 + end + else + SuR:StopGrab(ply.ExecutingEnt, ply, false) + end + end +end) diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_revive.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_revive.lua new file mode 100644 index 0000000..b4658a1 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_revive.lua @@ -0,0 +1,400 @@ +local meta = FindMetaTable('Player') + +function SuR:VJ_LNR_CreateZombie(victim, inflictor) + local findPos = victim:GetPos() + local findMDL = victim:GetModel() + + timer.Simple(0.01, function() + for _, v in pairs(ents.FindInSphere(findPos, 75)) do + if v:GetClass() == "prop_ragdoll" and v:GetModel() == findMDL then + v:Remove() + end + end + end) + + local zombie = NULL + local sndTbl = nil + local oldModel = victim:GetModel() + local oldSkin = victim:GetSkin() + local oldMaterial = victim:GetMaterial() + local oldColor = victim:GetColor() + + if victim.GetPlayerColor and victim:GetPlayerColor() then + oldPlayerColor = victim:GetPlayerColor() + else + oldPlayerColor = false + end + + local DefaultFootSteps = {"npc/metropolice/gear1.wav", "npc/metropolice/gear2.wav", "npc/metropolice/gear3.wav", "npc/metropolice/gear4.wav", "npc/metropolice/gear5.wav", "npc/metropolice/gear6.wav"} + + if victim.SoundTbl_FootStep and #victim.SoundTbl_FootStep > 0 then + sndTbl = victim.SoundTbl_FootStep + else + if victim.IsVJBaseSNPC_Human and not VJ_PICK(victim.SoundTbl_FootStep) then + sndTbl = DefaultFootSteps + end + end + + if victim:IsNPC() or victim:IsPlayer() then + if inflictor.LNR_Walker or victim.LNR_Walker then + victim.LNR_Infected = false + victim.LNR_Drowner = false + zombie = ents.Create("npc_vj_lnr_wal") + + if victim:IsPlayer() then + zombie = ents.Create("npc_vj_lnr_wal_ply") + end + end + + if inflictor.LNR_Infected or victim.LNR_Infected then + victim.LNR_Walker = false + victim.LNR_Drowner = false + zombie = ents.Create("npc_vj_lnr_inf") + + if victim:IsPlayer() then + zombie = ents.Create("npc_vj_lnr_inf_ply") + end + end + + if inflictor.LNR_Drowner or victim.LNR_Drowner then + victim.LNR_Walker = false + victim.LNR_Infected = false + zombie = ents.Create("npc_vj_lnr_drowned") + + if victim:IsPlayer() then + zombie = ents.Create("npc_vj_lnr_drowned_ply") + end + end + + zombie:SetPos(victim:GetPos()) + zombie:SetAngles(victim:GetAngles()) + zombie:Spawn() + undo.ReplaceEntity(victim, zombie) + zombie:VJ_LNR_CreateBoneMerge(zombie, oldModel, oldSkin, oldColor, oldMaterial, oldPlayerColor, victim) + end + + if sndTbl then + zombie.SoundTbl_FootStep = sndTbl + end + + -- This fixes an error that would pop up if an SNPC or entity infected more than one enemy at a time + if zombie.IsVJBaseSNPC and zombie.CurrentPossibleEnemies == nil then + zombie.CurrentPossibleEnemies = {} + end + + if string.find(oldModel, "female") or string.find(oldModel, "alyx") or string.find(oldModel, "mossman") or string.find(oldModel, "chell") then + if zombie.LNR_Walker then + zombie:ZombieVoice_FemaleWal() + elseif zombie.LNR_Infected then + zombie:ZombieVoice_FemaleInf() + elseif zombie.LNR_Drowner then + zombie:ZombieVoice_FemaleDro() + end + end + + if string.find(oldModel, "police") then + zombie:ZombieVoice_CP() + elseif string.find(oldModel, "combine") or string.find(oldModel, "zombie_soldier") then + zombie:ZombieVoice_Combine() + end + + local DeathAnims = {ACT_SIGNAL1, ACT_SIGNAL2, ACT_SIGNAL3} + + local AnimTime = VJ_GetSequenceDuration(zombie, zombie:GetSequenceName(zombie:GetSequence())) + zombie:VJ_ACT_PLAYACTIVITY(DeathAnims, true, 120, false) + zombie.LNR_AllowedToStumble = false + zombie.GodMode = true + zombie.CanInvestigate = false + zombie.HasPoseParameterLooking = false + zombie.DisableFindEnemy = true + zombie.DisableMakingSelfEnemyToNPCs = true + zombie:AddFlags(FL_NOTARGET) + zombie.MovementType = VJ_MOVETYPE_STATIONARY + zombie.CanTurnWhileStationary = false + zombie.HasSounds = false + zombie.DisableSelectSchedule = true + + timer.Simple(math.random(GetConVar("VJ_LNR_ResurrectionTime1"):GetInt(), GetConVar("VJ_LNR_ResurrectionTime2"):GetInt()), function() + if IsValid(zombie) then + zombie.GodMode = false + zombie.CanInvestigate = true + zombie.DisableFindEnemy = false + zombie.DisableMakingSelfEnemyToNPCs = false + zombie:RemoveFlags(FL_NOTARGET) + + if GetConVar("vj_npc_sd_nosounds"):GetInt() == 0 then + zombie.HasSounds = true + end + + if zombie:GetActivity() == ACT_SIGNAL1 then + zombie:VJ_ACT_PLAYACTIVITY("infectionrise", true, false, false) + AnimTime = VJ_GetSequenceDuration(zombie, "infectionrise") + elseif zombie:GetActivity() == ACT_SIGNAL2 then + zombie:VJ_ACT_PLAYACTIVITY("slumprise_a", true, false, false) + AnimTime = VJ_GetSequenceDuration(zombie, "slumprise_a") + + if zombie:GetActivity() == ACT_SIGNAL2 and math.random(1, 3) == 1 then + zombie:VJ_ACT_PLAYACTIVITY("slumprise_a2", true, false, false) + AnimTime = VJ_GetSequenceDuration(zombie, "slumprise_a2") + end + elseif zombie:GetActivity() == ACT_SIGNAL3 then + zombie:VJ_ACT_PLAYACTIVITY("infectionrise2", true, false, false) + AnimTime = VJ_GetSequenceDuration(zombie, "infectionrise2") + end + + if GetConVar("vj_npc_noidleparticle"):GetInt() == 0 and GetConVar("VJ_LNR_Eyes"):GetInt() == 1 then + for i = 1, 2 do + local att = i == 2 and "eye1" or "eye2" + local EyeGlow = ents.Create("env_sprite") + EyeGlow:SetKeyValue("model", "vj_base/sprites/vj_glow1.vmt") + EyeGlow:SetKeyValue("scale", "0.02") + EyeGlow:SetKeyValue("rendermode", "5") + + if zombie:GetClass() == "npc_vj_lnr_inf" or zombie:GetClass() == "npc_vj_lnr_inf_ply" then + EyeGlow:SetKeyValue("rendercolor", "255 0 0") + end + + if zombie:GetClass() == "npc_vj_lnr_drowned" or zombie:GetClass() == "npc_vj_lnr_drowned_ply" then + EyeGlow:SetKeyValue("rendercolor", "0 255 255 255") + end + + if zombie:GetClass() == "npc_vj_lnr_wal" or zombie:GetClass() == "npc_vj_lnr_wal_ply" then + EyeGlow:SetKeyValue("rendercolor", "255 255 0 255") + end + + EyeGlow:SetKeyValue("spawnflags", "1") + EyeGlow:SetParent(zombie) + EyeGlow:Fire("SetParentAttachment", att, 0) + EyeGlow:Spawn() + EyeGlow:Activate() + zombie:DeleteOnRemove(EyeGlow) + end + end + + timer.Simple(AnimTime, function() + if IsValid(zombie) then + zombie.HasPoseParameterLooking = true + zombie:DoChangeMovementType(VJ_MOVETYPE_GROUND) + + if zombie:GetClass() == "npc_vj_lnr_drowned" or zombie:GetClass() == "npc_vj_lnr_drowned_ply" then + zombie:DoChangeMovementType(VJ_MOVETYPE_AQUATIC) + end + + zombie.LNR_AllowedToStumble = true + zombie.DisableSelectSchedule = false + end + end) + end + end) + + if victim.IsVJBaseSNPC then + victim.HasDeathRagdoll = false + victim.HasDeathAnimation = false + end + + if victim:IsPlayer() then + if IsValid(victim:GetRagdollEntity()) then + SafeRemoveEntity(victim:GetRagdollEntity()) + end + end + + if victim:IsNPC() then + SafeRemoveEntity(victim) + end + + if IsValid(victim:GetActiveWeapon()) then + SafeRemoveEntity(victim:GetActiveWeapon()) + end +end + +function meta:SuR_MakeZombie() + if self:Alive() then + self:Kill() + if math.random(1,2) == 1 then + self.LNR_Infected = true + else + self.LNR_Walker = true + end + SuR:VJ_LNR_CreateZombie(self, self) + if SuR.Config.Versus_Mode then + timer.Simple(0, function() self:SetTeam(2) end) + end + end + SuR:StopInfection(self) +end + +function meta:SuR_SelfRevive() + if !self:IsDowned() or self:GetNWFloat('SelfRevive') <= 0 or self:GetSVAnim() != "" or self:IsFlagSet(FL_FROZEN) then return end + + if self:LookupAttachment("anim_attachment_LH") > 0 then + local att = self:GetAttachment(self:LookupAttachment("anim_attachment_LH")) + local ent = ents.Create("base_anim") + ent:SetModel("models/props_c17/TrapPropeller_Lever.mdl") + ent:Spawn() + ent:SetPos(att.Pos) + ent:SetAngles(att.Ang) + ent:SetParent(self, self:LookupAttachment("anim_attachment_LH")) + ent:SetLocalAngles(Angle(0,0,90)) + ent:SetLocalPos(Vector(0,0,-4)) + SafeRemoveEntityDelayed(ent, 8) + end + + self:SetSVAnimation("sur_selfrevive", true, true, true) + self:ConCommand("-forward") + timer.Remove("PlayerDowned"..self:EntIndex()) + timer.Simple(1, function() + if !IsValid(self) or !self:Alive() then return end + self:EmitSound("surrounded/player/syringe.mp3", 60, math.random(90,110)) + self:ScreenFade(SCREENFADE.IN, Color(20,200,20,100), 0.5, 0) + end) + timer.Simple(8, function() + if !IsValid(self) or !self:Alive() or self:IsFlagSet(FL_FROZEN) or !self:IsDowned() then return end + self:SuR_Revive(false, true) + self:SetNWFloat('SelfRevive', self:GetNWFloat('SelfRevive')-1) + end) +end + +function meta:SuR_Down() + if self.ExecutingTarget then return end + if self:GetInfection() >= 0.5 then + self:SuR_MakeZombie() + return + end + self:SetSVAnimation("sur_helpup_trials_follower_drophigh", true, true, true) + self:SetNWBool('SuR_Downed', true) + self:SetNWVector('CutsceneAddPos', self:GetUp()*-32) + self:SetHealth(50) + self:GodEnable() + self:SetActiveWeapon(nil) + self:SetNoTarget(true) + self:SetDSP(14) + self:PlayVoiceLine("downed") + self:DropButtons() + SuR:MessageOnClient(4, self) + SuR:ShowTips("revive") + + local delay = 65 + if SuR:CurrentFighters() < 1 and self:GetNWFloat('SelfRevive') <= 0 or SuR.ActiveMutator == 3 then + delay = 3 + elseif SuR.Current_Wave >= 15 then + delay = 15 + elseif SuR.Current_Wave >= 10 then + delay = 20 + elseif SuR.Current_Wave >= 6 then + delay = 25 + elseif SuR.Current_Wave >= 3 then + delay = 30 + end + + timer.Create("PlayerDowned2"..self:EntIndex(), delay, 1, function() + if !IsValid(self) then return end + + self:SetNoTarget(false) + self:GodDisable() + end) + timer.Create("PlayerDowned"..self:EntIndex(), SuR.Config.Bleedout_Time, 1, function() + if !IsValid(self) then return end + + self:DropButtons() + self:SetSVAnimation("sur_downed_trials_bleedout", true, true, true) + timer.Simple(3, function() + if !IsValid(self) or !self:IsDowned() then return end + self:SuR_Revive(true) + end) + end) + + local wep = self:GetActiveWeapon() + if IsValid(wep) then + self.PreDownedWeapon = wep:GetClass() + end +end + +function meta:SuR_Revive(kill, nophase, other) + self:SetNWBool('SuR_Downed', false) + self:SetNWVector('CutsceneAddPos', Vector(0,0,0)) + self:SetHealth(30) + self:SetDSP(0) + self:SetNoTarget(false) + self:GodDisable() + self:DropButtons() + timer.Remove("PlayerDowned"..self:EntIndex()) + timer.Remove("PlayerDowned2"..self:EntIndex()) + + if kill then + if self:Alive() then + self:Kill() + end + else + if other then + self:SetSVAnimation("sur_helpup_trials_follower_success", true, true, true) + else + self:SetSVAnimation("sur_revive_stand", true, true, true) + self:SetNoTarget(true) + self:SetHealth(60) + timer.Simple(5, function() + if !IsValid(self) or self:IsDowned() then return end + self:SetNoTarget(false) + end) + end + if !nophase then + self:PlayVoiceLine("thanks") + end + if isstring(self.PreDownedWeapon) then + self:SelectWeapon(self.PreDownedWeapon) + end + end + self.PreDownedWeapon = nil +end + +hook.Add("Think", "SuR_ThinkRevive", function() + local tab = player.GetAll() + for i=1, #tab do + local ply = tab[i] + + 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(ply:GetNWEntity('ReviveTarget')) and IsValid(ent) and ent:IsPlayer() and ent:IsDowned() and !ply:IsDowned() and ply:Alive() and ply:GetVelocity():Length() < 10 and ply:KeyDown(IN_USE) and ent:GetSVAnim() == "" then + ply:SetNWEntity('ReviveTarget', ent) + if ply:GetPlayerClass() == "medic" and ply:GetLevelState() >= 4 then + ply.ReviveProgress = 1 + end + elseif IsValid(ply:GetNWEntity('ReviveTarget')) then + local ent = ply:GetNWEntity('ReviveTarget') + if ply:KeyDown(IN_USE) and ent:IsDowned() and !ply:IsDowned() and ply:Alive() and ply:GetVelocity():Length() < 10 and ply:GetPos():Distance(ent:GetPos()) < 50 then + if ply.ReviveProgress == 0 then + ply:SetSVAnimation("sur_helpup_trials_leader_try", false, true, true) + ent:SetSVAnimation("sur_helpup_trials_follower_try", false, true, true) + ply:DropButtons() + ent:DropButtons() + end + ent:SetEyeAngles(ply:GetAngles()+Angle(0,180,0)) + ply.ReviveProgress = ply.ReviveProgress + FrameTime()/select(2, ply:LookupSequence("sur_helpup_trials_leader_try")) + if ply.ReviveProgress >= 1 then + ent:SuR_Revive(false, false, true) + ply:SetSVAnimation("sur_helpup_trials_leader_success", true, true, true) + end + else + if ply:GetSVAnim() == "sur_helpup_trials_leader_try" then + ply:SetSVAnimation("sur_helpup_trials_leader_leave", true, true, true) + end + if IsValid(ent) and ply:GetSVAnim() != "sur_helpup_trials_leader_success" then + ent:SetSVAnimation("sur_helpup_trials_follower_drophigh", true, true, true) + end + ply.ReviveProgress = 0 + ply:SetNWEntity('ReviveTarget', NULL) + end + else + if ply:GetSVAnim() == "sur_helpup_trials_leader_try" then + ply:SetSVAnimation("sur_helpup_trials_leader_leave", true, true, true) + end + ply:SetNWEntity('ReviveTarget', NULL) + ply.ReviveProgress = 0 + end + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_waves.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_waves.lua new file mode 100644 index 0000000..f7e8aa6 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/server/sv_waves.lua @@ -0,0 +1,651 @@ +SuR.Zombies_In_Wave = 8 +SuR.Time_Before_Wave = 0 +SuR.Wave_Started = false +SuR.Wave_Changing = false +SuR.Current_Wave = 0 +SuR.Enemy_To_Spawn = 0 +SuR.Game_Started = false +SuR.Delay_For_Spawn_Zombie = 0 +SuR.Delay_For_Spawn_Loot = 0 +SuR.Delay_Before_Lose = 0 +SuR.Max_Zombies_On_Map = SuR.Config.Max_Zombies_On_Map +SuR.TimerCountdown = false +SuR.AllowSpawn = false +SuR.DeployTime = CurTime()+SuR.Config.Delay_Before_Deploy +SuR.SpecialInfectedChance = 20 +SuR.ActiveMutator = 0 +SuR.Current_Boss = nil +SuR.ExfilWave = false +SuR.ExfilSuccess = false +SuR.ObjectiveFuelNeed = 1 +SuR.ObjectiveFuel = 0 +SuR.DisableMusic = false + +function SuR:ChangeStateOfGame(state) + if state then + hook.Call("SuR.GameState", nil, true) + SuR.Delay_For_Spawn_Zombie = 0 + SuR.Delay_For_Spawn_Loot = CurTime()+SuR.Config.Loot_Spawn_Delay + SuR.Zombies_In_Wave = SuR.Config.Start_Zombie_Count + if SuR.Config.Open_Func_Doors then + for _, d in ipairs(ents.FindByClass("func_door")) do + d:Fire('Open') + d:Fire('Lock') + end + end + if SuR.Config.Delete_Map_Items then + SuR:DeleteItems() + end + if SuR.Config.Delete_Map_Logic then + SuR:DeleteLogic() + end + for _, ply in ipairs(player.GetAll()) do + ply:SetTeam(1) + end + if SuR.Config.Objective_Mode then + SuR:StartObjectiveWave() + else + SuR:ChangeWave() + SuR:ShowTips("survival") + end + SuR:EnablePropDamage() + SuR:SpawnZone() + SuR:SpawnInvisWalls() + else + SuR:StopExfil() + timer.Remove("SuR.ObjectiveGasLeak") + hook.Call("SuR.GameState", nil, false) + SuR.Game_Started = false + SuR.Wave_Changing = false + SuR.ExfilSuccess = false + SuR.DisableMusic = false + SuR.Time_Before_Wave = 0 + SuR.Wave_Started = false + SuR.Current_Wave = 0 + SuR.Enemy_To_Spawn = 0 + SuR.Delay_For_Spawn_Zombie = 0 + SuR.Delay_For_Spawn_Loot = 0 + SuR.ActiveMutator = 0 + SuR.AllowSpawn = false + SuR.SpecialInfectedChance = 20 + SuR.Zombies_In_Wave = SuR.Config.Start_Zombie_Count + SuR.ObjectiveFuelNeed = 1 + SuR.ObjectiveFuel = 0 + SuR:SendDataToClient("Wave", 0) + SuR:SendDataToClient("WaveState", false, 1) + SuR:SendDataToClient("Mutator", 0) + for _, ply in ipairs(player.GetAll()) do + if ply:Alive() then ply:Kill() end + timer.Simple(0.1, function() + if !IsValid(ply) then return end + ply:SetTeam(1) + ply:SetModel("models/player/Group03/male_0"..math.random(1,9)..".mdl") + if #SuR.Config.Allowed_PlayerModels > 0 then + ply:SetModel(SuR.Config.Allowed_PlayerModels[math.random(1,#SuR.Config.Allowed_PlayerModels)]) + end + local str = ply:GetNWString('SuR_PlayerModel', '') + if str != '' then + ply:SetModel(str) + end + end) + end + game.CleanUpMap() + end +end + +function SuR:SpawnZone() + local radius, position = SuR.Config.Zone_Radius, SuR.Config.Zone_Center_Position + if radius > 250 then + local z = ents.Create("sur_zone") + z:SetPos(position) + z:Spawn() + end +end + +function SuR:SpawnInvisWalls() + for k, v in pairs(SuR.Config.Invisible_Walls) do + local ent = ents.Create("prop_dynamic") + ent:SetPos(v.pos) + ent:SetAngles(v.ang) + ent:SetModel(v.model) + ent:Spawn() + ent:SetSolid(SOLID_VPHYSICS) + ent:PhysicsInit(SOLID_VPHYSICS) + if IsValid(ent:GetPhysicsObject()) then + ent:GetPhysicsObject():EnableMotion(false) + end + ent:SetNoDraw(true) + end +end + +function SuR:StartWave() + SuR:PlaySoundOnClient("surrounded/wave_start.mp3") + SuR.Wave_Started = true + SuR.Wave_Changing = false + SuR:SendDataToClient("Wave", SuR.Current_Wave) + SuR:SendDataToClient("WaveState", true, 1) + SuR:MessageOnClient(2) + if SuR.Config.Versus_Mode and SuR.Current_Wave == 1 and player.GetCount() > 1 and SuR:CurrentPlayerZombies() == 0 then + local ply = table.Random(player.GetAll()) + ply:SuR_MakeZombie() + SuR:MessageOnClient(14, nil, ply) + end + + if SuR.ActiveMutator == 11 then + SuR:StartGasExfil() + end + + if SuR.Current_Wave == 1 then + SuR:ShowTips("waves") + end + + if SuR.Config.Versus_Mode then + for _, ply in ipairs(player.GetAll()) do + if ply:IsZombie() and !ply:Alive() then + ply:Spawn() + end + end + end + + local boss = SuR.Config.Bosses[SuR.Current_Wave] + if istable(boss) then + local pos = SuR:GetRandomPos(SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + if math.random(1,10) == 1 or !isvector(pos) then + pos = SuR:GetRandomPos(!SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + end + + if isvector(pos) then + local ent = ents.Create(boss.class) + if boss.class == "npc_vj_lnr_butcher_chainsaw" then + ent.AnimTbl_Run = {ACT_RUN} + end + ent:SetPos(pos+Vector(0,0,4)) + ent.NoRemove = true + ent:Spawn() + local hp = boss.health+((player.GetCount()-1)*(boss.health/10)) + ent:SetMaxHealth(hp) + ent:SetHealth(hp) + if SuR.ActiveMutator == 4 then + ent:SetHealth(ent:Health()/4) + end + ent.IsZombie = true + ent.FollowPlayer = false + ent.IsSpecial = true + ent.IsBoss = true + ent:RewriteLNR(true) + ent.FlinchChance = 50 + ent.CustomOnFlinch_BeforeFlinch = function() end + ent.CustomOnTakeDamage_AfterDamage = function() end + SuR.Enemy_To_Spawn = SuR.Enemy_To_Spawn - 1 + SuR.Current_Boss = ent + SuR:ShowTips("bosses") + timer.Create("ZombieMoveLogic"..ent:EntIndex(), 30, 0, function() + if IsValid(ent) then + local ply = SuR:PickRandomPlayer(true) + if IsValid(ply) then + local pos = ply:GetPos() + ent:SetLastPosition(pos) + ent:VJ_TASK_GOTO_LASTPOS() + end + else + timer.Remove("ZombieMoveLogic"..ent:EntIndex()) + end + end) + + timer.Simple(3, function() + if !IsValid(ent) then return end + + net.Start("SuR.Boss") + net.WriteString(boss.name) + net.WriteEntity(ent) + net.Broadcast() + end) + end + end +end + +function SuR:StartObjectiveWave() + SuR.Game_Started = true + SuR.Time_Before_Wave = math.huge + for _, ply in ipairs(player.GetAll()) do + ply:SetTeam(1) + ply:Spawn() + ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0) + end + BroadcastLua([[SuR:StartPhrase() SuR:PlayMusicOther("")]]) + SuR.Enemy_To_Spawn = math.huge + SuR.Config.Versus_Mode = false + + local count = math.Clamp(math.floor(8*(player.GetCount()/2)), 4, SuR.Config.Objective_Mode_Max_Cans) + local gen_count = math.Clamp(math.floor(count/4), 1, #SuR.Config.Objective_Mode_Positions["generator"]) + local to_fuel = math.ceil(count/gen_count) + local pos_tab = table.Copy(SuR.Config.Objective_Mode_Positions["generator"]) + SuR.ObjectiveFuel = 0 + SuR.ObjectiveFuelNeed = count + table.Shuffle(pos_tab) + SuR:SendDataToClient("MaxFuel", count) + SuR:SendDataToClient("Fuel", 0) + for i = 1, gen_count do + local tab = pos_tab[i] + if not tab then continue end + + local ent = ents.Create("sur_generator") + ent.ToFuel = to_fuel + ent.obj = true + ent:SetPos(tab.pos) + ent:SetAngles(tab.ang) + ent:Spawn() + end + timer.Simple(15, function() + if not SuR.Game_Started then return end + SuR.Wave_Started = true + for i = 1, count do + SuR:SpawnFuel() + end + end) + timer.Create("SuR.ObjectiveGasLeak", math.random(180,1200), 1, function() + if 25 < math.random(1,100) or SuR.ObjectiveFuelNeed == SuR.ObjectiveFuel then return end + SuR.ActiveMutator = 11 + SuR:SendDataToClient("Mutator", SuR.ActiveMutator) + SuR:StartGasExfil() + end) + SuR.SpecialInfectedChance = 40 + SuR.Current_Wave = SuR.Config.Objective_Mode_Wave + SuR.Wave_Changing = false + SuR:SendDataToClient("Wave", SuR.Current_Wave) + SuR:SendDataToClient("WaveState", true, 1) +end + +function SuR:ChangeWave() + SuR:SendDataToClient("WaveState", false) + SuR:SendDataToClient("Mutator", 0) + SuR.ActiveMutator = 0 + local rnd = math.random(1,12) + if SuR.Config.Mutator_Chance >= math.random(1,100) then + SuR.ActiveMutator = rnd + if rnd == 7 then + for _, e in ipairs(ents.FindByClass("sur_loot")) do + e:Remove() + end + end + end + SuR.Time_Before_Wave = CurTime()+math.max(SuR.Config.Delay_Before_Wave, 20) + SuR.Wave_Started = false + SuR.Wave_Changing = true + SuR.TimerCountdown = false + SuR.Current_Wave = SuR.Current_Wave + 1 + timer.Simple(10, function() + if not SuR.Game_Started then return end + + if SuR.Current_Wave == 3 or SuR.Current_Wave == 6 or SuR.Current_Wave == 10 or SuR.Current_Wave == 15 then + SuR:MessageOnClient(11) + end + end) + timer.Simple(20, function() + if not SuR.Game_Started or SuR.ActiveMutator == 0 then return end + + SuR:SendDataToClient("Mutator", SuR.ActiveMutator) + SuR:MessageOnClient(12) + end) + SuR.Zombies_In_Wave = math.floor(SuR.Zombies_In_Wave+SuR.Config.Zombie_Multiplier_Per_Wave+(SuR.Config.Zombie_Multiplier_Per_Player*player.GetCount())) + SuR.Enemy_To_Spawn = SuR.Zombies_In_Wave + SuR.SpecialInfectedChance = math.Clamp(SuR.Current_Wave*5, 1, 75) + if !SuR.Game_Started then + SuR.Game_Started = true + BroadcastLua([[SuR:PlayMusicOther(table.Random(SuR.Config.MusicWave["Start"])) SuR:StartPhrase()]]) + SuR:MessageOnClient(1) + SuR.Zombies_In_Wave = SuR.Zombies_In_Wave + else + SuR:PlaySoundOnClient("surrounded/wave_complete.mp3") + SuR:MessageOnClient(3) + end + if !SuR.Config.Versus_Mode or SuR.Current_Wave == 1 then + for _, ply in ipairs(player.GetAll()) do + if !ply:Alive() then + ply:SetTeam(1) + ply:Spawn() + ply:ScreenFade(SCREENFADE.IN, color_black, 1, 0) + end + if SuR.Current_Wave != 1 then + ply:AddXP(SuR.Config.XP_Giving["wave_complete"]) + end + end + end +end + +function SuR:GetRandomClass(type) + local class = "" + local boolean = false + if type == "zombie" then + class = SuR.Config.Zombies.walker[math.random(1,#SuR.Config.Zombies.walker)] + if SuR.Current_Wave >= SuR.Config.Runners_On_Wave and math.random(1,2) == 1 or SuR.Current_Wave >= SuR.Config.Only_Runners_On_Wave or SuR.ExfilWave then + class = SuR.Config.Zombies.runner[math.random(1,#SuR.Config.Zombies.runner)] + end + if SuR.SpecialInfectedChance >= math.random(1,100) or SuR.ActiveMutator == 2 then + local tab = SuR:GiveRandomTableWithChance(SuR.Config.Zombies.special, function(tab) + return tab.wave <= SuR.Current_Wave or SuR.ExfilWave + end) + if istable(tab) then + class = tab.class + boolean = true + end + end + end + if type == "loot" then + local tab, num = SuR:GiveRandomTableWithChance(LootItems) + class = num + end + if type == "weapon" then + class = SuR.Config.TierWeapons["Tier2"][math.random(1,#SuR.Config.TierWeapons["Tier2"])] + if SuR.Config.Loot_Tier3SpawnWave <= SuR.Current_Wave and math.random(1,3) > 1 then + class = SuR.Config.TierWeapons["Tier3"][math.random(1,#SuR.Config.TierWeapons["Tier3"])] + end + if SuR.Config.Loot_Tier4SpawnWave <= SuR.Current_Wave and math.random(1,3) == 1 then + class = SuR.Config.TierWeapons["Tier4"][math.random(1,#SuR.Config.TierWeapons["Tier4"])] + end + if SuR.Config.Loot_Tier5SpawnWave <= SuR.Current_Wave and math.random(1,4) == 1 then + class = SuR.Config.TierWeapons["Tier5"][math.random(1,#SuR.Config.TierWeapons["Tier5"])] + end + if math.random(1,100) <= SuR.Config.Melee_Spawn_Chance then + class = SuR.Config.TierWeapons["Other"][math.random(1,#SuR.Config.TierWeapons["Other"])] + end + if math.random(1,100) <= SuR.Config.Other_Spawn_Chance then + class = SuR.Config.TierWeapons["Melee"][math.random(1,#SuR.Config.TierWeapons["Melee"])] + end + end + return class, boolean +end + +function SuR:SpawnLoot(pos) + if SuR.Delay_For_Spawn_Loot > CurTime() or !SuR.Game_Started or SuR.Wave_Started and !isvector(pos) or SuR.ActiveMutator == 7 then return end + + local tab = ents.GetAll() + local count = 0 + for i=1,#tab do + local ent = tab[i] + if not ent.IsLoot then continue end + count = count + 1 + end + if count >= player.GetCount()*SuR.Config.Loot_Max_Per_Player then return end + + SuR.Delay_For_Spawn_Loot = CurTime()+SuR.Config.Loot_Spawn_Delay + + local weapon = nil + local type = "loot" + if not SuR.Config.Objective_Mode and math.random(1,6) == 1 and SuR.Current_Wave > 1 or SuR.Config.Objective_Mode and math.random(1,10) == 1 then + type = "weapon" + end + local class = SuR:GetRandomClass(type) + if !isvector(pos) then + pos = SuR:FindSpawnPositions(table.Random(SuR.Config.Loot_SpawnPositions), 250) + end + + if type == "weapon" then + local cl = class + local tab = weapons.Get(class) + if tab then + weapon = { + name = tab.PrintName, + class = cl, + model = tab.WorldModel, + usefunc = function(self, ply) + ply:Give(cl) + end + } + end + end + + if isvector(pos) then + local ent = ents.Create("sur_loot") + ent.LootType = class + ent.Weapon = weapon + ent:SetPos(pos) + ent:Spawn() + ent.IsLoot = true + end +end + +function SuR:SpawnFuel(pos) + if !isvector(pos) then + pos = table.Random(SuR.Config.Objective_Mode_Positions["fuel"]) + end + + local weapon = { + name = "Jerry Can", + class = "sur_fuel", + model = "models/surrounded/obj/w_JerryCanBlue.mdl", + usefunc = function(self, ply) + ply:Give("sur_fuel") + end + } + + local ent = ents.Create("sur_loot") + ent.Weapon = weapon + ent:SetPos(pos) + ent.NoRemove = true + ent.obj = true + ent:Spawn() + if IsValid(ent:GetPhysicsObject()) then + ent:GetPhysicsObject():SetVelocity(VectorRand(-100,100)) + end + ent.IsLoot = true +end + +function SuR:SpawnEnemy() + if SuR.Delay_For_Spawn_Zombie > CurTime() or !SuR.Game_Started or SuR.Enemy_To_Spawn == 0 or !SuR.Wave_Started or SuR:CurrentAliveEnemies() >= SuR.Max_Zombies_On_Map then return end + + local del = CurTime()+(SuR.Config.Zombie_Spawn_Delay/(SuR.Current_Wave/2)) + if SuR.ExfilWave or SuR.Config.Objective_Mode then + del = CurTime()+1 + end + SuR.Delay_For_Spawn_Zombie = del + local pos = SuR:GetRandomPos(SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + if math.random(1,10) == 1 or !isvector(pos) then + pos = SuR:GetRandomPos(!SuR.Config.Enable_Spawn_In_Building_Zombies, SuR.Config.Zombie_Spawn_Radius_Min, SuR.Config.Zombie_Spawn_Radius_Max) + end + local class, isspecial = SuR:GetRandomClass("zombie") + + if isvector(pos) then + local ent = ents.Create(class) + ent:SetPos(pos+Vector(0,0,4)) + ent.TimeBeforeDeath = CurTime()+120 + ent:Spawn() + ent:SetHealth(ent:Health()+math.floor(2*SuR.Current_Wave*(SuR.Config.Zombie_Multiplier_Per_Wave+SuR.Config.Zombie_Multiplier_Per_Player))) + if SuR.ActiveMutator == 4 then + ent:SetHealth(ent:Health()/4) + end + ent.IsZombie = true + ent.FollowPlayer = false + ent.IsSpecial = isspecial + ent:RewriteLNR(isspecial) + SuR.Enemy_To_Spawn = SuR.Enemy_To_Spawn - 1 + timer.Create("ZombieMoveLogic"..ent:EntIndex(), 30, 0, function() + if IsValid(ent) then + local ply = SuR:PickRandomPlayer(true) + if IsValid(ply) then + local pos = ply:GetPos() + ent:SetLastPosition(pos) + ent:ClearCondition(COND_ENEMY_UNREACHABLE) + ent:VJ_TASK_GOTO_LASTPOS() + end + else + timer.Remove("ZombieMoveLogic"..ent:EntIndex()) + end + end) + end +end + +hook.Add("SetupPlayerVisibility", "SuR_FixBossBar", function() + if IsValid(SuR.Gas_Entity) then + AddOriginToPVS(SuR.Gas_Entity:GetPos()) + end + if not SuR.Config.Allow_PVS_Info then return end + if IsValid(SuR.Current_Boss) then + AddOriginToPVS(SuR.Current_Boss:GetPos()) + end + if SuR.Config.Objective_Mode then + for _, ent in ipairs(ents.FindByClass("sur_*")) do + if !ent.obj and ent:GetModel() != "models/surrounded/obj/w_jerrycanblue.mdl" then return end + AddOriginToPVS(ent:GetPos()) + end + end + for _, ply in ipairs(player.GetAll()) do + if !ply:IsSurvivor() then return end + AddOriginToPVS(ply:GetPos()) + end +end) + +local clear_delay = 0 +local airdrop_delay = 0 +hook.Add("Think", "SuR_GameLogic", function() + if SuR.Game_Started and SuR.Current_Wave > 0 then + if SuR.Time_Before_Wave < CurTime() and not SuR.Wave_Started then + SuR:StartWave() + hook.Call("SuR.WaveState", nil, SuR.Current_Wave, true) + end + + if not SuR.TimerCountdown and SuR.Time_Before_Wave <= CurTime()+10 and not SuR.Wave_Started then + SuR.TimerCountdown = true + SuR:Countdown(10) + end + + if SuR.Wave_Started then + SuR:SpawnEnemy() + + if SuR.ExfilWave and SuR.Enemy_To_Spawn <= 0 then + SuR.Enemy_To_Spawn = 1 + end + + if airdrop_delay < CurTime() and SuR.ActiveMutator == 8 then + SuR:CallSupport(nil, 1) + airdrop_delay = CurTime()+60 + elseif SuR.ActiveMutator != 8 then + airdrop_delay = CurTime()+60 + end + + if SuR:CurrentAliveEnemies() == 0 and SuR.Enemy_To_Spawn <= 0 then + SuR:ChangeWave() + hook.Call("SuR.WaveState", nil, SuR.Current_Wave, false) + end + + if SuR:CurrentAliveEnemies() <= 3 then + local tab = ents.FindByClass("npc_*") + for i=1,#tab do + local ent = tab[i] + if not ent.IsZombie then continue end + ent.TimeOverDeath = ent.TimeOverDeath - FrameTime() + if ent.TimeOverDeath < 0 and not ent.NoRemove then + ent:Remove() + end + end + end + + SuR:SendDataToClient("Enemies", SuR:CurrentAliveEnemies()+SuR.Enemy_To_Spawn) + + if clear_delay < CurTime() then + RunConsoleCommand("ai_clear_bad_links") + clear_delay = CurTime()+1 + end + end + + if SuR.Config.Objective_Mode then + SuR:SendDataToClient("MaxFuel", SuR.ObjectiveFuelNeed) + SuR:SendDataToClient("Fuel", SuR.ObjectiveFuel) + end + + local tab = SuR:CurrentFighters(player.GetCount() == 1) + if tab > 0 then + SuR.Delay_Before_Lose = CurTime()+10 + end + + if !SuR.Wave_Started then + SuR.Delay_Before_Lose = CurTime()+10 + end + + local tab = ents.FindByClass("npc_*") + for i=1,#tab do + local ent = tab[i] + if not ent.IsZombie then continue end + local en = ent:GetEnemy() + if ent.ExecutingTarget then + if !IsValid(ent.ExecutingModel) then + ent:SetPos(ent.ExecutingPos) + end + end + if !ent:IsInWorld() and not ent.ExecutingTarget then + ent:TakeDamage(100) + end + if !ent.NoRemove then + if IsValid(en) and !ent:HasCondition(31) and not SuR.Config.Objective_Mode then + ent.TimeBeforeDeath = CurTime()+60 + end + if ent.TimeBeforeDeath < CurTime() then + ent:TakeDamage(100) + end + end + if ent.ExecutingTarget then + ent:SetState(VJ_STATE_FREEZE) + end + ent:SetNWBool('flinching', ent.Flinching) + end + + if SuR.Delay_Before_Lose > CurTime() then + SuR:SpawnLoot() + else + net.Start("SuR.GameOverScreen") + net.WriteFloat(SuR.Current_Wave) + net.WriteBool(SuR.ExfilSuccess) + net.Broadcast() + SuR:ChangeStateOfGame(false) + timer.Simple(SuR.Config.Game_Over_Screen_Delay, function() + if SuR.Game_Started then return end + SuR:ShowDeployCutscene(player.GetAll(), true) + end) + end + SuR.DeployTime = CurTime()+SuR.Config.Delay_Before_Deploy + end + if not SuR.Game_Started then + if player.GetCount() > 0 and not SuR.DisableLogic then + if SuR.DeployTime < CurTime() then + SuR:ChangeStateOfGame(true) + end + else + SuR.DeployTime = CurTime()+SuR.Config.Delay_Before_Deploy+30 + end + end + SuR:SendDataToClient("Deploying", !SuR.Game_Started) + SuR:SendDataToClient("DeployTime", SuR.DeployTime) + SuR:SendDataToClient("ExfilWave", SuR.ExfilWave) + SuR:SendDataToClient("DisableMusic", SuR.DisableMusic) +end) + +hook.Add("OnEntityCreated", "SuR_NPCChanges", function(ent) + if ent:GetClass() == "npc_vj_lnr_evo" or ent:GetClass() == "npc_vj_lnr_ravager" then + ent.LeapDistance = 400 + ent.LeapToMeleeDistance = 400 + ent.NextLeapAttackTime = 10 + ent.NextAnyAttackTime_Leap = 10 + end +end) + +concommand.Add("sur_startgame", function(ply) + if !ply:IsSuperAdmin() or SuR.Game_Started then return end + SuR:ChangeStateOfGame(true) + SuR:ShowDeployCutscene(player.GetAll(), false) +end) + +concommand.Add("sur_skipwave", function(ply, smd, args) + if !ply:IsSuperAdmin() or !SuR.Game_Started then return end + + local arg = tonumber(args[1]) + if isnumber(arg) then + SuR.Current_Wave = arg-1 + end + SuR.Enemy_To_Spawn = 0 + local tab = ents.FindByClass("npc_*") + for i=1,#tab do + local ent = tab[i] + if not ent.IsZombie then continue end + ent:Remove() + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared.lua new file mode 100644 index 0000000..10c72f5 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared.lua @@ -0,0 +1,500 @@ +SuR = SuR or {} + +SuR.Version = "0.6.0" +SuR.Build = "alpha" +SuR.DisableLogic = false + +GM.Name = "Surrounded" +GM.Author = "RefoselTeamWork" + +AddCSLuaFile('shared/sh_cvars.lua') +include('shared/sh_cvars.lua') + +AddCSLuaFile("lang/en.lua") +AddCSLuaFile("lang/ru.lua") + +SuR.Language = {} +local function change_language() + local lang = GetConVar("gmod_language"):GetString() + if lang == "ru" or lang == "uk" then + include("lang/ru.lua") + else + include("lang/en.lua") + end +end +change_language() + +local def_tracks = { + ["Exfil"] = {"surrounded/theme/music32.mp3"}, + ["Easy"] = {"surrounded/theme/music11.mp3", "surrounded/theme/music14.mp3", "surrounded/theme/music15.mp3", "surrounded/theme/music25.mp3", "surrounded/theme/music26.mp3", "surrounded/theme/music27.mp3", "surrounded/theme/music28.mp3"}, + ["Medium"] = {"surrounded/theme/music2.mp3", "surrounded/theme/music7.mp3", "surrounded/theme/music1.mp3", "surrounded/theme/music33.mp3", "surrounded/theme/music34.mp3", "surrounded/theme/music35.mp3"}, + ["Hard"] = {"surrounded/theme/music3.mp3", "surrounded/theme/music10.mp3", "surrounded/theme/music12.mp3", "surrounded/theme/music29.mp3", "surrounded/theme/music30.mp3", "surrounded/theme/music31.mp3"}, + ["Chaos"] = {"surrounded/theme/music9.mp3", "surrounded/theme/music5.mp3", "surrounded/theme/music13.mp3", "surrounded/theme/music16.mp3", "surrounded/theme/music17.mp3", "surrounded/theme/music21.mp3", "surrounded/theme/music23.mp3"}, + ["Extreme"] = {"surrounded/theme/music4.mp3", "surrounded/theme/music6.mp3", "surrounded/theme/music8.mp3", "surrounded/theme/music18.mp3", "surrounded/theme/music19.mp3", "surrounded/theme/music20.mp3", "surrounded/theme/music22.mp3", "surrounded/theme/music24.mp3"}, + ["Objective"] = {"surrounded/theme/obj1.mp3", "surrounded/theme/obj2.mp3", "surrounded/theme/obj3.mp3", "surrounded/theme/obj4.mp3", "surrounded/theme/obj5.mp3"}, + ["Countdown"] = {"surrounded/theme/countdown1.mp3", "surrounded/theme/countdown2.mp3", "surrounded/theme/countdown3.mp3"}, + + ["Deploy"] = {"surrounded/theme/deploy.mp3"}, + ["Start"] = {"surrounded/theme/start.mp3"}, + ["GameOver"] = {"surrounded/theme/game_over.mp3"}, + ["ExfilOver"] = {"surrounded/theme/exfil_over.mp3"}, +} + +SuR.Config = { + MusicWave = def_tracks, + DefaultMusicWave = def_tracks, + + EmptyWeapon = "tfa_nmrih_fists", + SecondaryWeapons = { + "tfa_private_p99", + "tfa_private_p226", + "tfa_private_mp412", + "tfa_private_p220", + "tfa_private_jericho", + "tfa_private_vp70", + "tfa_private_usp45", + "tfa_private_glock17", + "tfa_private_44magnum", + "tfa_private_glock18c", + "tfa_private_deagle", + "tfa_private_dual_m9_samurai", + "tfa_private_micro_roni", + "tfa_private_chinalake", + "tfa_private_milkor_mgl", + "tfa_private_m79", + "tfa_private_m72", + "sur_mine", + }, + OtherWeapons = { + "sur_artillery_strike", + "sur_hammer", + "sur_fuel", + }, + + TierWeapons = { + ["Other"] = {"sur_hammer"}, + ["Melee"] = {"tfa_nmrih_kknife", "tfa_nmrih_bcd", "tfa_nmrih_bat", "tfa_nmrih_asaw", "tfa_nmrih_chainsaw", "tfa_nmrih_wrench", "tfa_nmrih_spade", "tfa_nmrih_sledge", "tfa_nmrih_pickaxe", "tfa_nmrih_machete", "tfa_nmrih_lpipe", "tfa_nmrih_hatchet", "tfa_nmrih_fubar", "tfa_nmrih_fireaxe", "tfa_nmrih_etool", "tfa_nmrih_crowbar", "tfa_nmrih_cleaver"}, + ["Tier1"] = {"tfa_private_p99", "tfa_private_p226", "tfa_private_mp412", "tfa_private_p220", "tfa_private_jericho", "tfa_private_vp70", "tfa_private_usp45", "tfa_private_glock17"}, + ["Tier2"] = {"tfa_private_ump45", "tfa_private_m1cgarand", "tfa_private_winchester1897", "tfa_private_dual_m9_samurai", "tfa_private_famas", "tfa_private_9a91", "tfa_private_tmp", "tfa_private_aug_para", "tfa_private_pp2000", "tfa_private_kriss_vector", "tfa_private_m45", "tfa_private_uzi_pro", "tfa_private_mp5", "tfa_private_mp7", "tfa_private_44magnum", "tfa_private_glock18c", "tfa_private_deagle"}, + ["Tier3"] = {"tfa_private_m79", "tfa_private_m72", "tfa_private_mp5swordfish", "tfa_private_kriss_carbine", "tfa_private_micro_roni", "tfa_private_sig_mcx", "tfa_private_sg751", "tfa_private_sg552", "tfa_private_ar15", "tfa_private_sa58", "tfa_private_galil_arm", "tfa_private_type89", "tfa_private_type64", "tfa_private_hk433", "tfa_private_hk416c", "tfa_private_hk416mod3", "tfa_private_hk416", "tfa_private_xm8", "tfa_private_g36", "tfa_private_fal_ferret", "tfa_private_fedorov", "tfa_private_k2c", "tfa_private_cz805", "tfa_private_ro933", "tfa_private_edge_rifle", "tfa_private_ak12", "tfa_private_ak105", "tfa_private_sl8", "tfa_private_mk20", "tfa_private_pss10", "tfa_private_m500_magpul", "tfa_private_remington870", "tfa_private_bizon", "tfa_private_p90", "tfa_private_ak74u", "tfa_private_honeybadger"}, + ["Tier4"] = {"tfa_private_ppsh41", "tfa_private_chinalake", "tfa_private_ultimax100", "tfa_private_galil_sar", "tfa_private_dsr", "tfa_private_m200", "tfa_private_ksg12", "tfa_private_harms_cqr"}, + ["Tier5"] = {"tfa_private_milkor_mgl", "tfa_private_m60", "tfa_private_m240g", "tfa_private_mk46", "tfa_private_tac50", "tfa_private_m82", "tfa_private_aa12", "tfa_private_mg34", "tfa_private_mg42"}, + }, + + Tier_Colors = { + [1] = Color(150,150,150), + [2] = Color(75,150,0), + [3] = Color(200,200,0), + [4] = Color(230,150,0), + [5] = Color(200,40,40), + }, + + Tier2_Price = 25, + Tier3_Price = 100, + Tier4_Price = 275, + Tier5_Price = 500, + + Weapons_Executions_Anims = { + ["chainsaw"] = {"tfa_nmrih_chainsaw"}, + ["abrasivechainsaw"] = {"tfa_nmrih_asaw"}, + ["axe"] = {"tfa_nmrih_fireaxe"}, + ["hammer"] = {"tfa_nmrih_bcd"}, + ["shovel"] = {"tfa_nmrih_spade"}, + ["etool"] = {"tfa_nmrih_etool"}, + ["wrench"] = {"tfa_nmrih_wrench"}, + ["fubar"] = {"tfa_nmrih_fubar"}, + ["crowbar"] = {"tfa_nmrih_crowbar"}, + ["machete"] = {"tfa_nmrih_machete"}, + ["butcherknife"] = {"tfa_nmrih_cleaver"}, + ["pickaxe"] = {"tfa_nmrih_pickaxe"}, + ["pipe"] = {"tfa_nmrih_lpipe"}, + ["sledge"] = {"tfa_nmrih_sledge"}, + ["bat"] = {"tfa_nmrih_bat"}, + ["knife"] = {"tfa_nmrih_kknife"}, + ["handaxe"] = {"tfa_nmrih_hatchet"}, + }, + + Melee_Spawn_Chance = 10, + Other_Spawn_Chance = 3, + + ClassIcons = { + ["survivor"] = Material('surrounded/classes/survivor.png', 'noclamp smooth'), + ["scout"] = Material('surrounded/classes/scout.png', 'noclamp smooth'), + ["medic"] = Material('surrounded/classes/medic.png', 'noclamp smooth'), + ["engineer"] = Material('surrounded/classes/engineer.png', 'noclamp smooth'), + ["demoman"] = Material('surrounded/classes/demoman.png', 'noclamp smooth'), + ["marksman"] = Material('surrounded/classes/marksman.png', 'noclamp smooth'), + ["berserker"] = Material('surrounded/classes/berserker.png', 'noclamp smooth'), + }, + + VoicePacks = { + ["Default [EN]"] = { + ["pain"] = "surrounded/player/en/pain/", + ["death"] = "surrounded/player/en/death/", + ["reload"] = "surrounded/player/en/reload/", + ["enemyback"] = "surrounded/player/en/enemyback/", + ["enemydown"] = "surrounded/player/en/enemydown/", + ["pickup"] = "surrounded/player/en/pickup/", + ["noammo"] = "surrounded/player/en/noammo/", + ["downed"] = "surrounded/player/en/downed/", + ["friendlyfire"] = "surrounded/player/en/friendlyfire/", + ["frienddied"] = "surrounded/player/en/frienddied/", + ["lowhp"] = "surrounded/player/en/lowhp/", + ["infected"] = "surrounded/player/en/infected/", + ["enemyspotted"] = "surrounded/player/en/enemyspotted/", + ["thanks"] = "surrounded/player/en/thanks/", + ["cover"] = "surrounded/player/en/cover/", + }, + ["Sam"] = { + ["pain"] = "surrounded/player/sam_en/pain/", + ["death"] = "surrounded/player/sam_en/death/", + ["reload"] = "surrounded/player/sam_en/reload/", + ["enemyback"] = "surrounded/player/sam_en/enemyback/", + ["enemydown"] = "surrounded/player/sam_en/enemydown/", + ["pickup"] = "surrounded/player/sam_en/pickup/", + ["noammo"] = "surrounded/player/sam_en/noammo/", + ["downed"] = "surrounded/player/sam_en/downed/", + ["friendlyfire"] = "surrounded/player/sam_en/friendlyfire/", + ["frienddied"] = "surrounded/player/sam_en/frienddied/", + ["lowhp"] = "surrounded/player/sam_en/lowhp/", + ["infected"] = "surrounded/player/sam_en/infected/", + ["enemyspotted"] = "surrounded/player/sam_en/enemyspotted/", + ["thanks"] = "surrounded/player/sam_en/thanks/", + ["cover"] = "surrounded/player/sam_en/cover/", + }, + ["Default [RU]"] = { + ["pain"] = "surrounded/player/ru/pain/", + ["death"] = "surrounded/player/ru/death/", + ["reload"] = "surrounded/player/ru/reload/", + ["enemyback"] = "surrounded/player/ru/enemyback/", + ["enemydown"] = "surrounded/player/ru/enemydown/", + ["pickup"] = "surrounded/player/ru/pickup/", + ["noammo"] = "surrounded/player/ru/noammo/", + ["downed"] = "surrounded/player/ru/downed/", + ["friendlyfire"] = "surrounded/player/ru/friendlyfire/", + ["frienddied"] = "surrounded/player/ru/frienddied/", + ["lowhp"] = "surrounded/player/ru/lowhp/", + ["infected"] = "surrounded/player/ru/infected/", + ["enemyspotted"] = "surrounded/player/ru/enemyspotted/", + ["thanks"] = "surrounded/player/ru/thanks/", + ["cover"] = "surrounded/player/ru/cover/", + }, + }, + + Blocked_PlayerModels = { + "models/player/charple.mdl", + "models/player/corpse1.mdl", + "models/player/skeleton.mdl", + "models/player/zombie_classic.mdl", + "models/player/zombie_fast.mdl", + "models/player/zombie_soldier.mdl", + "models/player/soldier_stripped.mdl", + }, + Allowed_PlayerModels = {}, + + Zombies = { + walker = { + "npc_vj_lnrhl2_citizenf_wal", + "npc_vj_lnrhl2_citizenm_wal", + "npc_vj_lnrhl2_medicf_wal", + "npc_vj_lnrhl2_medicm_wal", + "npc_vj_lnrhl2_rebelf_wal", + "npc_vj_lnrhl2_rebelm_wal", + }, + runner = { + "npc_vj_lnrhl2_citizenf_inf", + "npc_vj_lnrhl2_citizenm_inf", + "npc_vj_lnrhl2_medicf_inf", + "npc_vj_lnrhl2_medicm_inf", + "npc_vj_lnrhl2_rebelm_inf", + "npc_vj_lnrhl2_rebelf_inf", + }, + special = { + { + class = "npc_vj_lnr_shambler", + chance = 10, + wave = 1, + }, + { + class = "npc_vj_lnr_healer", + chance = 20, + wave = 2, + }, + { + class = "npc_vj_lnrhl2_rebel_hvy", + chance = 30, + wave = 3, + }, + { + class = "npc_vj_lnr_fatso", + chance = 40, + wave = 3, + }, + { + class = "npc_vj_lnr_punk", + chance = 20, + wave = 4, + }, + { + class = "npc_vj_lnr_carrier", + chance = 35, + wave = 4, + }, + { + class = "npc_vj_lnr_hazmat", + chance = 35, + wave = 5, + }, + { + class = "npc_vj_lnr_spitter", + chance = 30, + wave = 6, + }, + { + class = "npc_vj_lnr_butcher", + chance = 15, + wave = 6, + }, + { + class = "npc_vj_lnr_brute", + chance = 30, + wave = 6, + }, + { + class = "npc_vj_lnr_riot", + chance = 15, + wave = 7, + }, + { + class = "npc_vj_lnr_evo", + chance = 20, + wave = 8, + }, + { + class = "npc_vj_lnr_ravager", + chance = 20, + wave = 8, + }, + { + class = "npc_vj_lnr_sentry", + chance = 20, + wave = 9, + }, + { + class = "npc_vj_lnr_tesla", + chance = 20, + wave = 10, + }, + { + class = "npc_vj_lnr_riot_shield", + chance = 25, + wave = 10, + }, + { + class = "npc_vj_lnr_napalm", + chance = 25, + wave = 11, + }, + { + class = "npc_vj_lnr_butcher_chainsaw", + chance = 15, + wave = 12, + }, + { + class = "npc_vj_lnr_bomber", + chance = 15, + wave = 13, + }, + { + class = "npc_vj_lnr_tyrant", + chance = 10, + wave = 14, + }, + { + class = "npc_vj_lnr_tank", + chance = 5, + wave = 15, + }, + }, + }, + Zombies_Executions = { + ["downed_machete"] = {"npc_vj_lnr_butcher", "npc_vj_lnrhl2_rebel_hvy", "npc_vj_lnr_healer"}, + ["downed_electro"] = {"npc_vj_lnr_tesla", "npc_vj_lnr_riot", "npc_vj_lnr_riot_shield", "npc_vj_lnr_bomber"}, + ["downed_guitar"] = {"npc_vj_lnr_punk"}, + ["downed_gas"] = {"npc_vj_lnr_hazmat"}, + ["downed_big"] = {"npc_vj_lnr_tyrant", "npc_vj_lnr_brute"}, + ["downed_acid"] = {"npc_vj_lnr_spitter", "npc_vj_lnr_sentry"}, + ["downed_unarmed"] = {"npc_vj_lnr_shambler", "npc_vj_lnr_carrier"}, + ["chainsaw"] = {"npc_vj_lnr_butcher_chainsaw"}, + ["berserk"] = {"npc_vj_lnr_carrier", "npc_vj_lnr_riot", "npc_vj_lnr_riot_shield", "npc_vj_lnrhl2_rebel_hvy"}, + ["jumper"] = {"npc_vj_lnr_evo", "npc_vj_lnr_ravager"}, + }, + Bosses = { + [2] = { + class = "npc_vj_lnr_punk", + health = 2000, + name = "boss_punk" + }, + [5] = { + class = "npc_vj_lnr_butcher_chainsaw", + health = 3000, + name = "boss_butcher" + }, + [9] = { + class = "npc_vj_lnr_tyrant", + health = 3000, + name = "boss_tyrant" + }, + [14] = { + class = "npc_vj_lnr_tank", + health = 7500, + name = "boss_tank" + }, + }, + Zombie_Unlock_Wave = { + ["Walker"] = 0, + ["Runner"] = 3, + ["Carrier"] = 4, + ["Hazmat"] = 5, + ["Spitter"] = 6, + ["Brute"] = 7, + ["Evo"] = 8, + ["Bomber"] = 13, + }, + Zombie_PlayerModels = { + ["Walker"] = { + "models/vj_lnrhl2/humans/group03/male_01.mdl", + "models/vj_lnrhl2/humans/group03/male_02.mdl", + "models/vj_lnrhl2/humans/group03/male_03.mdl", + "models/vj_lnrhl2/humans/group03/male_04.mdl", + "models/vj_lnrhl2/humans/group03/male_05.mdl", + "models/vj_lnrhl2/humans/group03/male_06.mdl", + "models/vj_lnrhl2/humans/group03/male_07.mdl", + "models/vj_lnrhl2/humans/group03/male_08.mdl", + "models/vj_lnrhl2/humans/group01/male_09.mdl", + "models/vj_lnrhl2/humans/group01/male_01.mdl", + "models/vj_lnrhl2/humans/group01/male_02.mdl", + "models/vj_lnrhl2/humans/group01/male_03.mdl", + "models/vj_lnrhl2/humans/group01/male_04.mdl", + "models/vj_lnrhl2/humans/group01/male_05.mdl", + "models/vj_lnrhl2/humans/group01/male_06.mdl", + "models/vj_lnrhl2/humans/group01/male_07.mdl", + "models/vj_lnrhl2/humans/group01/male_08.mdl", + "models/vj_lnrhl2/humans/group01/male_09.mdl", + }, + ["Runner"] = { + "models/vj_lnrhl2/humans/group03in/male_01.mdl", + "models/vj_lnrhl2/humans/group03in/male_02.mdl", + "models/vj_lnrhl2/humans/group03in/male_03.mdl", + "models/vj_lnrhl2/humans/group03in/male_04.mdl", + "models/vj_lnrhl2/humans/group03in/male_05.mdl", + "models/vj_lnrhl2/humans/group03in/male_06.mdl", + "models/vj_lnrhl2/humans/group03in/male_07.mdl", + "models/vj_lnrhl2/humans/group03in/male_08.mdl", + "models/vj_lnrhl2/humans/group03in/male_09.mdl", + "models/vj_lnrhl2/humans/group02/male_01.mdl", + "models/vj_lnrhl2/humans/group02/male_02.mdl", + "models/vj_lnrhl2/humans/group02/male_03.mdl", + "models/vj_lnrhl2/humans/group02/male_04.mdl", + "models/vj_lnrhl2/humans/group02/male_05.mdl", + "models/vj_lnrhl2/humans/group02/male_06.mdl", + "models/vj_lnrhl2/humans/group02/male_07.mdl", + "models/vj_lnrhl2/humans/group02/male_08.mdl", + "models/vj_lnrhl2/humans/group02/male_09.mdl", + }, + ["Carrier"] = { + "models/vj_lnrspecials/carrier.mdl", + }, + ["Hazmat"] = { + "models/vj_lnrspecials/hazmat_zombie.mdl", + }, + ["Spitter"] = { + "models/vj_lnrspecials/spitter.mdl", + }, + ["Brute"] = { + "models/vj_lnrspecials/brute.mdl", + }, + ["Evo"] = { + "models/vj_lnrspecials/evo.mdl", + }, + ["Bomber"] = { + "models/vj_lnrspecials/bomber.mdl", + }, + }, + + LoadingURL = "https://cdn.discordapp.com/attachments/905471196500471859/1162799475018965074/gm_underpass_2023-10-14_18.12.44.png", + + Delay_Before_Wave = 60, + Delay_Before_Deploy = 60, + + Zombie_Spawn_Delay = 4, + Max_Zombies_On_Map = 20, + Runners_On_Wave = 3, + Only_Runners_On_Wave = 6, + Start_Zombie_Count = 6, + Zombie_Multiplier_Per_Wave = 3, + Zombie_Multiplier_Per_Player = 1, + Zombie_Spawn_Radius_Min = 500, + Zombie_Spawn_Radius_Max = 2500, + Zombie_Grab_Chance = 15, + Zombie_Special_Grab_Chance = 20, + + Loot_HeightLimit = 4, + Loot_Spawn_Delay = 1, + Loot_Remove_Delay = 180, + Loot_Max_Per_Player = 15, + Loot_Tier3SpawnWave = 5, + Loot_Tier4SpawnWave = 9, + Loot_Tier5SpawnWave = 11, + + Game_Over_Screen_Delay = 22, + Deploy_Cutscene = {}, + + Loot_SpawnPositions = {}, + Support_SpawnPositions = {}, + Player_SpawnPositions = {}, + Gas_SpawnPositions = {}, + Camera_Position = { + Vector(0,0,0), + Angle(0,0,0), + }, + + Zone_Center_Position = Vector(), + Zone_Radius = 0, + + Invisible_Walls = {}, + + Bleedout_Time = 60, + Enable_Suicide = false, + Enable_Out_Of_Bounds_Check = true, + Enable_Dangerous_Water = false, + Delete_Map_Items = true, + Delete_Map_Logic = false, + Allow_PVS_Info = true, + Enable_Spawn_In_Building_Zombies = false, + Open_Func_Doors = false, + Mutator_Chance = 20, + Height_Of_Air = 0, + + Exfil_Wave = 6, + Exfil_Points = {}, + + Start_Level_XP = 100, + Level_Progress_Mult = 50, + XP_Giving = { + ["zombie_kill"] = 1, + ["special_kill"] = 2, + ["execution"] = 5, + ["wave_complete"] = 10, + ["fuel"] = 25, + ["boss_kill"] = 100, + ["evac_success"] = 250, + ["capsule_item"] = 500, + }, + + Versus_Mode = false, + Objective_Mode = false, + Objective_Mode_Wave = 6, + Objective_Mode_Max_Cans = 64, + Objective_Mode_Positions = {}, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared/sh_cvars.lua b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared/sh_cvars.lua new file mode 100644 index 0000000..d570756 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/gamemode/shared/sh_cvars.lua @@ -0,0 +1,259 @@ +local meta = FindMetaTable('Player') + +function meta:GetPlayerClass() + return self:GetNWString("PlayerClass", "survivor") +end + +function meta:GetLevel() + return self:GetNWFloat("PlayerLevel", 1), self:GetNWFloat("PlayerXP", 0) +end + +function meta:GetLevelState() + local lvl = self:GetLevel() + if self:IsZombie() or !self:Alive() then + return 0 + end + if lvl >= 21 then + return 5 + elseif lvl >= 16 then + return 4 + elseif lvl >= 11 then + return 3 + elseif lvl >= 6 then + return 2 + else + return 1 + end +end + +function meta:GetXPToLevel(without) + local start_xp = SuR.Config.Start_Level_XP + local lvl_mult = SuR.Config.Level_Progress_Mult + local lvl, cur_xp = self:GetLevel() + local formula = start_xp+(lvl*lvl_mult) + --formula = start_xp*lvl_mult^(lvl-1) + local need_xp = math.max(formula-cur_xp, 0) + if without then + need_xp = math.max(formula, 0) + end + + return need_xp +end + +function meta:IsSurvivor() + return self:Team() == 1 +end + +function meta:IsZombie() + return self:Team() == 2 +end + +function meta:IsDowned() + return self:GetNWBool('SuR_Downed', false) +end + +function meta:IsStunned(isidle) + return not isidle and string.match(self:GetSVAnim(), "sur_fall_") or isidle and string.match(self:GetSVAnim(), "sur_fall_idle") +end + +function meta:IsLockedAbilities() + return self:IsDowned() or self:IsStunned() or self:WaterLevel() >= 2 or self:GetNWBool('SVAnimStopCutscene') or self:GetNWBool('SVAnimStopMoving') or IsValid(self:GetNWEntity('ReviveTarget')) or self:IsZombie() +end + +function meta:GetSVAnim() + return self:GetNWString('SVAnim', '') +end + +function SuR:TransferModelData(base, model) + local ent1Model = base:GetModel() + local ent1Skin = base:GetSkin() + local ent1BodyGroups = base:GetNumBodyGroups() + model:SetModel(ent1Model) + model:SetSkin(ent1Skin) + for i = 0, ent1BodyGroups - 1 do + model:SetBodygroup(i, base:GetBodygroup(i)) + end +end + +function SuR:TransferBones(base, ragdoll, client) + if client and CLIENT then return end + if !IsValid(base) or !IsValid(ragdoll) then return end + if client then + net.Start("SuR.BecomeRagdoll") + net.WriteEntity(ragdoll) + net.Broadcast() + SafeRemoveEntityDelayed(base, 0.1) + else + for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do + local bone = ragdoll:GetPhysicsObjectNum( i ) + if ( IsValid( bone ) ) then + local pos, ang = base:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) ) + if ( pos ) then bone:SetPos( pos ) end + if ( ang ) then bone:SetAngles( ang ) end + bone:SetVelocity(-bone:GetVelocity()) + end + end + end +end + +function SuR:CurrentAliveEnemies() + local tab = {} + local tab2 = ents.FindByClass("*lnr*") + for i=1,#tab2 do + local ent = tab2[i] + if not ent.IsZombie then continue end + tab[#tab+1] = ent + end + return #tab +end + +function SuR:CurrentFighters(downed) + local tab = {} + local tab2 = player.GetAll() + for i=1,#tab2 do + local ent = tab2[i] + if not ent:Alive() or not downed and ent:IsDowned() and not ent.ExecutingTarget and ent:GetNWFloat('SelfRevive') <= 0 or ent:IsZombie() then continue end + tab[#tab+1] = ent + end + return #tab +end + +function SuR:CurrentPlayerZombies() + local tab = {} + local tab2 = player.GetAll() + for i=1,#tab2 do + local ent = tab2[i] + if not ent:IsZombie() then continue end + tab[#tab+1] = ent + end + return #tab +end + +function SuR:PickRandomPlayer() + local tab = {} + local tab2 = player.GetAll() + for i=1,#tab2 do + local ply = tab2[i] + if ply:Alive() and !ply:IsDowned() then + table.insert(tab, ply) + end + end + if #tab > 0 then + return tab[math.random(1,#tab)] + else + return nil + end +end + +function SuR:CopyTable(source, to) + to = {} + for k, v in pairs(source) do + to[k] = v + end +end + +function meta:GetInfection() + return self:GetNWFloat('InfectionProgress', 0) +end + +if SERVER then + RunConsoleCommand("vj_npc_knowenemylocation", 1) + RunConsoleCommand("vj_npc_itemdrops", 0) + RunConsoleCommand("vj_npc_sd_soundtrack", 1) + RunConsoleCommand("mp_falldamage", 1) + RunConsoleCommand("VJ_LNR_Infection", 0) +else + RunConsoleCommand("cl_tfa_hud_enabled", 0) + RunConsoleCommand("cl_tfa_hud_hitmarker_enabled", 0) + RunConsoleCommand("cl_tfa_hud_crosshair_enable_custom", 0) + RunConsoleCommand("cl_tfa_hud_keybindhints_enabled", 0) + RunConsoleCommand("cl_tfa_ironsights_toggle", 0) +end + +--------------------------------------------------- + +hook.Add("SetupMove", "SuR_Move", function(ply, mv, cmd) + if SERVER then + if SuR.ActiveMutator == 12 then + mv:SetMaxSpeed(75) + mv:SetMaxClientSpeed(75) + end + else + if SuR.Data["Mutator"] == 12 then + mv:SetMaxSpeed(75) + mv:SetMaxClientSpeed(75) + end + end + if ply:GetInfection() >= 0.8 or ply:Health() <= 15 then + mv:SetMaxSpeed(60) + mv:SetMaxClientSpeed(60) + elseif ply:GetInfection() >= 0.4 or ply:Health() <= 30 then + mv:SetMaxSpeed(90) + mv:SetMaxClientSpeed(90) + end + if ply:GetNWBool('SVAnimStopMoving') then + mv:SetMaxSpeed(1) + mv:SetMaxClientSpeed(1) + end + if ply:IsDowned() then + mv:SetMaxSpeed(20) + mv:SetMaxClientSpeed(20) + end + if ply:IsZombie() and ply:Alive() then + mv:SetSideSpeed(0) + end +end) + +--------------------------------------------------- + +game.AddParticles( "particles/antlion_gib_01.pcf" ) +game.AddParticles( "particles/antlion_gib_02.pcf" ) +game.AddParticles( "particles/advisor.pcf" ) +game.AddParticles( "particles/Advisor_FX.pcf" ) +game.AddParticles( "particles/aurora.pcf" ) +game.AddParticles( "particles/aurora_sphere2.pcf" ) +game.AddParticles( "particles/antlion_worker.pcf" ) +game.AddParticles( "particles/buildingdamage.pcf" ) +game.AddParticles( "particles/blob.pcf" ) +game.AddParticles( "particles/bonfire.pcf" ) +game.AddParticles( "particles/building_explosion.pcf" ) +game.AddParticles( "particles/default.pcf" ) +game.AddParticles( "particles/demo_paticle_light.pcf" ) +game.AddParticles( "particles/devtest.pcf" ) +game.AddParticles( "particles/door_explosion.pcf" ) +game.AddParticles( "particles/dust_bombdrop.pcf" ) +game.AddParticles( "particles/dust_rumble.pcf" ) +game.AddParticles( "particles/explosion.pcf" ) +game.AddParticles( "particles/electrical_fx.pcf" ) +game.AddParticles( "particles/fire_ring.pcf" ) +game.AddParticles( "particles/fireflow.pcf" ) +game.AddParticles( "particles/flamethrowertest.pcf" ) +game.AddParticles( "particles/grenade_fx.pcf" ) +game.AddParticles( "particles/grub_blood.pcf" ) +game.AddParticles( "particles/hunter_intro.pcf" ) +game.AddParticles( "particles/hunter_projectile.pcf" ) +game.AddParticles( "particles/hunter_shield_impact.pcf" ) +game.AddParticles( "particles/hunter_flechette.pcf" ) +game.AddParticles( "particles/choreo_dog_v_strider.pcf" ) +game.AddParticles( "particles/choreo_launch.pcf" ) +game.AddParticles( "particles/choreo_gman.pcf" ) +game.AddParticles( "particles/choreo_extract.pcf" ) +game.AddParticles( "particles/largefire.pcf" ) +game.AddParticles( "particles/light_rays.pcf" ) +game.AddParticles( "particles/magnusson_burner.pcf" ) +game.AddParticles( "particles/rain.pcf" ) +game.AddParticles( "particles/sand.pcf" ) +game.AddParticles( "particles/skybox_smoke.pcf" ) +game.AddParticles( "particles/stalactite.pcf" ) +game.AddParticles( "particles/striderbuster.pcf" ) +game.AddParticles( "particles/steampuff.pcf" ) +game.AddParticles( "particles/test_grnalpha.pcf" ) +game.AddParticles( "particles/test_noise.pcf" ) +game.AddParticles( "particles/vehicle.pcf" ) +game.AddParticles( "particles/vistasmokev1.pcf" ) +game.AddParticles( "particles/Vortigaunt_FX.pcf" ) +game.AddParticles( "particles/warpshield.pcf" ) +game.AddParticles( "particles/water_leaks.pcf" ) +game.AddParticles( "particles/waterfall.pcf" ) +game.AddParticles( "particles/waterdrips.pcf" ) +game.AddParticles( "particles/weapon_fx.pcf" ) \ No newline at end of file diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/icon24.png b/garrysmod/addons/surrounded/gamemodes/surrounded/icon24.png new file mode 100644 index 0000000..07a0b93 Binary files /dev/null and b/garrysmod/addons/surrounded/gamemodes/surrounded/icon24.png differ diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/logo.png b/garrysmod/addons/surrounded/gamemodes/surrounded/logo.png new file mode 100644 index 0000000..a53c4bb Binary files /dev/null and b/garrysmod/addons/surrounded/gamemodes/surrounded/logo.png differ diff --git a/garrysmod/addons/surrounded/gamemodes/surrounded/surrounded.txt b/garrysmod/addons/surrounded/gamemodes/surrounded/surrounded.txt new file mode 100644 index 0000000..051f647 --- /dev/null +++ b/garrysmod/addons/surrounded/gamemodes/surrounded/surrounded.txt @@ -0,0 +1,8 @@ +"surrounded" +{ + "base" "base" + "title" "Surrounded" + "maps" "^sur_" + "category" "pve" + "menusystem" "1" +} diff --git a/garrysmod/addons/surrounded/lua/wos/dynabase/registers/surrounded_reanim.lua b/garrysmod/addons/surrounded/lua/wos/dynabase/registers/surrounded_reanim.lua new file mode 100644 index 0000000..2b20539 --- /dev/null +++ b/garrysmod/addons/surrounded/lua/wos/dynabase/registers/surrounded_reanim.lua @@ -0,0 +1,17 @@ +if engine.ActiveGamemode() == "surrounded" then + wOS.DynaBase:RegisterSource({ + Name = "SuR L4D2 Anims", + Type = WOS_DYNABASE.REANIMATION, + Shared = "models/xdreanims/m_anm_slot_l4d.mdl", + }) + wOS.DynaBase:RegisterSource({ + Name = "SuR Extra Player Anims 1", + Type = WOS_DYNABASE.EXTENSION, + Shared = "models/surrounded/player_anims1.mdl", + }) + + hook.Add("PreLoadAnimations", "wOS.DynaBase.MountSuR1", function( gender ) + IncludeModel( "models/xdreanims/m_anm_slot_l4d.mdl" ) + IncludeModel( "models/surrounded/player_anims1.mdl" ) + end) +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/contagion_roanoke.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/contagion_roanoke.lua new file mode 100644 index 0000000..9ea65e2 --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/contagion_roanoke.lua @@ -0,0 +1,231 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(43,514,225), + Vector(-93,864,225), + Vector(189,1119,225), + Vector(723,1409,225), + Vector(135,1875,225), + Vector(-284,2004,225), + Vector(-621,1677,225), + Vector(-903,1376,242), + Vector(-834,2265,225), + Vector(-317,3104,105), + Vector(478,3312,225), + Vector(1701,3914,225), + Vector(1959,3843,385), + Vector(1723,3882,385), + Vector(1694,3595,65), + Vector(2311,3100,65), + Vector(1744,3209,65), + Vector(1718,2551,105), + Vector(742,3108,65), + Vector(723,2656,65), + Vector(442,3338,65), + Vector(610,1365,385), + Vector(2568,2171,9), + Vector(504,1749,225), +} + +SuR.Config.Support_SpawnPositions = { + Vector(2638,1721,-7), + Vector(-1061,326,-7), + Vector(2339,348,-7), + Vector(428,2816,385), + Vector(1074,2619,385), + Vector(2483,4919,-7), + Vector(-498,5021,-7), +} + +SuR.Config.Gas_SpawnPositions = { + Vector(-1469,-176,35), + Vector(-1519,7152,1), + Vector(3184,7152,1), + Vector(3152,-207,37), +} + +SuR.Config.Camera_Position = { + Vector(1074,4964,499), + Angle(-20,-118,0), +} + +SuR.Config.Player_SpawnPositions = { + Vector(2906,1852,-7), + Vector(2948,1814,-7), + Vector(3015,1977,-7), + Vector(567,288,-7), + Vector(627,221,-7), + Vector(668,401,-7), + Vector(708,357,-7), + Vector(429,158,-7), + Vector(489,146,-7), + Vector(-1296,111,-7), + Vector(-1241,202,-7), + Vector(-1261,3106,-231), + Vector(-1178,2973,-231), +} + +SuR.Config.Height_Of_Air = 2000 + +SuR.Config.Zombie_Spawn_Radius_Min = 500 +SuR.Config.Zombie_Spawn_Radius_Max = 3000 + +SuR.Config.Loot_Remove_Delay = 180 +SuR.Config.Loot_Max_Per_Player = 30 + +SuR.Config.TierWeapons["Tier1"] = { + "tfa_private_ump45", + "tfa_private_remington870", + "tfa_private_ro933", + "tfa_private_dsr", +} + +SuR.Config.Open_Func_Doors = true +SuR.Config.Enable_Out_Of_Bounds_Check = false +SuR.Config.Enable_Spawn_In_Building_Zombies = false +SuR.Config.Allow_PVS_Info = false + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(1022,3974,502), + [1] = {pos = Vector(1129,639,1988), ang = Angle(0,90,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(1031,4603,1600), ang = Angle(0,90,0), wait = false, sec = 20, dist = 300, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(1031,4603,739), ang = Angle(0,90,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(1031,4603,1600), ang = Angle(0,90,0), wait = false, sec = 6, dist = 100, damp = 0.9}, + [5] = {pos = Vector(2707,5122,2000), ang = Angle(20,25,0), wait = false, sec = 10, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(-143,3125,-123), + ang = Angle(-14,15,0), + fov = 80, + time = 5, + }, + { + pos = Vector(-453,2991,-192), + ang = Angle(0,111,0), + fov = 65, + time = 5, + }, + { + pos = Vector(-743,3126,-200), + ang = Angle(-3,179,0), + fov = 50, + time = 5, + }, + }, + model = { + { + pos = Vector(-1034,2996,-223), + ang = Angle(0,37,0), + }, + { + pos = Vector(-1044,3046,-231), + ang = Angle(0,17,0), + }, + { + pos = Vector(-1057,3103,-231), + ang = Angle(0,16,0), + }, + { + pos = Vector(-1060,3169,-231), + ang = Angle(0,-13,0), + }, + { + pos = Vector(-1047,3222,-231), + ang = Angle(2,-19,1), + }, + { + pos = Vector(-1042,3278,-223), + ang = Angle(0,-38,0), + }, + }, +} + +SuR.Config.Objective_Mode = true +SuR.Config.Objective_Mode_Wave = 20 +SuR.Config.Objective_Mode_Max_Cans = 64 +SuR.Config.Objective_Mode_Positions = { + ["fuel"] = { + Vector(2631,3480,70), + Vector(2042,3289,72), + Vector(1894,2236,77), + Vector(980,2412,76), + Vector(819,2415,66), + Vector(666,2466,79), + Vector(-56,2538,66), + Vector(-89,2326,66), + Vector(361,1684,66), + Vector(1021,2318,-89), + Vector(-119,3411,-219), + Vector(493,2232,-209), + Vector(2577,2293,20), + Vector(-535,1472,432), + Vector(-769,1795,425), + Vector(1196,3256,387), + Vector(1600,3888,392), + Vector(1826,3890,557), + Vector(-111,3775,70), + Vector(510,3142,67), + Vector(1473,3953,232), + Vector(543,1552,232), + Vector(1528,1836,235), + Vector(-727,2467,229), + Vector(623,2537,232), + Vector(348,3218,232), + Vector(-1011,3340,74), + Vector(175,2549,233), + Vector(551,1756,396), + Vector(858,1691,399), + Vector(994,1813,395), + Vector(-617,2259,74), + Vector(-921,3129,426), + Vector(2216,3650,79), + }, + ["generator"] = { + { + pos = Vector(477,3169,385), + ang = Angle(1,-90,0), + }, + { + pos = Vector(-164,4305,65), + ang = Angle(1,-89,0), + }, + { + pos = Vector(-18,561,385), + ang = Angle(1,-89,0), + }, + { + pos = Vector(481,3563,-222), + ang = Angle(-1,-179,1), + }, + { + pos = Vector(-908,2639,-223), + ang = Angle(1,-87,0), + }, + { + pos = Vector(2603,2992,65), + ang = Angle(0,90,-0), + }, + }, +} + +local models = { + "models/player/fbi/ct_fbi1.mdl", + "models/player/fbi/ct_fbi2.mdl", + "models/player/fbi/ct_fbi3.mdl", + "models/player/fbi/ct_fbi4.mdl", +} +SuR.Config.Allowed_PlayerModels = models + +if SERVER then + local function remove_shit() + for _, ent in ipairs(ents.FindByClass("env_sprite")) do + ent:Remove() + end + end + + hook.Add("InitPostEntity", "RemoveShit", remove_shit) + hook.Add("PostCleanupMap", "RemoveShit", remove_shit) +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/gm_police_station_v2.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_police_station_v2.lua new file mode 100644 index 0000000..f93105f --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_police_station_v2.lua @@ -0,0 +1,194 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(1293,1503,1), + Vector(1284,1272,1), + Vector(567,1425,1), + Vector(569,1103,1), + Vector(1264,1019,1), + Vector(1161,715,2), + Vector(1421,698,1), + Vector(454,793,1), + Vector(226,782,1), + Vector(678,875,1), + Vector(1130,1870,1), + Vector(1470,1852,1), + Vector(611,1619,1), + Vector(577,1935,1), + Vector(1398,1822,353), + Vector(1388,1458,353), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-377,2513,-7), + Vector(-382,1365,-7), + Vector(-390,-48,-7), + Vector(1800,-37,1), +} + +SuR.Config.Gas_SpawnPositions = { + Vector(2085,2988,1), + Vector(2092,1611,1), + Vector(2072,-405,1), +} + +SuR.Config.Camera_Position = { + Vector(-244,1045,149), + Angle(-16,-32,0), +} + +SuR.Config.Player_SpawnPositions = { + Vector(1382,596,1), + Vector(1381,674,1), + Vector(1380,759,1), + Vector(1379,832,1), + Vector(1432,833,1), + Vector(1433,759,1), + Vector(1434,691,1), + Vector(1435,596,1), +} + +SuR.Config.Height_Of_Air = 450 + +SuR.Config.Zombie_Spawn_Radius_Min = 400 +SuR.Config.Zombie_Spawn_Radius_Max = 4000 + +SuR.Config.Loot_Remove_Delay = 180 +SuR.Config.Loot_Max_Per_Player = 15 + +table.insert(SuR.Config.SecondaryWeapons, "tfa_private_glock19") +SuR.Config.TierWeapons["Tier1"] = {"tfa_private_glock19"} + +SuR.Config.Open_Func_Doors = true + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(-535,2128,-515), + [1] = {pos = Vector(1612,-200,700), ang = Angle(0,155,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-457,1699,500), ang = Angle(0,90,0), wait = false, sec = 10, dist = 200, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-358,2243,265), ang = Angle(0,90,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(-605,2131,450), ang = Angle(0,90,0), wait = false, sec = 6, dist = 100, damp = 0.9}, + [5] = {pos = Vector(1432,2737,700), ang = Angle(20,0,0), wait = false, sec = 5, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(832,973,64), + ang = Angle(2,53,0), + fov = 65, + time = 4, + }, + { + pos = Vector(927,1399,72), + ang = Angle(1,119,0), + fov = 80, + time = 4, + }, + { + pos = Vector(668,1450,99), + ang = Angle(10,-121,20), + fov = 70, + time = 4, + }, + { + pos = Vector(568,1456,44), + ang = Angle(-2,-93,0), + fov = 80, + time = 4, + }, + }, + model = { + { + pos = Vector(714,1267,1), + ang = Angle(0,137,0), + }, + { + pos = Vector(659,1221,1), + ang = Angle(0,112,0), + }, + { + pos = Vector(564,1161,1), + ang = Angle(0,93,0), + }, + { + pos = Vector(468,1222,1), + ang = Angle(-0,67,1), + }, + { + pos = Vector(422,1305,1), + ang = Angle(0,42,0), + }, + }, +} + +local models = { + "models/kerry/nypd_v2/male_04.mdl", + "models/kerry/nypd_v2/male_05.mdl", + "models/kerry/nypd_v2/male_06.mdl", + "models/kerry/nypd_v2/male_07.mdl", + "models/kerry/nypd_v2/male_08.mdl", + "models/kerry/nypd_v2/male_09.mdl", +} + +SuR.Config.Allowed_PlayerModels = models + +---CODE PART--- + +local positions = { + Vector(1088,1102,1), + Vector(620,1128,1), + Vector(646,843,1), + Vector(972,399,1), + Vector(834,654,1), + Vector(828,1907,1), + Vector(1139,2279,1), + Vector(844,1846,353), +} + +hook.Add("PlayerSpawn", "SuR.ChangeModels", function(ply) + timer.Simple(0.001, function() + if !IsValid(ply) or !ply:Alive() or ply:IsZombie() then return end + ply:SetBodygroup(3, math.random(0,1)) + ply:SetBodygroup(1, math.random(0,3)) + ply:StripWeapons() + ply:Give("tfa_private_glock19") + ply:Give("tfa_nmrih_wrench") + end) +end) + +hook.Add("EntityRemoved", "SuR.OfficerDown", function(ent) + if ent:GetClass() == "sur_support_npc" and math.random(1,2) == 1 and SERVER then + SuR:PlaySoundOnClient("sur_config/officerdown.wav") + end +end) + +hook.Add("SuR.GameState", "SuR.SpawnNPCs", function(state) + if state then + timer.Simple(0.01, function() + for k, v in ipairs(positions) do + local ent = ents.Create("sur_support_npc") + ent.Model = models + ent:SetPos(v) + ent:SetAngles(Angle(0,math.random(0,360),0)) + ent:Spawn() + ent:SetHealth(50) + ent:SetBodygroup(3, math.random(0,1)) + ent:SetBodygroup(5, math.random(0,1)) + ent:SetBodygroup(1, math.random(0,3)) + ent:Give("weapon_vj_glock17") + end + + for k, v in pairs(ents.FindByClass("*door*")) do + v:Remove() + end + + for i=1,40 do + local ent = ents.Create("prop_physics") + ent:SetModel("models/props_wasteland/dockplank01b.mdl") + ent:SetPos(Vector(1013,1167,355)+Vector(0,0,i*6)) + ent:Spawn() + ent:GetPhysicsObject():SetMass(100) + end + end) + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/gm_quarantine.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_quarantine.lua new file mode 100644 index 0000000..66758e9 --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_quarantine.lua @@ -0,0 +1,111 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(-1101,-1289,-479), + Vector(-2111,-1519,-469), + Vector(-1105,-823,-575), + Vector(-1078,-197,-607), + Vector(-748,-362,-607), + Vector(-333,-504,-639), + Vector(57,43,-761), + Vector(1436,-115,-767), + Vector(1260,1119,-703), + Vector(659,1584,-696), + Vector(647,1582,-719), + Vector(761,1507,-719), + Vector(669,1572,-591), + Vector(-1245,250,-719), + Vector(-1064,-178,-607), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-1382,1306,-760), + Vector(-766,724,-760), + Vector(1152,1396,-760), + Vector(1724,686,-765), + Vector(-49,-1014,-380), +} + +SuR.Config.Camera_Position = { + Vector(-1575,583,-673), + Angle(-18,41,0) +} + +SuR.Config.Height_Of_Air = 500 + +SuR.Config.Invisible_Walls = { + { + pos = Vector(-1883,-705,-518), + ang = Angle(90,90,180), + model = "models/hunter/plates/plate2x3.mdl", + }, + { + pos = Vector(-1662,-705,-519), + ang = Angle(90,90,180), + model = "models/hunter/plates/plate2x3.mdl", + }, + { + pos = Vector(1195,1120,-651), + ang = Angle(90,-180,180), + model = "models/hunter/plates/plate2x3.mdl", + }, +} + +SuR.Config.Loot_Remove_Delay = 240 +SuR.Config.Loot_Max_Per_Player = 30 + +SuR.Config.Enable_Spawn_In_Building_Zombies = true + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(-1344,715,-761), + [1] = {pos = Vector(-1924,817,519), ang = Angle(20,-0,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-845,794,520), ang = Angle(10,-0,0), wait = false, sec = 10, dist = 200, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-845,794,-475), ang = Angle(0,-0,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(-845,794,520), ang = Angle(0,-0,0), wait = false, sec = 6, dist = 100, damp = 0.9}, + [5] = {pos = Vector(1547,741,519), ang = Angle(20,0,0), wait = false, sec = 5, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(1286,864,-400), + ang = Angle(-4,-156,0), + fov = 90, + time = 5, + }, + { + pos = Vector(1109,1250,-440), + ang = Angle(-2,137,0), + fov = 60, + time = 5, + }, + { + pos = Vector(996,1335,-480), + ang = Angle(-15,86,0), + fov = 30, + time = 5, + }, + }, + model = { + { + pos = Vector(902,1856,-383), + ang = Angle(0,-66,0), + }, + { + pos = Vector(964,1862,-383), + ang = Angle(0,-97,0), + }, + { + pos = Vector(1032,1846,-383), + ang = Angle(0,-92,0), + }, + { + pos = Vector(1097,1841,-383), + ang = Angle(0,-98,0), + }, + { + pos = Vector(1162,1810,-383), + ang = Angle(0,-120,0), + }, + }, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/gm_retreat.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_retreat.lua new file mode 100644 index 0000000..156e7bf --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_retreat.lua @@ -0,0 +1,114 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(15,129,-63), + Vector(20,-500,-63), + Vector(-97,-1169,-63), + Vector(297,-1215,-63), + Vector(458,-1178,-63), + Vector(673,-1181,-63), + Vector(660,-1577,-63), + Vector(470,-1536,-63), + Vector(290,-1554,-63), + Vector(-106,-1641,-63), + Vector(275,-2048,-63), + Vector(241,-2442,-63), + Vector(369,-2457,-255), + Vector(-101,-2429,-255), + Vector(-1372,-765,-255), + Vector(-1423,-103,-255), + Vector(-1757,-754,-255), + Vector(-547,-1260,-127), + Vector(-657,-1620,-127), + Vector(-867,-1508,-127), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-659,1408,-65), + Vector(-168,1719,-60), + Vector(-898,1384,-50), +} + +SuR.Config.Camera_Position = { + Vector(-1332,2144,129), + Angle(-3,-56,0) +} + +SuR.Config.Height_Of_Air = 400 + +SuR.Config.Invisible_Walls = { + { + pos = Vector(-329,-1400,-47), + ang = Angle(1,-179,-0), + model = "models/hunter/blocks/cube075x075x075.mdl", + }, + { + pos = Vector(-23,-1400,-41), + ang = Angle(0,-0,-0), + model = "models/hunter/blocks/cube075x075x075.mdl", + }, + { + pos = Vector(-64,1263,-204), + ang = Angle(0,-0,-0), + model = "models/hunter/blocks/cube6x6x6.mdl", + }, + { + pos = Vector(-26,1481,35), + ang = Angle(0,155,-0), + model = "models/hunter/blocks/cube4x4x4.mdl", + }, + { + pos = Vector(-1086,1457,-0), + ang = Angle(90,-180,180), + model = "models/hunter/plates/plate2x2.mdl", + }, + { + pos = Vector(-265,2135,-12), + ang = Angle(90,-180,180), + model = "models/hunter/plates/plate2x2.mdl", + }, +} + +SuR.Config.Loot_Max_Per_Player = 20 + +SuR.Config.Enable_Spawn_In_Building_Zombies = true +SuR.Config.Zombie_Spawn_Radius_Max = 2000 + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(-212,-473,-12), + ang = Angle(-18,-70,0), + fov = 90, + time = 5, + }, + { + pos = Vector(-236,-346,-20), + ang = Angle(-3,137,0), + fov = 80, + time = 5, + }, + { + pos = Vector(-208,-321,-19), + ang = Angle(-10,91,0), + fov = 65, + time = 5, + }, + }, + model = { + { + pos = Vector(-274,-204,-63), + ang = Angle(0,-53,0), + }, + { + pos = Vector(-236,-170,-63), + ang = Angle(0,-65,0), + }, + { + pos = Vector(-180,-148,-63), + ang = Angle(0,-105,0), + }, + { + pos = Vector(-142,-206,-63), + ang = Angle(0,-131,0), + }, + }, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/gm_underpass.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_underpass.lua new file mode 100644 index 0000000..6c6ef8e --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/gm_underpass.lua @@ -0,0 +1,114 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(-1264,3870,-495), + Vector(-925,3875,-511), + Vector(643,3310,-639), + Vector(1231,3309,-639), + Vector(1598,2609,-511), + Vector(1631,2503,-255), + Vector(1850,2506,-255), + Vector(2348,2147,-515), + Vector(2324,2561,-511), + Vector(2504,2533,-511), + Vector(1543,1293,-527), + Vector(1962,1276,-527), + Vector(2450,1256,-943), + Vector(-1716,1599,-687), + Vector(-1835,2629,-687), + Vector(690,3542,-383), + Vector(810,3422,-383), + Vector(714,3703,-383), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-551,3470,-515), + Vector(-1886,3461,-515), + Vector(-491,2173,-515), + Vector(597,2051,-515), + Vector(-471,4092,-515), + Vector(1312,3284,-639), +} + +SuR.Config.Gas_SpawnPositions = { + Vector(1583,3547,-575), + Vector(2474,1849,-511), + Vector(-2104,3667,-511), + Vector(1714,1187,-527), +} + +SuR.Config.Camera_Position = { + Vector(-305,2946,-450), + Angle(-22,122,0), +} + +SuR.Config.Height_Of_Air = 150 + +SuR.Config.Invisible_Walls = { + { + pos = Vector(-1299,1563,-705), + ang = Angle(0,-175,-0), + model = "models/hunter/blocks/cube8x8x8.mdl", + }, +} + +SuR.Config.Loot_Remove_Delay = 300 +SuR.Config.Loot_Max_Per_Player = 30 + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(-535,2128,-515), + [1] = {pos = Vector(2384,2101,450), ang = Angle(20,-180,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-609,2085,342), ang = Angle(10,-180,0), wait = false, sec = 10, dist = 500, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-581,2152,-240), ang = Angle(0,-180,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(-605,2131,330), ang = Angle(0,-180,0), wait = false, sec = 6, dist = 100, damp = 0.9}, + [5] = {pos = Vector(-384,4397,450), ang = Angle(20,90,0), wait = false, sec = 5, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(-764,2141,-462), + ang = Angle(-13,92,0), + fov = 25, + time = 5, + }, + { + pos = Vector(-764,2141,-462), + ang = Angle(-2,82,0), + fov = 65, + time = 5, + }, + { + pos = Vector(-779,2094,-464), + ang = Angle(0,75,0), + fov = 45, + time = 5, + }, + }, + model = { + { + pos = Vector(-799,2400,-511), + ang = Angle(0,-82,0), + }, + { + pos = Vector(-719,2379,-511), + ang = Angle(0,-90,0), + }, + { + pos = Vector(-580,2370,-515), + ang = Angle(0,-108,0), + }, + { + pos = Vector(-666,2469,-511), + ang = Angle(0,-89,0), + }, + { + pos = Vector(-603,2481,-515), + ang = Angle(0,-98,0), + }, + { + pos = Vector(-720,2475,-511), + ang = Angle(0,-96,0), + }, + }, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/hr_antarctic_hospital_d.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/hr_antarctic_hospital_d.lua new file mode 100644 index 0000000..f93033d --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/hr_antarctic_hospital_d.lua @@ -0,0 +1,93 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(-123,-940,36), + Vector(-546,-467,36), + Vector(67,-299,36), + Vector(224,-648,36), + Vector(505,-632,36), + Vector(262,-1238,36), + Vector(-122,-1281,36), + Vector(-91,-920,36), + Vector(-160,-630,36), + Vector(-5,-449,36), + Vector(164,-626,180), + Vector(-239,-589,180), + Vector(-236,-891,180), + Vector(15,-866,180), + Vector(-121,-1189,180), + Vector(-170,-267,180), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-53,222,36), + Vector(541,289,36), + Vector(802,-53,36), + Vector(973,-869,36), + Vector(414,-261,180), +} + +SuR.Config.Camera_Position = { + Vector(1051,366,452), + Angle(12,-133,0), +} + +SuR.Config.Height_Of_Air = 800 + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(339,-208,180), + [1] = {pos = Vector(-1185,2820,975), ang = Angle(20,-90,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(204,147,958), ang = Angle(10,-55,0), wait = false, sec = 10, dist = 200, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(347,233,490), ang = Angle(0,90,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(347,233,700), ang = Angle(0,90,0), wait = false, sec = 6, dist = 100, damp = 0.9}, + [5] = {pos = Vector(-1716,2578,1052), ang = Angle(20,130,0), wait = false, sec = 5, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Invisible_Walls = { + { + pos = Vector(341,-163,195), + ang = Angle(45,-90,0), + model = "models/hunter/plates/plate075x4.mdl", + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(217,-1145,243), + ang = Angle(9,-110,0), + fov = 90, + time = 5, + }, + { + pos = Vector(-66,-1274,218), + ang = Angle(4,-161,0), + fov = 85, + time = 5, + }, + { + pos = Vector(-112,-1227,215), + ang = Angle(-5,151,0), + fov = 80, + time = 5, + }, + }, + model = { + { + pos = Vector(-246,-1246,177), + ang = Angle(0,10,0), + }, + { + pos = Vector(-264,-1172,176), + ang = Angle(0,-10,0), + }, + { + pos = Vector(-240,-1104,177), + ang = Angle(0,-45,0), + }, + { + pos = Vector(-171,-1081,177), + ang = Angle(0,-58,0), + }, + }, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_day_v1_0.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_day_v1_0.lua new file mode 100644 index 0000000..bec6b1e --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_day_v1_0.lua @@ -0,0 +1,140 @@ +SuR.Config.Loot_Spawn_Delay = 1 +SuR.Config.Loot_HeightLimit = 0 + +local function ChangePositions() + local rnd = math.random(1,3) + if rnd == 1 then + SuR.Config.Loot_SpawnPositions = { + Vector(2314,683,53), + Vector(2688,683,41), + Vector(2401,280,55), + Vector(2673,-170,50), + Vector(2365,-271,37), + Vector(2406,-658,47), + Vector(1648,-610,26), + Vector(1763,-230,22), + Vector(1402,-173,22), + Vector(1688,324,56), + Vector(1762,606,66), + Vector(1380,743,56), + Vector(104,751,62), + Vector(-251,742,39), + Vector(-145,368,42), + Vector(-214,2565,55), + Vector(-248,2947,44), + Vector(2917,2610,22), + } + + SuR.Config.Support_SpawnPositions = { + Vector(770,1301,48), + Vector(290,-445,1), + Vector(3041,-306,16), + Vector(578,2464,34), + Vector(2633,1734,48), + } + + SuR.Config.Player_SpawnPositions = { + Vector(2344,666,16), + Vector(2421,-278,16), + Vector(1684,-697,0), + Vector(1444,-213,0), + Vector(1413,767,32), + Vector(161,765,16), + Vector(-159,308,16), + Vector(-196,2625,24), + Vector(2841,2559,3), + } + + SuR.Config.Zone_Center_Position = Vector(1995,1190,48) + SuR.Config.Zone_Radius = 3000 + SuR.Config.Loot_Max = 40 + elseif rnd == 2 then + SuR.Config.Loot_SpawnPositions = { + Vector(2576,9737,114), + Vector(2436,10050,121), + Vector(2456,10312,121), + Vector(4673,9952,246), + Vector(4343,9159,115), + Vector(4100,9126,111), + Vector(5220,11407,128), + Vector(5784,11559,135), + Vector(5631,11900,269), + Vector(5302,11439,267), + Vector(5790,11570,270), + Vector(5425,12161,261), + Vector(4555,8547,122), + Vector(4301,8546,113), + Vector(4150,11784,125), + Vector(2742,12013,122), + Vector(2558,11249,237), + } + + SuR.Config.Support_SpawnPositions = { + Vector(6609,10763,96), + Vector(3596,10753,96), + Vector(3620,12763,96), + Vector(6624,12770,96), + Vector(3574,9760,96), + Vector(3623,8613,96), + } + + SuR.Config.Player_SpawnPositions = { + Vector(4298,9977,96), + Vector(4061,9703,96), + Vector(2664,9686,96), + Vector(2823,11623,96), + Vector(4148,11737,96), + Vector(5715,11922,100), + Vector(5649,11818,256), + Vector(5572,9425,96), + Vector(4322,8244,96), + Vector(6322,11556,104), + } + + SuR.Config.Zone_Center_Position = Vector(4940,10561,104) + SuR.Config.Zone_Radius = 3500 + SuR.Config.Loot_Max = 30 + else + SuR.Config.Loot_SpawnPositions = { + Vector(6799,-670,64), + Vector(7554,-375,71), + Vector(7538,-802,93), + Vector(6813,679,113), + Vector(6433,659,110), + Vector(7479,678,66), + Vector(7221,3464,73), + Vector(7240,2849,73), + Vector(6998,2416,56), + Vector(7704,2958,61), + } + + SuR.Config.Support_SpawnPositions = { + Vector(7112,-968,16), + Vector(7151,253,16), + Vector(6837,1533,48), + Vector(6404,2757,16), + Vector(6906,3896,17), + } + + SuR.Config.Player_SpawnPositions = { + Vector(7329,2213,12), + Vector(6705,882,29), + Vector(7047,1529,48), + Vector(7485,-1200,14), + Vector(6477,-241,10), + Vector(6446,3379,16), + Vector(7127,3135,12), + } + + SuR.Config.Zone_Center_Position = Vector(6887,1536,48) + SuR.Config.Zone_Radius = 3000 + SuR.Config.Loot_Max = 20 + end +end + +ChangePositions() +hook.Add("SuR.GameState", "SuR_MapLogic", function(state) + if state then + ChangePositions() + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_night_v1_0.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_night_v1_0.lua new file mode 100644 index 0000000..bec6b1e --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/old/gm_aftermath_night_v1_0.lua @@ -0,0 +1,140 @@ +SuR.Config.Loot_Spawn_Delay = 1 +SuR.Config.Loot_HeightLimit = 0 + +local function ChangePositions() + local rnd = math.random(1,3) + if rnd == 1 then + SuR.Config.Loot_SpawnPositions = { + Vector(2314,683,53), + Vector(2688,683,41), + Vector(2401,280,55), + Vector(2673,-170,50), + Vector(2365,-271,37), + Vector(2406,-658,47), + Vector(1648,-610,26), + Vector(1763,-230,22), + Vector(1402,-173,22), + Vector(1688,324,56), + Vector(1762,606,66), + Vector(1380,743,56), + Vector(104,751,62), + Vector(-251,742,39), + Vector(-145,368,42), + Vector(-214,2565,55), + Vector(-248,2947,44), + Vector(2917,2610,22), + } + + SuR.Config.Support_SpawnPositions = { + Vector(770,1301,48), + Vector(290,-445,1), + Vector(3041,-306,16), + Vector(578,2464,34), + Vector(2633,1734,48), + } + + SuR.Config.Player_SpawnPositions = { + Vector(2344,666,16), + Vector(2421,-278,16), + Vector(1684,-697,0), + Vector(1444,-213,0), + Vector(1413,767,32), + Vector(161,765,16), + Vector(-159,308,16), + Vector(-196,2625,24), + Vector(2841,2559,3), + } + + SuR.Config.Zone_Center_Position = Vector(1995,1190,48) + SuR.Config.Zone_Radius = 3000 + SuR.Config.Loot_Max = 40 + elseif rnd == 2 then + SuR.Config.Loot_SpawnPositions = { + Vector(2576,9737,114), + Vector(2436,10050,121), + Vector(2456,10312,121), + Vector(4673,9952,246), + Vector(4343,9159,115), + Vector(4100,9126,111), + Vector(5220,11407,128), + Vector(5784,11559,135), + Vector(5631,11900,269), + Vector(5302,11439,267), + Vector(5790,11570,270), + Vector(5425,12161,261), + Vector(4555,8547,122), + Vector(4301,8546,113), + Vector(4150,11784,125), + Vector(2742,12013,122), + Vector(2558,11249,237), + } + + SuR.Config.Support_SpawnPositions = { + Vector(6609,10763,96), + Vector(3596,10753,96), + Vector(3620,12763,96), + Vector(6624,12770,96), + Vector(3574,9760,96), + Vector(3623,8613,96), + } + + SuR.Config.Player_SpawnPositions = { + Vector(4298,9977,96), + Vector(4061,9703,96), + Vector(2664,9686,96), + Vector(2823,11623,96), + Vector(4148,11737,96), + Vector(5715,11922,100), + Vector(5649,11818,256), + Vector(5572,9425,96), + Vector(4322,8244,96), + Vector(6322,11556,104), + } + + SuR.Config.Zone_Center_Position = Vector(4940,10561,104) + SuR.Config.Zone_Radius = 3500 + SuR.Config.Loot_Max = 30 + else + SuR.Config.Loot_SpawnPositions = { + Vector(6799,-670,64), + Vector(7554,-375,71), + Vector(7538,-802,93), + Vector(6813,679,113), + Vector(6433,659,110), + Vector(7479,678,66), + Vector(7221,3464,73), + Vector(7240,2849,73), + Vector(6998,2416,56), + Vector(7704,2958,61), + } + + SuR.Config.Support_SpawnPositions = { + Vector(7112,-968,16), + Vector(7151,253,16), + Vector(6837,1533,48), + Vector(6404,2757,16), + Vector(6906,3896,17), + } + + SuR.Config.Player_SpawnPositions = { + Vector(7329,2213,12), + Vector(6705,882,29), + Vector(7047,1529,48), + Vector(7485,-1200,14), + Vector(6477,-241,10), + Vector(6446,3379,16), + Vector(7127,3135,12), + } + + SuR.Config.Zone_Center_Position = Vector(6887,1536,48) + SuR.Config.Zone_Radius = 3000 + SuR.Config.Loot_Max = 20 + end +end + +ChangePositions() +hook.Add("SuR.GameState", "SuR_MapLogic", function(state) + if state then + ChangePositions() + end +end) \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/ph_hospital.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/ph_hospital.lua new file mode 100644 index 0000000..c861891 --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/ph_hospital.lua @@ -0,0 +1,134 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(-247,832,225), + Vector(153,1069,225), + Vector(497,1076,225), + Vector(-228,819,385), + Vector(158,1065,385), + Vector(475,1071,385), + Vector(775,679,385), + Vector(963,668,385), + Vector(1188,1256,385), + Vector(1214,720,385), + Vector(1463,726,385), + Vector(1874,741,385), + Vector(1873,1012,385), + Vector(1874,1282,385), + Vector(426,1038,545), + Vector(170,1029,545), + Vector(135,778,545), + Vector(136,555,545), + Vector(475,1061,225), + Vector(163,1063,225), + Vector(-285,831,225), + Vector(148,564,225), + Vector(905,1247,225), + Vector(879,717,225), + Vector(1065,680,225), + Vector(1380,1243,225), + Vector(1662,1236,225), + Vector(1641,736,225), + Vector(1329,321,225), + Vector(1640,92,225), + Vector(1602,-180,225), + Vector(1205,-79,225), + Vector(1229,370,65), + Vector(1191,187,65), + Vector(1656,18,65), + Vector(1653,-178,65), + Vector(1159,-65,65), + Vector(1127,759,65), + Vector(1675,730,65), + Vector(1811,1223,65), + Vector(1933,755,65), + Vector(1045,1203,65), + Vector(1421,1218,65), + Vector(978,794,65), + Vector(773,667,65), + Vector(290,580,65), + Vector(132,1083,65), + Vector(-354,840,65), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-636,-201,-7), + Vector(-132,105,-7), + Vector(236,-414,-7), + Vector(790,64,-7), +} + +SuR.Config.Camera_Position = { + Vector(-839,-590,64), + Angle(-10,45,0) +} + +SuR.Config.Gas_SpawnPositions = { + Vector(-2776,-1884,-47), + Vector(2358,1650,142), + Vector(2454,-577,4), +} + +SuR.Config.Height_Of_Air = 800 + +SuR.Config.Loot_Remove_Delay = 180 +SuR.Config.Loot_Max_Per_Player = 25 +SuR.Config.Enable_Dangerous_Water = true + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(-445,105,50), + [1] = {pos = Vector(2740,2028,1500), ang = Angle(20,-135,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-491,-224,1000), ang = Angle(0,-135,0), wait = false, sec = 10, dist = 200, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-491,-224,300), ang = Angle(0,-90,0), wait = true, sec = 3, dist = 50, damp = 0.5, smoothrotate = true}, + [4] = {pos = Vector(-491,-224,800), ang = Angle(0,-90,0), wait = false, sec = 6, dist = 200, damp = 0.9}, + [5] = {pos = Vector(1669,-272,1500), ang = Angle(20,0,0), wait = false, sec = 5, dist = 300, damp = 1}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(633,-545,698), + ang = Angle(-26,125,0), + fov = 100, + time = 5, + }, + { + pos = Vector(73,-155,425), + ang = Angle(8,139,0), + fov = 75, + time = 5, + }, + { + pos = Vector(-442,110,57), + ang = Angle(-3,83,0), + fov = 50, + time = 5, + }, + }, + model = { + { + pos = Vector(-558,473,65), + ang = Angle(0,-54,0), + }, + { + pos = Vector(-497,537,65), + ang = Angle(0,-73,0), + }, + { + pos = Vector(-393,544,67), + ang = Angle(0,-102,0), + }, + { + pos = Vector(-302,542,65), + ang = Angle(0,-100,0), + }, + { + pos = Vector(-198,481,46), + ang = Angle(0,-119,0), + }, + { + pos = Vector(-390,434,1), + ang = Angle(0,-101,0), + }, + }, +} \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/rd_apartmentcomplex.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/rd_apartmentcomplex.lua new file mode 100644 index 0000000..65e5dca --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/rd_apartmentcomplex.lua @@ -0,0 +1,171 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(807,5,146), + Vector(762,591,146), + Vector(952,464,146), + Vector(797,1006,146), + Vector(956,842,146), + Vector(765,-557,146), + Vector(954,-697,146), + Vector(810,-937,146), + Vector(948,-1090,147), + Vector(1364,-930,146), + Vector(1520,-1075,146), + Vector(1381,-531,146), + Vector(1516,-694,146), + Vector(1341,600,146), + Vector(1519,476,146), + Vector(1367,990,146), + Vector(1524,840,146), + Vector(1356,997,2), + Vector(800,974,2), + Vector(953,835,2), + Vector(1514,842,2), + Vector(1412,604,2), + Vector(1530,455,2), + Vector(1369,-575,2), + Vector(1514,-688,2), + Vector(1338,-973,2), + Vector(1526,-1082,2), + Vector(782,-929,2), + Vector(955,-1074,2), + Vector(815,-535,2), + Vector(958,-692,2), + Vector(744,-2,2), + Vector(824,596,2), + Vector(964,450,2), + Vector(829,972,2), + Vector(961,836,2), + Vector(-1032,935,66), + Vector(-1148,1067,196), + Vector(-1143,810,196), + Vector(-912,944,196), + Vector(-1156,231,197), + Vector(-1150,-75,197), + Vector(-928,87,197), + Vector(-1176,75,66), + Vector(-1004,-659,66), + Vector(-1207,-999,66), + Vector(-1232,-1022,193), + Vector(-876,-991,193), + Vector(-1015,-668,193), + Vector(-1308,-645,193), + Vector(7,186,137), + Vector(-4,-182,137), +} + +SuR.Config.Support_SpawnPositions = { + Vector(3,1179,4), + Vector(2,-1174,4), + Vector(305,-31,4), + Vector(-320,-58,4), +} + +SuR.Config.Gas_SpawnPositions = { + Vector(-1673,-1380,4), + Vector(-1651,1357,4), + Vector(1667,1358,4), + Vector(1672,-1364,4), + Vector(-697,2198,4), + Vector(697,2190,4), +} + +SuR.Config.Camera_Position = { + Vector(-895,1027,606), + Angle(19,-40,0) +} + +SuR.Config.Height_Of_Air = 1600 + +SuR.Config.Loot_Remove_Delay = 180 +SuR.Config.Loot_Max_Per_Player = 20 +SuR.Config.Enable_Dangerous_Water = true + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(656,-0,150), + [1] = {pos = Vector(-2,1499,1500), ang = Angle(20,-90,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(4,-792,1200), ang = Angle(0,-90,0), wait = false, sec = 10, dist = 500, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(4,-792,540), ang = Angle(0,-90,0), wait = true, sec = 3, dist = 50, damp = 0.9, smoothrotate = true}, + [4] = {pos = Vector(4,-792,1200), ang = Angle(0,90,0), wait = false, sec = 6, dist = 100, damp = 0.9, smoothrotate = true}, + [5] = {pos = Vector(74,1560,1500), ang = Angle(20,90,0), wait = false, sec = 5, dist = 300, damp = 1, smoothrotate = true}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(-141,-1213,80), + ang = Angle(2,-15,0), + fov = 25, + time = 5, + }, + { + pos = Vector(-539,-1179,299), + ang = Angle(1,70,0), + fov = 80, + time = 5, + }, + { + pos = Vector(-679,-1173,241), + ang = Angle(0,156,0), + fov = 45, + time = 5, + }, + }, + model = { + { + pos = Vector(-1065,-824,193), + ang = Angle(0,-58,0), + }, + { + pos = Vector(-1217,-879,193), + ang = Angle(0,-41,0), + }, + { + pos = Vector(-1239,-956,193), + ang = Angle(0,7,0), + }, + { + pos = Vector(-1374,-1069,193), + ang = Angle(0,3,0), + }, + { + pos = Vector(-1052,-1131,193), + ang = Angle(0,60,0), + }, + { + pos = Vector(-1030,-1093,193), + ang = Angle(0,-115,0), + }, + }, +} + +if SERVER then + hook.Add("SuR.ExfilHeliSpawned", "SuR_SpawnLadder", function(heli) + local ent = ents.Create("prop_dynamic") + ent:SetPos(Vector(323,-1,226)) + ent:SetAngles(Angle(1,-90,-12)) + ent:SetModel("models/mechanics/solid_steel/truss_48.mdl") + ent:Spawn() + ent:SetSolid(SOLID_VPHYSICS) + ent:PhysicsInit(SOLID_VPHYSICS) + if IsValid(ent:GetPhysicsObject()) then + ent:GetPhysicsObject():EnableMotion(false) + end + + for _, ent in ipairs(ents.FindInSphere(Vector(620,-0,170),64)) do + if !string.match(ent:GetClass(), "breakable") then return end + ent:Fire("Break") + end + + local sol = ents.Create("sur_support_npc") + sol:SetPos(Vector(142,142,257)) + sol:Spawn() + sol.IsGuard = true + + local sol = ents.Create("sur_support_npc") + sol:SetPos(Vector(142,-142,257)) + sol:Spawn() + sol.IsGuard = true + end) +end \ No newline at end of file diff --git a/garrysmod/addons/surrounded_maps/lua/surrounded/sur_destroyed_city.lua b/garrysmod/addons/surrounded_maps/lua/surrounded/sur_destroyed_city.lua new file mode 100644 index 0000000..46eb5b0 --- /dev/null +++ b/garrysmod/addons/surrounded_maps/lua/surrounded/sur_destroyed_city.lua @@ -0,0 +1,267 @@ +SuR.Config.Loot_SpawnPositions = { + Vector(-8061,1027,181), + Vector(-8451,656,181), + Vector(-8406,775,181), + Vector(-8397,512,45), + Vector(-8436,473,-91), + Vector(-8440,504,-227), + Vector(-8092,995,-363), + Vector(-7924,-486,-499), + Vector(-7119,-659,-498), + Vector(-8015,-877,-361), + Vector(-7222,-1174,-499), + Vector(-7971,-1747,-498), + Vector(-7224,-2035,-499), + Vector(-7111,-2480,-499), + Vector(-7047,-3404,-499), + Vector(-6544,-3507,-498), + Vector(-6113,-3398,-499), + Vector(-7147,-2539,-499), + Vector(-7983,-3452,-499), + Vector(-7988,-4205,-498), + Vector(-7247,-4034,-361), + Vector(-7305,-4379,-499), + Vector(-9805,-3683,-497), + Vector(-10326,-3935,-494), + Vector(-9840,-2974,-498), + Vector(-9717,-2464,-501), + Vector(-8998,-1918,-498), + Vector(-9790,-1157,-499), + Vector(-9108,-1416,-499), + Vector(-9075,-763,-371), + Vector(-8689,-391,-370), + Vector(-10258,1262,-507), + Vector(-9121,3944,-501), +} + +SuR.Config.Support_SpawnPositions = { + Vector(-8422,947,317), + Vector(-8051,909,317), + Vector(-7048,258,-511), + Vector(-10965,1387,-507), + Vector(-12171,1519,-507), + Vector(-11667,-2421,-511), + Vector(-7183,-3501,45), + Vector(-9630,1002,-507), + Vector(-7024,2291,-511), +} + +SuR.Config.Gas_SpawnPositions = { + Vector(-13446,5364,-439), + Vector(-5136,5104,-511), + Vector(-5136,-5103,-232), + Vector(-12879,-5103,-506), +} + +SuR.Config.Camera_Position = { + Vector(-6725,638,-60), + Angle(-12,-156,0), +} + +SuR.Config.Height_Of_Air = 4500 + +SuR.Config.Zombie_Spawn_Radius_Min = 500 +SuR.Config.Zombie_Spawn_Radius_Max = 3000 + +SuR.Config.Loot_Remove_Delay = 180 +SuR.Config.Loot_Max_Per_Player = 30 + +SuR.Config.TierWeapons["Tier1"] = { + "tfa_private_ak74u", + "tfa_private_ak105", + "tfa_private_ak12", + "tfa_private_bizon", + "tfa_private_pp2000", + "tfa_private_fedorov", +} + +SuR.Config.Enable_Out_Of_Bounds_Check = false +SuR.Config.Enable_Spawn_In_Building_Zombies = false +SuR.Config.Allow_PVS_Info = true +SuR.Config.MusicWave["Deploy"] = {"sur_config/intro.mp3"} + +SuR.Config.Exfil_Points = { + { + ["Main"] = Vector(-7142,-3467,76), + [1] = {pos = Vector(-4787,4689,1405), ang = Angle(20,-100,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-6925,-3163,825), ang = Angle(0,-125,0), wait = false, sec = 15, dist = 400, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-7721,-3518,355), ang = Angle(0,-180,0), wait = true, sec = 3, dist = 50, damp = 0.5, smoothrotate = true}, + [4] = {pos = Vector(-7721,-3518,1500), ang = Angle(0,-180,0), wait = false, sec = 6, dist = 200, damp = 0.9}, + [5] = {pos = Vector(-14847,-3389,3110), ang = Angle(20,-180,0), wait = false, sec = 10, dist = 300, damp = 1}, + }, + { + ["Main"] = Vector(-8433,907,347), + [1] = {pos = Vector(-5173,969,1600), ang = Angle(20,-180,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-8935,936,1800), ang = Angle(0,-180,0), wait = false, sec = 15, dist = 400, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-8935,936,610), ang = Angle(0,-180,0), wait = true, sec = 3, dist = 50, damp = 0.5, smoothrotate = true}, + [4] = {pos = Vector(-8935,936,1800), ang = Angle(0,-180,0), wait = false, sec = 6, dist = 200, damp = 0.9}, + [5] = {pos = Vector(-14428,993,3280), ang = Angle(20,-180,0), wait = false, sec = 10, dist = 300, damp = 1}, + }, + { + ["Main"] = Vector(-11593,1561,-478), + [1] = {pos = Vector(-4910,1531,2600), ang = Angle(20,-180,0), wait = false, sec = 0, dist = 0, damp = 0.5}, + [2] = {pos = Vector(-12052,1553,1300), ang = Angle(0,-180,0), wait = false, sec = 15, dist = 400, damp = 0.5, smoothrotate = true}, + [3] = {pos = Vector(-12052,1553,-215), ang = Angle(0,-180,0), wait = true, sec = 3, dist = 50, damp = 0.5, smoothrotate = true}, + [4] = {pos = Vector(-12052,1553,1300), ang = Angle(0,-180,0), wait = false, sec = 6, dist = 200, damp = 0.9}, + [5] = {pos = Vector(-14503,-5218,1255), ang = Angle(20,-115,0), wait = false, sec = 10, dist = 300, damp = 1}, + }, +} + +SuR.Config.Deploy_Cutscene = { + cam = { + { + pos = Vector(-8726,288,57), + ang = Angle(-1,-129,0), + fov = 100, + time = 5, + }, + { + pos = Vector(-8719,184,223), + ang = Angle(-4,-5,0), + fov = 80, + time = 5, + }, + { + pos = Vector(-8659,282,237), + ang = Angle(2,25,0), + fov = 60, + time = 5, + }, + }, + model = { + { + pos = Vector(-8394,248,181), + ang = Angle(0,175,0), + }, + { + pos = Vector(-8391,304,181), + ang = Angle(0,-176,0), + }, + { + pos = Vector(-8399,357,181), + ang = Angle(0,-161,0), + }, + { + pos = Vector(-8423,408,181), + ang = Angle(0,-145,0), + }, + { + pos = Vector(-8459,463,181), + ang = Angle(0,-133,0), + }, + { + pos = Vector(-8506,492,181), + ang = Angle(0,-110,0), + }, + }, +} + +SuR.Config.Objective_Mode = true +SuR.Config.Objective_Mode_Wave = 15 +SuR.Config.Objective_Mode_Max_Cans = 64 +SuR.Config.Objective_Mode_Positions = { + ["fuel"] = { + Vector(-7362,-3586,-224), + Vector(-7353,-3562,-360), + Vector(-7337,-3570,-88), + Vector(-7327,-3662,48), + Vector(-7142,-3356,-496), + Vector(-7242,-3978,-493), + Vector(-7991,-3914,-495), + Vector(-8045,-3892,-359), + Vector(-8046,-3931,-223), + Vector(-8124,-3570,-360), + Vector(-8462,-3497,-494), + Vector(-7321,-3809,-358), + Vector(-7324,-4501,-360), + Vector(-7859,-2630,-348), + Vector(-7114,-2808,-496), + Vector(-7113,-2795,-360), + Vector(-7248,-2182,-360), + Vector(-7250,-1322,-360), + Vector(-7108,-1318,-224), + Vector(-7081,-916,-223), + Vector(-7117,-972,-359), + Vector(-7133,-941,-495), + Vector(-8057,-369,-360), + Vector(-7920,-1030,-357), + Vector(-8526,234,-496), + Vector(-8248,915,-360), + Vector(-8237,919,-224), + Vector(-8005,872,-88), + Vector(-8390,733,48), + Vector(-7946,1887,-359), + Vector(-7944,1912,-223), + Vector(-7954,2507,-360), + Vector(-7960,2485,-496), + Vector(-7962,1893,-495), + Vector(-8704,-610,-367), + Vector(-8658,-336,-480), + Vector(-9752,1765,-456), + Vector(-9014,3952,-481), + Vector(-9785,-1049,-360), + Vector(-9786,-1052,-224), + Vector(-9925,-433,-223), + Vector(-9906,-446,-359), + Vector(-9910,-439,-495), + Vector(-9880,-1470,-360), + Vector(-9756,-1490,-496), + Vector(-9764,-2166,-357), + Vector(-9692,-2353,-360), + Vector(-9693,-2360,-224), + Vector(-9847,-2785,-495), + Vector(-9842,-2778,-359), + Vector(-9832,-2753,-223), + Vector(-9636,-4645,-491), + Vector(-10210,-4769,-497), + Vector(-12451,-3831,-508), + Vector(-12407,-4177,-508), + Vector(-5742,4112,-508), + Vector(-5754,4503,-508), + Vector(-9114,-1596,-360), + Vector(-9122,-1597,-224), + Vector(-8962,-2147,-359), + Vector(-8977,-2154,-223), + Vector(-8556,-2652,-359), + Vector(-8532,-2661,-223), + Vector(-8539,-2645,-495), + Vector(-6487,-3238,-508), + Vector(-7733,-3992,-508), + Vector(-9308,-2289,-508), + Vector(-9904,-3531,-508), + Vector(-9250,2702,-508), + Vector(-7927,3122,-508), + Vector(-8808,-1568,-508), + }, + ["generator"] = { + { + pos = Vector(-8433,253,181), + ang = Angle(1,91,0), + }, + { + pos = Vector(-8759,-76,-511), + ang = Angle(-0,3,1), + }, + { + pos = Vector(-10256,812,-507), + ang = Angle(-0,90,0), + }, + { + pos = Vector(-10258,1653,-507), + ang = Angle(1,-90,-0), + }, + { + pos = Vector(-8563,-464,-370), + ang = Angle(1,-179,0), + }, + { + pos = Vector(-9932,-3932,-496), + ang = Angle(0,1,0), + }, + }, +} + +local models = { + "models/surrounded/obj/m_vsrf.mdl" +} +SuR.Config.Allowed_PlayerModels = models \ No newline at end of file