This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 8064ba84d8
commit 6a58f406b1
7522 changed files with 4011896 additions and 15 deletions

5
gamemodes/base/base.txt Normal file
View File

@@ -0,0 +1,5 @@
"base"
{
"title" "Base"
"base" ""
}

View File

@@ -0,0 +1,49 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
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

View File

@@ -0,0 +1,65 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
EFFECT.Mat = Material( "pp/dof" )
function EFFECT:Init( data )
table.insert( DOF_Ents, self )
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

View File

@@ -0,0 +1,68 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,33 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include( "shared.lua" )
--[[---------------------------------------------------------
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

View File

@@ -0,0 +1,147 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile( "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 to update which sounds the NPC should be able to hear
function ENT:GetSoundInterests()
-- Hear thumper sound hints
-- return 256
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

View File

@@ -0,0 +1,216 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
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 )
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 )
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
function ENT:TranslateActivity( act )
-- Return a value to translate the activity to a new one
-- if ( act == ACT_WALK ) then return ACT_RUN end
end

View File

@@ -0,0 +1,54 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,90 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
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 )
for k, v in ipairs( ents.FindInSphere( self:GetPos(), data.Radius or 512 ) ) 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

View File

@@ -0,0 +1,114 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
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

View File

@@ -0,0 +1,66 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,34 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,87 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile( "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

View File

@@ -0,0 +1,133 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- This is called from ENT:KeyValue(key,value) to store the output from
-- the map, it could also be called from ENT:AcceptInput I think, so if
-- ent_fire addoutput is used, we can store that too (that hasn't been
-- tested though).
-- Usage: self:StoreOutput("<name of output>","<entities to fire>,<input name>,<param>,<delay>,<times to be used>")
-- If called from ENT:KeyValue, then the first parameter is the key, and
-- the second is value.
function ENT:StoreOutput( name, info )
-- Newer Source Engine games use this symbol as a delimiter
local rawData = string.Explode( "\x1B", info )
if ( #rawData < 2 ) then
rawData = string.Explode( ",", info )
end
local Output = {}
Output.entities = rawData[1] or ""
Output.input = rawData[2] or ""
Output.param = rawData[3] or ""
Output.delay = tonumber( rawData[4] ) or 0
Output.times = tonumber( rawData[5] ) or -1
self.m_tOutputs = self.m_tOutputs or {}
self.m_tOutputs[ name ] = self.m_tOutputs[ name ] or {}
table.insert( self.m_tOutputs[ name ], Output )
end
-- This works like SetNetworkKeyValue, call it from ENT:KeyValue and it'll
-- return true if it successfully added an output from the passed KV pair.
function ENT:AddOutputFromKeyValue( key, value )
if ( key:sub( 1, 2 ) == "On" ) then
self:StoreOutput( key, value )
return true
end
return false
end
-- Call from ENT:AcceptInput and it'll return true if the input was AddOutput
-- and if it successfully added an output.
-- Note that to be strictly compatible with Source entities, AddOutput should
-- allow setting arbitrary keyvalues, but this implementation does not.
function ENT:AddOutputFromAcceptInput( name, value )
if ( name ~= "AddOutput" ) then
return false
end
local pos = string.find( value, " ", 1, true )
if ( pos == nil ) then
return false
end
name, value = value:sub( 1, pos - 1 ), value:sub( pos + 1 )
-- This is literally KeyValue but as an input and with ,s as :s.
value = value:gsub( ":", "," )
return self:AddOutputFromKeyValue( name, value )
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 ipairs( 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, activator, data ) ) then
-- Shift the indexes so this loop doesn't fail later
table.remove( self.m_tOutputs[ name ], idx )
end
end
end

View File

@@ -0,0 +1,16 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
ENT.Base = "base_entity"
ENT.Type = "anim"
ENT.Spawnable = false
ENT.AdminOnly = false

View File

@@ -0,0 +1,54 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,64 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Base = "base_entity"
ENT.PrintName = ""
ENT.Author = ""
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
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

View File

@@ -0,0 +1,425 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--
-- 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:OnTakeDamage
-- Desc: Called when the bot is about to take damage
-- Arg1: CTakeDamageInfo|info|damage info
-- Ret1: number|how much damage was taken, prevents default damage code from running
--
function ENT:OnTakeDamage( damageinfo )
-- return 0
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 ipairs( areas ) do
-- get the spots
local spots
if ( tbl.type == 'hiding' ) then spots = area:GetHidingSpots() end
for k, vec in ipairs( spots ) do
-- Work out the length, and add them to a table
path:Invalidate()
path:Compute( self, vec ) -- 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

View File

@@ -0,0 +1,55 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,142 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
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 sunlist = ents.FindByClass( "env_sun" )
if ( #sunlist > 0 ) then
self.EnvSun = sunlist[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 && !IsValid( g_SkyPaint ) ) then
g_SkyPaint = self
end
end
--
-- To prevent server insanity - only let admins edit the sky.
--
function ENT:CanEditVariables( ply )
return ply:IsAdmin() || game.SinglePlayer()
end

View File

@@ -0,0 +1,77 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
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

View File

@@ -0,0 +1,91 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,20 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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"

View File

@@ -0,0 +1,73 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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

View File

@@ -0,0 +1,82 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
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"
} )

View File

@@ -0,0 +1,188 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
if ( CLIENT ) then
CreateConVar( "cl_draweffectrings", "1", 0, "Should the green effect 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

View File

@@ -0,0 +1,317 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
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 )
if ( IsValid( ragdoll.MotionSensorController ) && ragdoll.MotionSensorController == self ) then
ragdoll.MotionSensorController = nil
end
end
end
end
function ENT:Draw()
--
-- Don't draw if we're holding the camera
--
local ply = LocalPlayer()
local wep = ply:GetActiveWeapon()
if ( IsValid( wep ) && wep:GetClass() == "gmod_camera" ) then
return
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 )
debugoverlay.Box( fixedbonepos[i], min, max, StayTime, col_tran_bn )
end
--
-- Draw bones
--
for k, v in ipairs( motionsensor.DebugBones ) do
debugoverlay.Line( realbonepos[ v[1] ], realbonepos[ v[2] ], StayTime, col_bone, true )
end
--
-- Draw translated sensor bones
--
for k, v in ipairs( 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 position = phys:GetPos()
local angle = phys:GetAngles()
local txt = tostring( i )
if ( ang[i] == nil ) then
txt = i .. " (UNSET)"
end
debugoverlay.Text( position, txt, StayTime )
debugoverlay.Axis( position, angle, 5, StayTime, true )
end
end
function ENT:SetRagdoll( ragdoll )
ragdoll.MotionSensorController = self
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

View File

@@ -0,0 +1,202 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
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

View File

@@ -0,0 +1,221 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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 title_color = "<color=230,230,230,255>"
local text_color = "<color=150,150,150,255>"
local str = "<font=HudSelectionText>"
if ( self.Author != "" ) then str = str .. title_color .. "Author:</color>\t" .. text_color .. self.Author .. "</color>\n" end
if ( self.Contact != "" ) then str = str .. title_color .. "Contact:</color>\t" .. text_color .. self.Contact .. "</color>\n\n" end
if ( self.Purpose != "" ) then str = str .. title_color .. "Purpose:</color>\n" .. text_color .. self.Purpose .. "</color>\n\n" end
if ( self.Instructions != "" ) then str = str .. title_color .. "Instructions:</color>\n" .. text_color .. self.Instructions .. "</color>\n" end
str = str .. "</font>"
self.InfoMarkup = markup.Parse( str, 250 )
end
surface.SetDrawColor( 60, 60, 60, alpha )
surface.SetTexture( self.SpeechBubbleLid )
surface.DrawTexturedRect( x, y - 64 - 5, 128, 64 )
draw.RoundedBox( 8, x - 5, y - 6, 260, self.InfoMarkup:GetHeight() + 18, Color( 60, 60, 60, alpha ) )
self.InfoMarkup:Draw( x + 5, y + 5, nil, nil, alpha )
end
--[[---------------------------------------------------------
Name: SWEP:FreezeMovement()
Desc: Return true to freeze moving the view
-----------------------------------------------------------]]
function SWEP:FreezeMovement()
return false
end
--[[---------------------------------------------------------
Name: SWEP:ViewModelDrawn( viewModel )
Desc: Called straight after the viewmodel has been drawn
-----------------------------------------------------------]]
function SWEP:ViewModelDrawn( vm )
end
--[[---------------------------------------------------------
Name: OnRestore
Desc: Called immediately after a "load"
-----------------------------------------------------------]]
function SWEP:OnRestore()
end
--[[---------------------------------------------------------
Name: CustomAmmoDisplay
Desc: Return a table
-----------------------------------------------------------]]
function SWEP:CustomAmmoDisplay()
end
--[[---------------------------------------------------------
Name: GetViewModelPosition
Desc: Allows you to re-position the view model
-----------------------------------------------------------]]
function SWEP:GetViewModelPosition( pos, ang )
return pos, ang
end
--[[---------------------------------------------------------
Name: TranslateFOV
Desc: Allows the weapon to translate the player's FOV (clientside)
-----------------------------------------------------------]]
function SWEP:TranslateFOV( current_fov )
return current_fov
end
--[[---------------------------------------------------------
Name: DrawWorldModel
Desc: Draws the world model (not the viewmodel)
-----------------------------------------------------------]]
function SWEP:DrawWorldModel()
self:DrawModel()
end
--[[---------------------------------------------------------
Name: DrawWorldModelTranslucent
Desc: Draws the world model (not the viewmodel)
-----------------------------------------------------------]]
function SWEP:DrawWorldModelTranslucent()
self:DrawModel()
end
--[[---------------------------------------------------------
Name: AdjustMouseSensitivity
Desc: Allows you to adjust the mouse sensitivity.
-----------------------------------------------------------]]
function SWEP:AdjustMouseSensitivity()
return nil
end
--[[---------------------------------------------------------
Name: GetTracerOrigin
Desc: Allows you to override where the tracer comes from (in first person view)
returning anything but a vector indicates that you want the default action
-----------------------------------------------------------]]
function SWEP:GetTracerOrigin()
--[[
local ply = self:GetOwner()
local pos = ply:EyePos() + ply:EyeAngles():Right() * -5
return pos
--]]
end
--[[---------------------------------------------------------
Name: FireAnimationEvent
Desc: Allows you to override weapon animation events
-----------------------------------------------------------]]
function SWEP:FireAnimationEvent( pos, ang, event, options )
if ( !self.CSMuzzleFlashes ) then return end
-- CS Muzzle flashes
if ( event == 5001 or event == 5011 or event == 5021 or event == 5031 ) then
local data = EffectData()
data:SetFlags( 0 )
data:SetEntity( self:GetOwner():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

View File

@@ -0,0 +1,114 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile( "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 immediately 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" )

View File

@@ -0,0 +1,97 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
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:GetOwner():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

View File

@@ -0,0 +1,280 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- 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
local owner = self:GetOwner()
if ( !owner:IsNPC() ) then 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
local owner = self:GetOwner()
if ( !owner:IsNPC() ) then 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()
local owner = self:GetOwner()
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) -- View model animation
owner:MuzzleFlash() -- Crappy muzzle light
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 owner = self:GetOwner()
local bullet = {}
bullet.Num = num_bullets
bullet.Src = owner:GetShootPos() -- Source
bullet.Dir = 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
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:GetOwner():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:GetOwner():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:GetOwner():GetAmmoCount( self:GetPrimaryAmmoType() )
end
--[[---------------------------------------------------------
Name: Ammo2
Desc: Returns how much of ammo2 the player has
-----------------------------------------------------------]]
function SWEP:Ammo2()
return self:GetOwner():GetAmmoCount( self:GetSecondaryAmmoType() )
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

View File

@@ -0,0 +1,406 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
function GM:HandlePlayerJumping( ply, velocity, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
if ( ply:GetMoveType() == MOVETYPE_NOCLIP ) then
plyTable.m_bJumping = false
return
end
-- airwalk more like hl2mp, we airwalk until we have 0 velocity, then it's the jump animation
-- underwater we're alright we airwalking
if ( !plyTable.m_bJumping && !ply:OnGround() && ply:WaterLevel() <= 0 ) then
if ( !plyTable.m_fGroundTime ) then
plyTable.m_fGroundTime = CurTime()
elseif ( ( CurTime() - plyTable.m_fGroundTime ) > 0 && velocity:Length2DSqr() < 0.25 ) then
plyTable.m_bJumping = true
plyTable.m_bFirstJumpFrame = false
plyTable.m_flJumpStartTime = 0
end
end
if ( plyTable.m_bJumping ) then
if ( plyTable.m_bFirstJumpFrame ) then
plyTable.m_bFirstJumpFrame = false
ply:AnimRestartMainSequence()
end
if ( ( ply:WaterLevel() >= 2 ) || ( ( CurTime() - plyTable.m_flJumpStartTime ) > 0.2 && ply:OnGround() ) ) then
plyTable.m_bJumping = false
plyTable.m_fGroundTime = nil
ply:AnimRestartMainSequence()
end
if ( plyTable.m_bJumping ) then
plyTable.CalcIdeal = ACT_MP_JUMP
return true
end
end
return false
end
function GM:HandlePlayerDucking( ply, velocity, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
if ( !ply:IsFlagSet( FL_ANIMDUCKING ) ) then return false end
if ( velocity:Length2DSqr() > 0.25 ) then
plyTable.CalcIdeal = ACT_MP_CROUCHWALK
else
plyTable.CalcIdeal = ACT_MP_CROUCH_IDLE
end
return true
end
function GM:HandlePlayerNoClipping( ply, velocity, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
if ( ply:GetMoveType() != MOVETYPE_NOCLIP || ply:InVehicle() ) then
if ( plyTable.m_bWasNoclipping ) then
plyTable.m_bWasNoclipping = nil
ply:AnimResetGestureSlot( GESTURE_SLOT_CUSTOM )
if ( CLIENT ) then ply:SetIK( true ) end
end
return
end
if ( !plyTable.m_bWasNoclipping ) then
ply:AnimRestartGesture( GESTURE_SLOT_CUSTOM, ACT_GMOD_NOCLIP_LAYER, false )
if ( CLIENT ) then ply:SetIK( false ) end
end
return true
end
function GM:HandlePlayerVaulting( ply, velocity, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
if ( velocity:LengthSqr() < 1000000 ) then return end
if ( ply:IsOnGround() ) then return end
plyTable.CalcIdeal = ACT_MP_SWIM
return true
end
function GM:HandlePlayerSwimming( ply, velocity, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
if ( ply:WaterLevel() < 2 || ply:IsOnGround() ) then
plyTable.m_bInSwim = false
return false
end
plyTable.CalcIdeal = ACT_MP_SWIM
plyTable.m_bInSwim = true
return true
end
function GM:HandlePlayerLanding( ply, velocity, WasOnGround )
if ( ply:GetMoveType() == MOVETYPE_NOCLIP ) then return end
if ( ply:IsOnGround() && !WasOnGround ) then
ply:AnimRestartGesture( GESTURE_SLOT_JUMP, ACT_LAND, true )
end
end
function GM:HandlePlayerDriving( ply, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
-- The player must have a parent to be in a vehicle. If there's no parent, we are in the exit anim, so don't do sitting in 3rd person anymore
if ( !ply:InVehicle() || !IsValid( ply:GetParent() ) ) then return false end
local pVehicle = ply:GetVehicle()
if ( !pVehicle.HandleAnimation && pVehicle.GetVehicleClass ) then
local c = pVehicle:GetVehicleClass()
local t = list.Get( "Vehicles" )[ c ]
if ( t && t.Members && t.Members.HandleAnimation ) then
pVehicle.HandleAnimation = t.Members.HandleAnimation
else
pVehicle.HandleAnimation = true -- Prevent this if block from trying to assign HandleAnimation again.
end
end
if ( isfunction( pVehicle.HandleAnimation ) ) then
local seq = pVehicle:HandleAnimation( ply )
if ( seq != nil ) then
plyTable.CalcSeqOverride = seq
end
end
if ( plyTable.CalcSeqOverride == -1 ) then -- pVehicle.HandleAnimation did not give us an animation
local class = pVehicle:GetClass()
if ( class == "prop_vehicle_jeep" ) then
plyTable.CalcSeqOverride = ply:LookupSequence( "drive_jeep" )
elseif ( class == "prop_vehicle_airboat" ) then
plyTable.CalcSeqOverride = ply:LookupSequence( "drive_airboat" )
elseif ( class == "prop_vehicle_prisoner_pod" && pVehicle:GetModel() == "models/vehicles/prisoner_pod_inner.mdl" ) then
-- HACK!!
plyTable.CalcSeqOverride = ply:LookupSequence( "drive_pd" )
else
plyTable.CalcSeqOverride = ply:LookupSequence( "sit_rollercoaster" )
end
end
local use_anims = ( plyTable.CalcSeqOverride == ply:LookupSequence( "sit_rollercoaster" ) || plyTable.CalcSeqOverride == ply:LookupSequence( "sit" ) )
if ( use_anims && ply:GetAllowWeaponsInVehicle() && IsValid( ply:GetActiveWeapon() ) ) then
local holdtype = ply:GetActiveWeapon():GetHoldType()
if ( holdtype == "smg" ) then holdtype = "smg1" end
local seqid = ply:LookupSequence( "sit_" .. holdtype )
if ( seqid != -1 ) then
plyTable.CalcSeqOverride = seqid
end
end
return true
end
--[[---------------------------------------------------------
Name: gamemode:UpdateAnimation()
Desc: Animation updates (pose params etc) should be done here
-----------------------------------------------------------]]
function GM:UpdateAnimation( ply, velocity, maxseqgroundspeed )
local len = velocity:Length()
local movement = 1.0
if ( len > 0.2 ) then
movement = ( len / maxseqgroundspeed )
end
local rate = math.min( movement, 2 )
-- if we're under water we want to constantly be swimming..
if ( ply:WaterLevel() >= 2 ) then
rate = math.max( rate, 0.5 )
elseif ( !ply:IsOnGround() && len >= 1000 ) then
rate = 0.1
end
ply:SetPlaybackRate( rate )
-- We only need to do this clientside..
if ( CLIENT ) then
if ( ply:InVehicle() ) then
--
-- This is used for the 'rollercoaster' arms
--
local Vehicle = ply:GetVehicle()
local Velocity = Vehicle:GetVelocity()
local fwd = Vehicle:GetUp()
local dp = fwd:Dot( Vector( 0, 0, 1 ) )
ply:SetPoseParameter( "vertical_velocity", ( dp < 0 && dp || 0 ) + fwd:Dot( Velocity ) * 0.005 )
-- Pass the vehicles steer param down to the player
local steer = Vehicle:GetPoseParameter( "vehicle_steer" )
steer = steer * 2 - 1 -- convert from 0..1 to -1..1
if ( Vehicle:GetClass() == "prop_vehicle_prisoner_pod" ) then steer = 0 ply:SetPoseParameter( "aim_yaw", math.NormalizeAngle( ply:GetAimVector():Angle().y - Vehicle:GetAngles().y - 90 ) ) end
ply:SetPoseParameter( "vehicle_steer", steer )
end
GAMEMODE:GrabEarAnimation( ply )
GAMEMODE:MouthMoveAnimation( ply )
end
end
--
-- If you don't want the player to grab his ear in your gamemode then
-- just override this.
--
function GM:GrabEarAnimation( ply, plyTable )
if ( !plyTable ) then plyTable = ply:GetTable() end
plyTable.ChatGestureWeight = plyTable.ChatGestureWeight || 0
-- Don't show this when we're playing a taunt!
if ( ply:IsPlayingTaunt() ) then return end
if ( ply:IsTyping() ) then
plyTable.ChatGestureWeight = math.Approach( plyTable.ChatGestureWeight, 1, FrameTime() * 5.0 )
else
plyTable.ChatGestureWeight = math.Approach( plyTable.ChatGestureWeight, 0, FrameTime() * 5.0 )
end
if ( plyTable.ChatGestureWeight > 0 ) then
ply:AnimRestartGesture( GESTURE_SLOT_VCD, ACT_GMOD_IN_CHAT, true )
ply:AnimSetGestureWeight( GESTURE_SLOT_VCD, plyTable.ChatGestureWeight )
end
end
--
-- Moves the mouth when talking on voicecom
--
function GM:MouthMoveAnimation( ply )
local flexes = {
ply:GetFlexIDByName( "jaw_drop" ),
ply:GetFlexIDByName( "left_part" ),
ply:GetFlexIDByName( "right_part" ),
ply:GetFlexIDByName( "left_mouth_drop" ),
ply:GetFlexIDByName( "right_mouth_drop" )
}
local weight = ply:IsSpeaking() && math.Clamp( ply:VoiceVolume() * 2, 0, 2 ) || 0
for k, v in ipairs( flexes ) do
ply:SetFlexWeight( v, weight )
end
end
function GM:CalcMainActivity( ply, velocity )
local plyTable = ply:GetTable()
plyTable.CalcIdeal = ACT_MP_STAND_IDLE
plyTable.CalcSeqOverride = -1
self:HandlePlayerLanding( ply, velocity, plyTable.m_bWasOnGround )
if !( self:HandlePlayerNoClipping( ply, velocity, plyTable ) ||
self:HandlePlayerDriving( ply, plyTable ) ||
self:HandlePlayerVaulting( ply, velocity, plyTable ) ||
self:HandlePlayerJumping( ply, velocity, plyTable ) ||
self:HandlePlayerSwimming( ply, velocity, plyTable ) ||
self:HandlePlayerDucking( ply, velocity, plyTable ) ) then
local len2d = velocity:Length2DSqr()
if ( len2d > 22500 ) then plyTable.CalcIdeal = ACT_MP_RUN elseif ( len2d > 0.25 ) then plyTable.CalcIdeal = ACT_MP_WALK end
end
plyTable.m_bWasOnGround = ply:IsOnGround()
plyTable.m_bWasNoclipping = ( ply:GetMoveType() == MOVETYPE_NOCLIP && !ply:InVehicle() )
return plyTable.CalcIdeal, plyTable.CalcSeqOverride
end
local IdleActivity = ACT_HL2MP_IDLE
local IdleActivityTranslate = {}
IdleActivityTranslate[ ACT_MP_STAND_IDLE ] = IdleActivity
IdleActivityTranslate[ ACT_MP_WALK ] = IdleActivity + 1
IdleActivityTranslate[ ACT_MP_RUN ] = IdleActivity + 2
IdleActivityTranslate[ ACT_MP_CROUCH_IDLE ] = IdleActivity + 3
IdleActivityTranslate[ ACT_MP_CROUCHWALK ] = IdleActivity + 4
IdleActivityTranslate[ ACT_MP_ATTACK_STAND_PRIMARYFIRE ] = IdleActivity + 5
IdleActivityTranslate[ ACT_MP_ATTACK_CROUCH_PRIMARYFIRE ] = IdleActivity + 5
IdleActivityTranslate[ ACT_MP_RELOAD_STAND ] = IdleActivity + 6
IdleActivityTranslate[ ACT_MP_RELOAD_CROUCH ] = IdleActivity + 6
IdleActivityTranslate[ ACT_MP_JUMP ] = ACT_HL2MP_JUMP_SLAM
IdleActivityTranslate[ ACT_MP_SWIM ] = IdleActivity + 9
IdleActivityTranslate[ ACT_LAND ] = ACT_LAND
-- it is preferred you return ACT_MP_* in CalcMainActivity, and if you have a specific need to not translate through the weapon do it here
function GM:TranslateActivity( ply, act )
local newact = ply:TranslateWeaponActivity( act )
-- select idle anims if the weapon didn't decide
if ( act == newact ) then
return IdleActivityTranslate[ act ]
end
return newact
end
function GM:DoAnimationEvent( ply, event, data )
if ( event == PLAYERANIMEVENT_ATTACK_PRIMARY ) then
if ply:IsFlagSet( FL_ANIMDUCKING ) then
ply:AnimRestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, true )
else
ply:AnimRestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_PRIMARYFIRE, true )
end
return ACT_VM_PRIMARYATTACK
elseif ( event == PLAYERANIMEVENT_ATTACK_SECONDARY ) then
-- there is no gesture, so just fire off the VM event
return ACT_VM_SECONDARYATTACK
elseif ( event == PLAYERANIMEVENT_RELOAD ) then
if ply:IsFlagSet( FL_ANIMDUCKING ) then
ply:AnimRestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH, true )
else
ply:AnimRestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND, true )
end
return ACT_INVALID
elseif ( event == PLAYERANIMEVENT_JUMP ) then
ply.m_bJumping = true
ply.m_bFirstJumpFrame = true
ply.m_flJumpStartTime = CurTime()
ply:AnimRestartMainSequence()
return ACT_INVALID
elseif ( event == PLAYERANIMEVENT_CANCEL_RELOAD ) then
ply:AnimResetGestureSlot( GESTURE_SLOT_ATTACK_AND_RELOAD )
return ACT_INVALID
end
end

View File

@@ -0,0 +1,302 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hud_deathnotice_time = CreateConVar( "hud_deathnotice_time", "6", FCVAR_REPLICATED, "Amount of time to show death notice (kill feed) for" )
local cl_drawhud = GetConVar( "cl_drawhud" )
-- These are our kill icons
local Color_Icon = Color( 255, 80, 0, 255 )
local NPC_Color_Enemy = Color( 250, 50, 50, 255 )
local NPC_Color_Friendly = Color( 50, 200, 50, 255 )
killicon.AddFont( "prop_physics", "HL2MPTypeDeath", "9", Color_Icon, 0.52 )
killicon.AddFont( "weapon_smg1", "HL2MPTypeDeath", "/", Color_Icon, 0.55 )
killicon.AddFont( "weapon_357", "HL2MPTypeDeath", ".", Color_Icon, 0.55 )
killicon.AddFont( "weapon_ar2", "HL2MPTypeDeath", "2", Color_Icon, 0.6 )
killicon.AddFont( "crossbow_bolt", "HL2MPTypeDeath", "1", Color_Icon, 0.5 )
killicon.AddFont( "weapon_shotgun", "HL2MPTypeDeath", "0", Color_Icon, 0.45 )
killicon.AddFont( "rpg_missile", "HL2MPTypeDeath", "3", Color_Icon, 0.35 )
killicon.AddFont( "npc_grenade_frag", "HL2MPTypeDeath", "4", Color_Icon, 0.56 )
killicon.AddFont( "weapon_pistol", "HL2MPTypeDeath", "-", Color_Icon, 0.52 )
killicon.AddFont( "prop_combine_ball", "HL2MPTypeDeath", "8", Color_Icon, 0.5 )
killicon.AddFont( "grenade_ar2", "HL2MPTypeDeath", "7", Color_Icon, 0.35 )
killicon.AddFont( "weapon_stunstick", "HL2MPTypeDeath", "!", Color_Icon, 0.6 )
killicon.AddFont( "npc_satchel", "HL2MPTypeDeath", "*", Color_Icon, 0.53 )
killicon.AddAlias( "npc_tripmine", "npc_satchel" )
killicon.AddFont( "weapon_crowbar", "HL2MPTypeDeath", "6", Color_Icon, 0.45 )
killicon.AddFont( "weapon_physcannon", "HL2MPTypeDeath", ",", Color_Icon, 0.55 )
-- Prop like objects get the prop kill icon
killicon.AddAlias( "prop_ragdoll", "prop_physics" )
killicon.AddAlias( "prop_physics_respawnable", "prop_physics" )
killicon.AddAlias( "func_physbox", "prop_physics" )
killicon.AddAlias( "func_physbox_multiplayer", "prop_physics" )
killicon.AddAlias( "trigger_vphysics_motion", "prop_physics" )
killicon.AddAlias( "func_movelinear", "prop_physics" )
killicon.AddAlias( "func_plat", "prop_physics" )
killicon.AddAlias( "func_platrot", "prop_physics" )
killicon.AddAlias( "func_pushable", "prop_physics" )
killicon.AddAlias( "func_rotating", "prop_physics" )
killicon.AddAlias( "func_rot_button", "prop_physics" )
killicon.AddAlias( "func_tracktrain", "prop_physics" )
killicon.AddAlias( "func_train", "prop_physics" )
local function HandleAchievements( victimType )
-- Try to find by name
for id, tab in pairs( list.Get( "NPC" ) ) do
if ( tab.Name == victimType ) then
victimType = tab.Class
end
end
-- If fails, try to omit the translation system #
if ( victimType:StartsWith( "#" ) ) then
victimType = victimType:sub( 2 )
end
local bIsEnemy = IsEnemyEntityName( victimType )
local bIsFriend = IsFriendEntityName( victimType )
if ( bIsEnemy ) then
achievements.IncBaddies()
end
if ( bIsFriend ) then
achievements.IncGoodies()
end
if ( !bIsFriend && !bIsEnemy ) then
achievements.IncBystander()
end
end
-- Backwards compatiblity for addons
net.Receive( "PlayerKilledByPlayer", function()
local victim = net.ReadEntity()
local inflictor = net.ReadString()
local attacker = net.ReadEntity()
if ( !IsValid( attacker ) ) then return end
if ( !IsValid( victim ) ) then return end
hook.Run( "AddDeathNotice", attacker:Name(), attacker:Team(), inflictor, victim:Name(), victim:Team(), 0 )
end )
net.Receive( "PlayerKilledSelf", function()
local victim = net.ReadEntity()
if ( !IsValid( victim ) ) then return end
hook.Run( "AddDeathNotice", nil, 0, "suicide", victim:Name(), victim:Team(), 0 )
end )
net.Receive( "PlayerKilled", function()
local victim = net.ReadEntity()
if ( !IsValid( victim ) ) then return end
local inflictor = net.ReadString()
local attacker = net.ReadString()
hook.Run( "AddDeathNotice", "#" .. attacker, -1, inflictor, victim:Name(), victim:Team(), 0 )
end )
net.Receive( "PlayerKilledNPC", function()
local victimtype = net.ReadString()
local inflictor = net.ReadString()
local attacker = net.ReadEntity()
--
-- For some reason the killer isn't known to us, so don't proceed.
--
if ( !IsValid( attacker ) ) then return end
hook.Run( "AddDeathNotice", attacker:Name(), attacker:Team(), inflictor, "#" .. victimtype, -1, 0 )
local bIsLocalPlayer = ( IsValid( attacker ) && attacker == LocalPlayer() )
if ( bIsLocalPlayer ) then
HandleAchievements( victimtype )
end
end )
net.Receive( "NPCKilledNPC", function()
local victim = "#" .. net.ReadString()
local inflictor = net.ReadString()
local attacker = "#" .. net.ReadString()
hook.Run( "AddDeathNotice", attacker, -1, inflictor, victim, -1, 0 )
end )
-- The new way
DEATH_NOTICE_FRIENDLY_VICTIM = 1
DEATH_NOTICE_FRIENDLY_ATTACKER = 2
--DEATH_NOTICE_HEADSHOT = 4
--DEATH_NOTICE_PENETRATION = 8
net.Receive( "DeathNoticeEvent", function()
local attacker = nil
local attackerType = net.ReadUInt( 2 )
if ( attackerType == 1 ) then
attacker = net.ReadString()
elseif ( attackerType == 2 ) then
attacker = net.ReadEntity()
end
local inflictor = net.ReadString()
local victim = nil
local victimType = net.ReadUInt( 2 )
if ( victimType == 1 ) then
victim = net.ReadString()
elseif ( victimType == 2 ) then
victim = net.ReadEntity()
end
local flags = net.ReadUInt( 8 )
local bIsLocalPlayer = ( isentity( attacker ) && IsValid( attacker ) && attacker == LocalPlayer() )
if ( bIsLocalPlayer && isstring( victim ) ) then
HandleAchievements( victim )
end
local team_a = -1
local team_v = -1
if ( bit.band( flags, DEATH_NOTICE_FRIENDLY_VICTIM ) != 0 ) then team_v = -2 end
if ( bit.band( flags, DEATH_NOTICE_FRIENDLY_ATTACKER ) != 0 ) then team_a = -2 end
-- Handle player entities
if ( isentity( attacker ) and attacker:IsValid() and attacker:IsPlayer() ) then team_a = attacker:Team() attacker = attacker:Name() end
if ( isentity( victim ) and victim:IsValid() and victim:IsPlayer() ) then team_v = victim:Team() victim = victim:Name() end
-- Handle other entities
if ( isentity( attacker ) and attacker:IsValid() ) then attacker = attacker:GetClass() end
if ( isentity( victim ) and victim:IsValid() ) then victim = victim:GetClass() end
hook.Run( "AddDeathNotice", attacker, team_a, inflictor, victim, team_v, flags )
end )
local Deaths = {}
local function getDeathColor( teamID, target )
if ( teamID == -1 ) then
return table.Copy( NPC_Color_Enemy )
end
if ( teamID == -2 ) then
return table.Copy( NPC_Color_Friendly )
end
return table.Copy( team.GetColor( teamID ) )
end
--[[---------------------------------------------------------
Name: gamemode:AddDeathNotice( Attacker, team1, Inflictor, Victim, team2, flags )
Desc: Adds an death notice entry
-----------------------------------------------------------]]
function GM:AddDeathNotice( attacker, team1, inflictor, victim, team2, flags )
if ( inflictor == "suicide" ) then attacker = nil end
local Death = {}
Death.time = CurTime()
Death.left = attacker
Death.right = victim
Death.icon = inflictor
Death.flags = flags
Death.color1 = getDeathColor( team1, Death.left )
Death.color2 = getDeathColor( team2, Death.right )
table.insert( Deaths, Death )
end
local function DrawDeath( x, y, death, time )
local w, h = killicon.GetSize( death.icon )
if ( !w or !h ) then return end
local fadeout = ( death.time + time ) - CurTime()
local alpha = math.Clamp( fadeout * 255, 0, 255 )
death.color1.a = alpha
death.color2.a = alpha
-- Draw Icon
killicon.Render( x - w / 2, y, death.icon, alpha )
-- Draw KILLER
if ( death.left ) then
draw.SimpleText( death.left, "ChatFont", x - ( w / 2 ) - 16, y + h / 2, death.color1, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER )
end
-- Draw VICTIM
draw.SimpleText( death.right, "ChatFont", x + ( w / 2 ) + 16, y + h / 2, death.color2, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER )
return math.ceil( y + h * 0.75 )
-- Font killicons are too high when height corrected, and changing that is not backwards compatible
--return math.ceil( y + math.max( h, 28 ) )
end
function GM:DrawDeathNotice( x, y )
if ( cl_drawhud:GetInt() == 0 ) then return end
local time = hud_deathnotice_time:GetFloat()
local reset = Deaths[1] != nil -- Don't reset it if there's nothing in it
x = x * ScrW()
y = y * ScrH()
-- Draw
for k, Death in ipairs( Deaths ) do
if ( Death.time + time > CurTime() ) then
if ( Death.lerp ) then
x = x * 0.3 + Death.lerp.x * 0.7
y = y * 0.3 + Death.lerp.y * 0.7
end
Death.lerp = Death.lerp or {}
Death.lerp.x = x
Death.lerp.y = y
y = DrawDeath( math.floor( x ), math.floor( y ), Death, time )
reset = false
end
end
-- We want to maintain the order of the table so instead of removing
-- expired entries one by one we will just clear the entire table
-- once everything is expired.
if ( reset ) then
Deaths = {}
end
end

View File

@@ -0,0 +1,183 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
GM.PickupHistory = {}
GM.PickupHistoryLast = 0
GM.PickupHistoryTop = ScrH() / 2
GM.PickupHistoryWide = 300
GM.PickupHistoryCorner = surface.GetTextureID( "gui/corner8" )
local function AddGenericPickup( self, itemname )
local pickup = {}
pickup.time = CurTime()
pickup.name = itemname
pickup.holdtime = 5
pickup.font = "DermaDefaultBold"
pickup.fadein = 0.04
pickup.fadeout = 0.3
surface.SetFont( pickup.font )
local w, h = surface.GetTextSize( pickup.name )
pickup.height = h
pickup.width = w
--[[if ( self.PickupHistoryLast >= pickup.time ) then
pickup.time = self.PickupHistoryLast + 0.05
end]]
table.insert( self.PickupHistory, pickup )
self.PickupHistoryLast = pickup.time
return pickup
end
--[[---------------------------------------------------------
Name: gamemode:HUDWeaponPickedUp( wep )
Desc: The game wants you to draw on the HUD that a weapon has been picked up
-----------------------------------------------------------]]
function GM:HUDWeaponPickedUp( wep )
if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end
if ( !IsValid( wep ) ) then return end
if ( !isfunction( wep.GetPrintName ) ) then return end
local pickup = AddGenericPickup( self, wep:GetPrintName() )
pickup.color = Color( 255, 200, 50, 255 )
end
--[[---------------------------------------------------------
Name: gamemode:HUDItemPickedUp( itemname )
Desc: An item has been picked up..
-----------------------------------------------------------]]
function GM:HUDItemPickedUp( itemname )
if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end
local pickup = AddGenericPickup( self, "#" .. itemname )
pickup.color = Color( 180, 255, 180, 255 )
end
--[[---------------------------------------------------------
Name: gamemode:HUDAmmoPickedUp( itemname, amount )
Desc: Ammo has been picked up..
-----------------------------------------------------------]]
function GM:HUDAmmoPickedUp( itemname, amount )
if ( !IsValid( LocalPlayer() ) || !LocalPlayer():Alive() ) then return end
-- Try to tack it onto an exisiting ammo pickup
if ( self.PickupHistory ) then
for k, v in pairs( self.PickupHistory ) do
if ( v.name == "#" .. itemname .. "_ammo" ) then
v.amount = tostring( tonumber( v.amount ) + amount )
v.time = CurTime() - v.fadein
return
end
end
end
local pickup = AddGenericPickup( self, "#" .. itemname .. "_ammo" )
pickup.color = Color( 180, 200, 255, 255 )
pickup.amount = tostring( amount )
local w, h = surface.GetTextSize( pickup.amount )
pickup.width = pickup.width + w + 16
end
function GM:HUDDrawPickupHistory()
if ( self.PickupHistory == nil ) then return end
local x, y = ScrW() - self.PickupHistoryWide - 20, self.PickupHistoryTop
local tall = 0
local wide = 0
for k, v in pairs( self.PickupHistory ) do
if ( !istable( v ) ) then
Msg( tostring( v ) .. "\n" )
PrintTable( self.PickupHistory )
self.PickupHistory[ k ] = nil
return
end
if ( v.time < CurTime() ) then
if ( v.y == nil ) then v.y = y end
v.y = ( v.y * 5 + y ) / 6
local delta = ( v.time + v.holdtime ) - CurTime()
delta = delta / v.holdtime
local alpha = 255
local colordelta = math.Clamp( delta, 0.6, 0.7 )
-- Fade in/out
if ( delta > 1 - v.fadein ) then
alpha = math.Clamp( ( 1.0 - delta ) * ( 255 / v.fadein ), 0, 255 )
elseif ( delta < v.fadeout ) then
alpha = math.Clamp( delta * ( 255 / v.fadeout ), 0, 255 )
end
v.x = x + self.PickupHistoryWide - ( self.PickupHistoryWide * ( alpha / 255 ) )
local rx, ry, rw, rh = math.Round( v.x - 4 ), math.Round( v.y - ( v.height / 2 ) - 4 ), math.Round( self.PickupHistoryWide + 9 ), math.Round( v.height + 8 )
local bordersize = 8
surface.SetTexture( self.PickupHistoryCorner )
surface.SetDrawColor( v.color.r, v.color.g, v.color.b, alpha )
surface.DrawTexturedRectRotated( rx + bordersize / 2, ry + bordersize / 2, bordersize, bordersize, 0 )
surface.DrawTexturedRectRotated( rx + bordersize / 2, ry + rh -bordersize / 2, bordersize, bordersize, 90 )
surface.DrawRect( rx, ry + bordersize, bordersize, rh-bordersize * 2 )
surface.DrawRect( rx + bordersize, ry, v.height - 4, rh )
surface.SetDrawColor( 230 * colordelta, 230 * colordelta, 230 * colordelta, alpha )
surface.DrawTexturedRectRotated( rx + rw - bordersize / 2 , ry + rh - bordersize / 2, bordersize, bordersize, 180 )
surface.DrawTexturedRectRotated( rx + rw - bordersize / 2 , ry + bordersize / 2, bordersize, bordersize, 270 )
surface.DrawRect( rx + rw - bordersize, ry + bordersize, bordersize, rh-bordersize * 2 )
surface.DrawRect( rx + bordersize + v.height - 4, ry, rw - ( v.height - 4 ) - bordersize * 2, rh )
draw.SimpleText( v.name, v.font, v.x + v.height + 9, ry + ( rh / 2 ) + 1, Color( 0, 0, 0, alpha * 0.5 ), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER )
draw.SimpleText( v.name, v.font, v.x + v.height + 8, ry + ( rh / 2 ), Color( 255, 255, 255, alpha ), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER )
if ( v.amount ) then
draw.SimpleText( v.amount, v.font, v.x + self.PickupHistoryWide + 1, ry + ( rh / 2 ) + 1, Color( 0, 0, 0, alpha * 0.5 ), TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER )
draw.SimpleText( v.amount, v.font, v.x + self.PickupHistoryWide, ry + ( rh / 2 ), Color( 255, 255, 255, alpha ), TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER )
end
y = y + ( v.height + 16 )
tall = tall + v.height + 18
wide = math.max( wide, v.width + v.height + 24 )
if ( alpha == 0 ) then self.PickupHistory[ k ] = nil end
end
end
self.PickupHistoryTop = ( self.PickupHistoryTop * 5 + ( ScrH() * 0.75 - tall ) / 2 ) / 6
self.PickupHistoryWide = ( self.PickupHistoryWide * 5 + wide ) / 6
end

View File

@@ -0,0 +1,746 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include( "shared.lua" )
include( "cl_scoreboard.lua" )
include( "cl_targetid.lua" )
include( "cl_hudpickup.lua" )
include( "cl_spawnmenu.lua" )
include( "cl_deathnotice.lua" )
include( "cl_pickteam.lua" )
include( "cl_voice.lua" )
--[[---------------------------------------------------------
Name: gamemode:Initialize()
Desc: Called immediately after starting the gamemode
-----------------------------------------------------------]]
function GM:Initialize()
GAMEMODE.ShowScoreboard = false
end
--[[---------------------------------------------------------
Name: gamemode:InitPostEntity()
Desc: Called as soon as all map entities have been spawned
-----------------------------------------------------------]]
function GM:InitPostEntity()
end
--[[---------------------------------------------------------
Name: gamemode:Think()
Desc: Called every frame
-----------------------------------------------------------]]
function GM:Think()
end
--[[---------------------------------------------------------
Name: gamemode:PlayerBindPress()
Desc: A player pressed a bound key - return true to override action
-----------------------------------------------------------]]
function GM:PlayerBindPress( pl, bind, down )
return false
end
--[[---------------------------------------------------------
Name: gamemode:HUDShouldDraw( name )
Desc: return true if we should draw the named element
-----------------------------------------------------------]]
function GM:HUDShouldDraw( name )
-- Allow the weapon to override this
local ply = LocalPlayer()
if ( IsValid( ply ) ) then
local wep = ply:GetActiveWeapon()
if ( IsValid( wep ) ) then
local fShouldDraw = wep.HUDShouldDraw
if ( isfunction( fShouldDraw ) ) then
local ret = fShouldDraw( wep, name )
if ( ret != nil ) then return ret end
end
end
end
return true
end
--[[---------------------------------------------------------
Name: gamemode:HUDPaint()
Desc: Use this section to paint your HUD
-----------------------------------------------------------]]
function GM:HUDPaint()
hook.Run( "HUDDrawTargetID" )
hook.Run( "HUDDrawPickupHistory" )
hook.Run( "DrawDeathNotice", 0.85, 0.04 )
end
--[[---------------------------------------------------------
Name: gamemode:HUDPaintBackground()
Desc: Same as HUDPaint except drawn before
-----------------------------------------------------------]]
function GM:HUDPaintBackground()
end
--[[---------------------------------------------------------
Name: gamemode:GUIMouseReleased( mousecode )
Desc: The mouse was double clicked
-----------------------------------------------------------]]
function GM:GUIMouseDoublePressed( mousecode, AimVector )
-- We don't capture double clicks by default,
-- We just treat them as regular presses
GAMEMODE:GUIMousePressed( mousecode, AimVector )
end
--[[---------------------------------------------------------
Name: gamemode:ShutDown( )
Desc: Called when the Lua system is about to shut down
-----------------------------------------------------------]]
function GM:ShutDown()
end
--[[---------------------------------------------------------
Name: gamemode:RenderScreenspaceEffects( )
Desc: Bloom etc should be drawn here (or using this hook)
-----------------------------------------------------------]]
function GM:RenderScreenspaceEffects()
end
--[[---------------------------------------------------------
Name: gamemode:GetTeamColor( ent )
Desc: Return the color for this ent's team
This is for chat and deathnotice text
-----------------------------------------------------------]]
function GM:GetTeamColor( ent )
local team = TEAM_UNASSIGNED
if ( ent.Team ) then team = ent:Team() end
return GAMEMODE:GetTeamNumColor( team )
end
--[[---------------------------------------------------------
Name: gamemode:GetTeamNumColor( num )
Desc: returns the colour for this team num
-----------------------------------------------------------]]
function GM:GetTeamNumColor( num )
return team.GetColor( num )
end
--[[---------------------------------------------------------
Name: gamemode:OnPlayerChat()
Process the player's chat.. return true for no default
-----------------------------------------------------------]]
function GM:OnPlayerChat( player, strText, bTeamOnly, bPlayerIsDead )
--
-- I've made this all look more complicated than it is. Here's the easy version
--
-- chat.AddText( player, color_white, ": ", strText )
--
local tab = {}
if ( bPlayerIsDead ) then
table.insert( tab, Color( 255, 30, 40 ) )
table.insert( tab, "*DEAD* " )
end
if ( bTeamOnly ) then
table.insert( tab, Color( 30, 160, 40 ) )
table.insert( tab, "(TEAM) " )
end
if ( IsValid( player ) ) then
table.insert( tab, player )
else
table.insert( tab, "Console" )
end
local filter_context = TEXT_FILTER_GAME_CONTENT
if ( bit.band( GetConVarNumber( "cl_chatfilters" ), 64 ) != 0 ) then filter_context = TEXT_FILTER_CHAT end
table.insert( tab, color_white )
table.insert( tab, ": " .. util.FilterText( strText, filter_context, IsValid( player ) and player or nil ) )
chat.AddText( unpack( tab ) )
return true
end
--[[---------------------------------------------------------
Name: gamemode:OnChatTab( str )
Desc: Tab is pressed when typing (Auto-complete names, IRC style)
-----------------------------------------------------------]]
function GM:OnChatTab( str )
str = string.TrimRight(str)
local LastWord
for word in string.gmatch( str, "[^ ]+" ) do
LastWord = word
end
if ( LastWord == nil ) then return str end
for k, v in ipairs( player.GetAll() ) do
local nickname = v:Nick()
if ( string.len( LastWord ) < string.len( nickname ) && string.find( string.lower( nickname ), string.lower( LastWord ), 0, true ) == 1 ) then
str = string.sub( str, 1, ( string.len( LastWord ) * -1 ) - 1 )
str = str .. nickname
return str
end
end
return str
end
--[[---------------------------------------------------------
Name: gamemode:StartChat( teamsay )
Desc: Start Chat.
If you want to display your chat shit different here's what you'd do:
In StartChat show your text box and return true to hide the default
Update the text in your box with the text passed to ChatTextChanged
Close and clear your text box when FinishChat is called.
Return true in ChatText to not show the default chat text
-----------------------------------------------------------]]
function GM:StartChat( teamsay )
return false
end
--[[---------------------------------------------------------
Name: gamemode:FinishChat()
-----------------------------------------------------------]]
function GM:FinishChat()
end
--[[---------------------------------------------------------
Name: gamemode:ChatTextChanged( text)
-----------------------------------------------------------]]
function GM:ChatTextChanged( text )
end
--[[---------------------------------------------------------
Name: ChatText
Allows override of the chat text
-----------------------------------------------------------]]
function GM:ChatText( playerindex, playername, text, filter )
if ( filter == "chat" ) then
Msg( playername, ": ", text, "\n" )
else
Msg( text, "\n" )
end
return false
end
--[[---------------------------------------------------------
Name: gamemode:PostProcessPermitted( str )
Desc: return true/false depending on whether this post process should be allowed
-----------------------------------------------------------]]
function GM:PostProcessPermitted( str )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PostRenderVGUI( )
Desc: Called after VGUI has been rendered
-----------------------------------------------------------]]
function GM:PostRenderVGUI()
end
--[[---------------------------------------------------------
Name: gamemode:PreRender( )
Desc: Called before all rendering
Return true to NOT render this frame for some reason (danger!)
-----------------------------------------------------------]]
function GM:PreRender()
return false
end
--[[---------------------------------------------------------
Name: gamemode:PostRender( )
Desc: Called after all rendering
-----------------------------------------------------------]]
function GM:PostRender()
end
--[[---------------------------------------------------------
Name: gamemode:RenderScene( )
Desc: Render the scene
-----------------------------------------------------------]]
function GM:RenderScene( origin, angle, fov )
end
--[[---------------------------------------------------------
Name: CalcVehicleView
-----------------------------------------------------------]]
function GM:CalcVehicleView( Vehicle, ply, view )
if ( Vehicle.GetThirdPersonMode == nil || ply:GetViewEntity() != ply ) then
-- This shouldn't ever happen.
return
end
--
-- If we're not in third person mode - then get outa here stalker
--
if ( !Vehicle:GetThirdPersonMode() ) then return view end
-- Don't roll the camera
-- view.angles.roll = 0
local mn, mx = Vehicle:GetRenderBounds()
local radius = ( mn - mx ):Length()
local radius = radius + radius * Vehicle:GetCameraDistance()
-- Trace back from the original eye position, so we don't clip through walls/objects
local TargetOrigin = view.origin + ( view.angles:Forward() * -radius )
local WallOffset = 4
local tr = util.TraceHull( {
start = view.origin,
endpos = TargetOrigin,
filter = function( e )
local c = e:GetClass() -- Avoid contact with entities that can potentially be attached to the vehicle. Ideally, we should check if "e" is constrained to "Vehicle".
return !c:StartsWith( "prop_physics" ) &&!c:StartsWith( "prop_dynamic" ) && !c:StartsWith( "phys_bone_follower" ) && !c:StartsWith( "prop_ragdoll" ) && !e:IsVehicle() && !c:StartsWith( "gmod_" )
end,
mins = Vector( -WallOffset, -WallOffset, -WallOffset ),
maxs = Vector( WallOffset, WallOffset, WallOffset ),
} )
view.origin = tr.HitPos
view.drawviewer = true
--
-- If the trace hit something, put the camera there.
--
if ( tr.Hit && !tr.StartSolid) then
view.origin = view.origin + tr.HitNormal * WallOffset
end
return view
end
--[[---------------------------------------------------------
Name: CalcView
Allows override of the default view
-----------------------------------------------------------]]
function GM:CalcView( ply, origin, angles, fov, znear, zfar )
local Vehicle = ply:GetVehicle()
local Weapon = ply:GetActiveWeapon()
local view = {
["origin"] = origin,
["angles"] = angles,
["fov"] = fov,
["znear"] = znear,
["zfar"] = zfar,
["drawviewer"] = false,
}
--
-- Let the vehicle override the view and allows the vehicle view to be hooked
--
if ( IsValid( Vehicle ) ) then return hook.Run( "CalcVehicleView", Vehicle, ply, view ) end
--
-- Let drive possibly alter the view
--
if ( drive.CalcView( ply, view ) ) then return view end
--
-- Give the player manager a turn at altering the view
--
player_manager.RunClass( ply, "CalcView", view )
-- Give the active weapon a go at changing the view
if ( IsValid( Weapon ) ) then
local func = Weapon.CalcView
if ( func ) then
local origin, angles, fov = func( Weapon, ply, Vector( view.origin ), Angle( view.angles ), view.fov ) -- Note: Constructor to copy the object so the child function can't edit it.
view.origin, view.angles, view.fov = origin or view.origin, angles or view.angles, fov or view.fov
end
end
return view
end
--
-- If return true: Will draw the local player
-- If return false: Won't draw the local player
-- If return nil: Will carry out default action
--
function GM:ShouldDrawLocalPlayer( ply )
return player_manager.RunClass( ply, "ShouldDrawLocal" )
end
--[[---------------------------------------------------------
Name: gamemode:AdjustMouseSensitivity()
Desc: Allows you to adjust the mouse sensitivity.
The return is a fraction of the normal sensitivity (0.5 would be half as sensitive)
Return -1 to not override.
-----------------------------------------------------------]]
function GM:AdjustMouseSensitivity( fDefault )
local ply = LocalPlayer()
if ( !IsValid( ply ) ) then return -1 end
local wep = ply:GetActiveWeapon()
if ( wep && wep.AdjustMouseSensitivity ) then
return wep:AdjustMouseSensitivity()
end
return -1
end
--[[---------------------------------------------------------
Name: gamemode:ForceDermaSkin()
Desc: Return the name of skin this gamemode should use.
If nil is returned the skin will use default
-----------------------------------------------------------]]
function GM:ForceDermaSkin()
--return "example"
return nil
end
--[[---------------------------------------------------------
Name: gamemode:PostPlayerDraw()
Desc: The player has just been drawn.
-----------------------------------------------------------]]
function GM:PostPlayerDraw( ply )
end
--[[---------------------------------------------------------
Name: gamemode:PrePlayerDraw()
Desc: The player is just about to be drawn.
-----------------------------------------------------------]]
function GM:PrePlayerDraw( ply )
end
--[[---------------------------------------------------------
Name: gamemode:GetMotionBlurSettings()
Desc: Allows you to edit the motion blur values
-----------------------------------------------------------]]
function GM:GetMotionBlurValues( x, y, fwd, spin )
-- fwd = 0.5 + math.sin( CurTime() * 5 ) * 0.5
return x, y, fwd, spin
end
--[[---------------------------------------------------------
Name: gamemode:InputMouseApply()
Desc: Allows you to control how moving the mouse affects the view angles
-----------------------------------------------------------]]
function GM:InputMouseApply( cmd, x, y, angle )
--angle.roll = angle.roll + 1
--cmd:SetViewAngles( Ang )
--return true
end
--[[---------------------------------------------------------
Name: gamemode:OnAchievementAchieved()
-----------------------------------------------------------]]
function GM:OnAchievementAchieved( ply, achid )
chat.AddText( ply, Color( 230, 230, 230 ), " earned the achievement ", Color( 255, 200, 0 ), achievements.GetName( achid ) )
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawSkyBox()
Desc: Called before drawing the skybox. Return true to not draw the skybox.
-----------------------------------------------------------]]
function GM:PreDrawSkyBox()
--return true
end
--[[---------------------------------------------------------
Name: gamemode:PostDrawSkyBox()
Desc: Called after drawing the skybox
-----------------------------------------------------------]]
function GM:PostDrawSkyBox()
end
--
-- Name: GM:PostDraw2DSkyBox
-- Desc: Called right after the 2D skybox has been drawn - allowing you to draw over it.
-- Arg1:
-- Ret1:
--
function GM:PostDraw2DSkyBox()
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawOpaqueRenderables()
Desc: Called before drawing opaque entities
-----------------------------------------------------------]]
function GM:PreDrawOpaqueRenderables( bDrawingDepth, bDrawingSkybox )
-- return true
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawOpaqueRenderables()
Desc: Called before drawing opaque entities
-----------------------------------------------------------]]
function GM:PostDrawOpaqueRenderables( bDrawingDepth, bDrawingSkybox )
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawOpaqueRenderables()
Desc: Called before drawing opaque entities
-----------------------------------------------------------]]
function GM:PreDrawTranslucentRenderables( bDrawingDepth, bDrawingSkybox )
-- return true
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawOpaqueRenderables()
Desc: Called before drawing opaque entities
-----------------------------------------------------------]]
function GM:PostDrawTranslucentRenderables( bDrawingDepth, bDrawingSkybox )
end
--[[---------------------------------------------------------
Name: gamemode:CalcViewModelView()
Desc: Called to set the view model's position
-----------------------------------------------------------]]
function GM:CalcViewModelView( Weapon, ViewModel, OldEyePos, OldEyeAng, EyePos, EyeAng )
if ( !IsValid( Weapon ) ) then return end
local vm_origin, vm_angles = EyePos, EyeAng
-- Controls the position of all viewmodels
local func = Weapon.GetViewModelPosition
if ( func ) then
local pos, ang = func( Weapon, EyePos*1, EyeAng*1 )
vm_origin = pos or vm_origin
vm_angles = ang or vm_angles
end
-- Controls the position of individual viewmodels
func = Weapon.CalcViewModelView
if ( func ) then
local pos, ang = func( Weapon, ViewModel, OldEyePos*1, OldEyeAng*1, EyePos*1, EyeAng*1 )
vm_origin = pos or vm_origin
vm_angles = ang or vm_angles
end
return vm_origin, vm_angles
end
--[[---------------------------------------------------------
Name: gamemode:PreDrawViewModel()
Desc: Called before drawing the view model
-----------------------------------------------------------]]
function GM:PreDrawViewModel( ViewModel, Player, Weapon )
if ( !IsValid( Weapon ) ) then return false end
player_manager.RunClass( Player, "PreDrawViewModel", ViewModel, Weapon )
if ( Weapon.PreDrawViewModel == nil ) then return false end
return Weapon:PreDrawViewModel( ViewModel, Weapon, Player )
end
--[[---------------------------------------------------------
Name: gamemode:PostDrawViewModel()
Desc: Called after drawing the view model
-----------------------------------------------------------]]
function GM:PostDrawViewModel( ViewModel, Player, Weapon )
if ( !IsValid( Weapon ) ) then return false end
if ( Weapon.UseHands || !Weapon:IsScripted() ) then
local hands = Player:GetHands()
if ( IsValid( hands ) && IsValid( hands:GetParent() ) ) then
if ( not hook.Call( "PreDrawPlayerHands", self, hands, ViewModel, Player, Weapon ) ) then
if ( Weapon.ViewModelFlip ) then render.CullMode( MATERIAL_CULLMODE_CW ) end
hands:DrawModel()
render.CullMode( MATERIAL_CULLMODE_CCW )
end
hook.Call( "PostDrawPlayerHands", self, hands, ViewModel, Player, Weapon )
end
end
player_manager.RunClass( Player, "PostDrawViewModel", ViewModel, Weapon )
if ( Weapon.PostDrawViewModel == nil ) then return false end
return Weapon:PostDrawViewModel( ViewModel, Weapon, Player )
end
--[[---------------------------------------------------------
Name: gamemode:DrawPhysgunBeam()
Desc: Return false to override completely
-----------------------------------------------------------]]
function GM:DrawPhysgunBeam( ply, weapon, bOn, target, boneid, pos )
-- Do nothing
return true
end
--[[---------------------------------------------------------
Name: gamemode:NetworkEntityCreated()
Desc: Entity is created over the network
-----------------------------------------------------------]]
function GM:NetworkEntityCreated( ent )
end
--[[---------------------------------------------------------
Name: gamemode:CreateMove( command )
Desc: Allows the client to change the move commands
before it's send to the server
-----------------------------------------------------------]]
function GM:CreateMove( cmd )
if ( drive.CreateMove( cmd ) ) then return true end
if ( player_manager.RunClass( LocalPlayer(), "CreateMove", cmd ) ) then return true end
end
--[[---------------------------------------------------------
Name: gamemode:PreventScreenClicks()
Desc: The player is hovering over a ScreenClickable world
-----------------------------------------------------------]]
function GM:PreventScreenClicks( cmd )
--
-- Returning true in this hook will prevent screen clicking sending IN_ATTACK
-- commands to the weapons. We want to do this in the properties system, so
-- that you don't fire guns when opening the properties menu. Holla!
--
return false
end
--[[---------------------------------------------------------
Name: gamemode:GUIMousePressed( mousecode )
Desc: The mouse has been pressed on the game screen
-----------------------------------------------------------]]
function GM:GUIMousePressed( mousecode, AimVector )
end
--[[---------------------------------------------------------
Name: gamemode:GUIMouseReleased( mousecode )
Desc: The mouse has been released on the game screen
-----------------------------------------------------------]]
function GM:GUIMouseReleased( mousecode, AimVector )
end
--[[---------------------------------------------------------
Player class has been changed
-----------------------------------------------------------]]
function GM:PlayerClassChanged( ply, newID )
-- No class is set
if ( newID < 1 ) then return end
-- Invalid class ID?
local classname = util.NetworkIDToString( newID )
if ( !classname ) then return end
-- Initialize the class on client
player_manager.SetPlayerClass( ply, classname )
end
function GM:PreDrawHUD()
end
function GM:PostDrawHUD()
end
function GM:DrawOverlay()
end
function GM:DrawMonitors()
end
function GM:PreDrawEffects()
end
function GM:PostDrawEffects()
end
function GM:PreDrawHalos()
end
function GM:CloseDermaMenus()
end
function GM:CreateClientsideRagdoll( entity, ragdoll )
end
function GM:VehicleMove( ply, vehicle, mv )
end

View File

@@ -0,0 +1,75 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Name: gamemode:ShowTeam()
Desc:
-----------------------------------------------------------]]
function GM:ShowTeam()
if ( IsValid( self.TeamSelectFrame ) ) then return end
-- Simple team selection box
self.TeamSelectFrame = vgui.Create( "DFrame" )
self.TeamSelectFrame:SetTitle( "Pick Team" )
local AllTeams = team.GetAllTeams()
local y = 30
for ID, TeamInfo in pairs ( AllTeams ) do
if ( ID != TEAM_CONNECTING && ID != TEAM_UNASSIGNED ) then
local Team = vgui.Create( "DButton", self.TeamSelectFrame )
function Team.DoClick() self:HideTeam() RunConsoleCommand( "changeteam", ID ) end
Team:SetPos( 10, y )
Team:SetSize( 130, 20 )
Team:SetText( TeamInfo.Name )
if ( IsValid( LocalPlayer() ) && LocalPlayer():Team() == ID ) then
Team:SetEnabled( false )
end
y = y + 30
end
end
if ( GAMEMODE.AllowAutoTeam ) then
local Team = vgui.Create( "DButton", self.TeamSelectFrame )
function Team.DoClick() self:HideTeam() RunConsoleCommand( "autoteam" ) end
Team:SetPos( 10, y )
Team:SetSize( 130, 20 )
Team:SetText( "Auto" )
y = y + 30
end
self.TeamSelectFrame:SetSize( 150, y )
self.TeamSelectFrame:Center()
self.TeamSelectFrame:MakePopup()
self.TeamSelectFrame:SetKeyboardInputEnabled( false )
end
--[[---------------------------------------------------------
Name: gamemode:HideTeam()
Desc:
-----------------------------------------------------------]]
function GM:HideTeam()
if ( IsValid(self.TeamSelectFrame) ) then
self.TeamSelectFrame:Remove()
self.TeamSelectFrame = nil
end
end

View File

@@ -0,0 +1,305 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
surface.CreateFont( "ScoreboardDefault", {
font = "Helvetica",
size = 22,
weight = 800
} )
surface.CreateFont( "ScoreboardDefaultTitle", {
font = "Helvetica",
size = 32,
weight = 800
} )
--
-- This defines a new panel type for the player row. The player row is given a player
-- and then from that point on it pretty much looks after itself. It updates player info
-- in the think function, and removes itself when the player leaves the server.
--
local PLAYER_LINE = {
Init = function( self )
self.AvatarButton = self:Add( "DButton" )
self.AvatarButton:Dock( LEFT )
self.AvatarButton:SetSize( 32, 32 )
self.AvatarButton.DoClick = function() self.Player:ShowProfile() end
self.Avatar = vgui.Create( "AvatarImage", self.AvatarButton )
self.Avatar:SetSize( 32, 32 )
self.Avatar:SetMouseInputEnabled( false )
self.Name = self:Add( "DLabel" )
self.Name:Dock( FILL )
self.Name:SetFont( "ScoreboardDefault" )
self.Name:SetTextColor( Color( 93, 93, 93 ) )
self.Name:DockMargin( 8, 0, 0, 0 )
self.Mute = self:Add( "DImageButton" )
self.Mute:SetSize( 32, 32 )
self.Mute:Dock( RIGHT )
self.Ping = self:Add( "DLabel" )
self.Ping:Dock( RIGHT )
self.Ping:SetWidth( 50 )
self.Ping:SetFont( "ScoreboardDefault" )
self.Ping:SetTextColor( Color( 93, 93, 93 ) )
self.Ping:SetContentAlignment( 5 )
self.Deaths = self:Add( "DLabel" )
self.Deaths:Dock( RIGHT )
self.Deaths:SetWidth( 50 )
self.Deaths:SetFont( "ScoreboardDefault" )
self.Deaths:SetTextColor( Color( 93, 93, 93 ) )
self.Deaths:SetContentAlignment( 5 )
self.Kills = self:Add( "DLabel" )
self.Kills:Dock( RIGHT )
self.Kills:SetWidth( 50 )
self.Kills:SetFont( "ScoreboardDefault" )
self.Kills:SetTextColor( Color( 93, 93, 93 ) )
self.Kills:SetContentAlignment( 5 )
self:Dock( TOP )
self:DockPadding( 3, 3, 3, 3 )
self:SetHeight( 32 + 3 * 2 )
self:DockMargin( 2, 0, 2, 2 )
end,
Setup = function( self, pl )
self.Player = pl
self.Avatar:SetPlayer( pl )
self:Think( self )
--local friend = self.Player:GetFriendStatus()
--MsgN( pl, " Friend: ", friend )
end,
Think = function( self )
if ( !IsValid( self.Player ) ) then
self:SetZPos( 9999 ) -- Causes a rebuild
self:Remove()
return
end
if ( self.PName == nil || self.PName != self.Player:Nick() ) then
self.PName = self.Player:Nick()
self.Name:SetText( self.PName )
end
if ( self.NumKills == nil || self.NumKills != self.Player:Frags() ) then
self.NumKills = self.Player:Frags()
self.Kills:SetText( self.NumKills )
end
if ( self.NumDeaths == nil || self.NumDeaths != self.Player:Deaths() ) then
self.NumDeaths = self.Player:Deaths()
self.Deaths:SetText( self.NumDeaths )
end
if ( self.NumPing == nil || self.NumPing != self.Player:Ping() ) then
self.NumPing = self.Player:Ping()
self.Ping:SetText( self.NumPing )
end
--
-- Change the icon of the mute button based on state
--
if ( self.Muted == nil || self.Muted != self.Player:IsMuted() ) then
self.Muted = self.Player:IsMuted()
if ( self.Muted ) then
self.Mute:SetImage( "icon32/muted.png" )
else
self.Mute:SetImage( "icon32/unmuted.png" )
end
self.Mute.DoClick = function( s ) self.Player:SetMuted( !self.Muted ) end
self.Mute.OnMouseWheeled = function( s, delta )
self.Player:SetVoiceVolumeScale( self.Player:GetVoiceVolumeScale() + ( delta / 100 * 5 ) )
s.LastTick = CurTime()
end
self.Mute.PaintOver = function( s, w, h )
if ( !IsValid( self.Player ) ) then return end
local a = 255 - math.Clamp( CurTime() - ( s.LastTick or 0 ), 0, 3 ) * 255
if ( a <= 0 ) then return end
draw.RoundedBox( 4, 0, 0, w, h, Color( 0, 0, 0, a * 0.75 ) )
draw.SimpleText( math.ceil( self.Player:GetVoiceVolumeScale() * 100 ) .. "%", "DermaDefaultBold", w / 2, h / 2, Color( 255, 255, 255, a ), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
end
end
--
-- Connecting players go at the very bottom
--
if ( self.Player:Team() == TEAM_CONNECTING ) then
self:SetZPos( 2000 + self.Player:EntIndex() )
return
end
--
-- This is what sorts the list. The panels are docked in the z order,
-- so if we set the z order according to kills they'll be ordered that way!
-- Careful though, it's a signed short internally, so needs to range between -32,768k and +32,767
--
self:SetZPos( ( self.NumKills * -50 ) + self.NumDeaths + self.Player:EntIndex() )
end,
Paint = function( self, w, h )
if ( !IsValid( self.Player ) ) then
return
end
--
-- We draw our background a different colour based on the status of the player
--
if ( self.Player:Team() == TEAM_CONNECTING ) then
draw.RoundedBox( 4, 0, 0, w, h, Color( 200, 200, 200, 200 ) )
return
end
if ( !self.Player:Alive() ) then
draw.RoundedBox( 4, 0, 0, w, h, Color( 230, 200, 200, 255 ) )
return
end
if ( self.Player:IsAdmin() ) then
draw.RoundedBox( 4, 0, 0, w, h, Color( 230, 255, 230, 255 ) )
return
end
draw.RoundedBox( 4, 0, 0, w, h, Color( 230, 230, 230, 255 ) )
end
}
--
-- Convert it from a normal table into a Panel Table based on DPanel
--
PLAYER_LINE = vgui.RegisterTable( PLAYER_LINE, "DPanel" )
--
-- Here we define a new panel table for the scoreboard. It basically consists
-- of a header and a scrollpanel - into which the player lines are placed.
--
local SCORE_BOARD = {
Init = function( self )
self.Header = self:Add( "Panel" )
self.Header:Dock( TOP )
self.Header:SetHeight( 100 )
self.Name = self.Header:Add( "DLabel" )
self.Name:SetFont( "ScoreboardDefaultTitle" )
self.Name:SetTextColor( color_white )
self.Name:Dock( TOP )
self.Name:SetHeight( 40 )
self.Name:SetContentAlignment( 5 )
self.Name:SetExpensiveShadow( 2, Color( 0, 0, 0, 200 ) )
--self.NumPlayers = self.Header:Add( "DLabel" )
--self.NumPlayers:SetFont( "ScoreboardDefault" )
--self.NumPlayers:SetTextColor( color_white )
--self.NumPlayers:SetPos( 0, 100 - 30 )
--self.NumPlayers:SetSize( 300, 30 )
--self.NumPlayers:SetContentAlignment( 4 )
self.Scores = self:Add( "DScrollPanel" )
self.Scores:Dock( FILL )
end,
PerformLayout = function( self )
self:SetSize( 700, ScrH() - 200 )
self:SetPos( ScrW() / 2 - 350, 100 )
end,
Paint = function( self, w, h )
--draw.RoundedBox( 4, 0, 0, w, h, Color( 0, 0, 0, 200 ) )
end,
Think = function( self, w, h )
self.Name:SetText( GetHostName() )
--
-- Loop through each player, and if one doesn't have a score entry - create it.
--
for id, pl in ipairs( player.GetAll() ) do
if ( IsValid( pl.ScoreEntry ) ) then continue end
pl.ScoreEntry = vgui.CreateFromTable( PLAYER_LINE, pl.ScoreEntry )
pl.ScoreEntry:Setup( pl )
self.Scores:AddItem( pl.ScoreEntry )
end
end
}
SCORE_BOARD = vgui.RegisterTable( SCORE_BOARD, "EditablePanel" )
--[[---------------------------------------------------------
Name: gamemode:ScoreboardShow( )
Desc: Sets the scoreboard to visible
-----------------------------------------------------------]]
function GM:ScoreboardShow()
if ( !IsValid( g_Scoreboard ) ) then
g_Scoreboard = vgui.CreateFromTable( SCORE_BOARD )
end
if ( IsValid( g_Scoreboard ) ) then
g_Scoreboard:Show()
g_Scoreboard:MakePopup()
g_Scoreboard:SetKeyboardInputEnabled( false )
end
end
--[[---------------------------------------------------------
Name: gamemode:ScoreboardHide( )
Desc: Hides the scoreboard
-----------------------------------------------------------]]
function GM:ScoreboardHide()
if ( IsValid( g_Scoreboard ) ) then
g_Scoreboard:Hide()
end
end
--[[---------------------------------------------------------
Name: gamemode:HUDDrawScoreBoard( )
Desc: If you prefer to draw your scoreboard the stupid way (without vgui)
-----------------------------------------------------------]]
function GM:HUDDrawScoreBoard()
end

View File

@@ -0,0 +1,46 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Spawn Menu
-----------------------------------------------------------]]
function GM:OnSpawnMenuOpen()
end
function GM:OnSpawnMenuClose()
end
concommand.Add( "+menu", function()
hook.Run( "OnSpawnMenuOpen" )
end, nil, "Opens the spawnmenu", FCVAR_DONTRECORD )
concommand.Add( "-menu", function()
if ( input.IsKeyTrapping() ) then return end
hook.Run( "OnSpawnMenuClose" )
end, nil, "Closes the spawnmenu", FCVAR_DONTRECORD )
--[[---------------------------------------------------------
Context Menu
-----------------------------------------------------------]]
function GM:OnContextMenuOpen()
end
function GM:OnContextMenuClose()
end
concommand.Add( "+menu_context", function()
hook.Run( "OnContextMenuOpen" )
end, nil, "Opens the context menu", FCVAR_DONTRECORD )
concommand.Add( "-menu_context", function()
if ( input.IsKeyTrapping() ) then return end
hook.Run( "OnContextMenuClose" )
end, nil, "Closes the context menu", FCVAR_DONTRECORD )

View File

@@ -0,0 +1,70 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Name: gamemode:HUDDrawTargetID( )
Desc: Draw the target id (the name of the player you're currently looking at)
-----------------------------------------------------------]]
function GM:HUDDrawTargetID()
local tr = util.GetPlayerTrace( LocalPlayer() )
local trace = util.TraceLine( tr )
if ( !trace.Hit ) then return end
if ( !trace.HitNonWorld ) then return end
local text = "ERROR"
local font = "TargetID"
if ( trace.Entity:IsPlayer() ) then
text = trace.Entity:Nick()
else
--text = trace.Entity:GetClass()
return
end
surface.SetFont( font )
local w, h = surface.GetTextSize( text )
local MouseX, MouseY = input.GetCursorPos()
if ( MouseX == 0 && MouseY == 0 || !vgui.CursorVisible() ) then
MouseX = ScrW() / 2
MouseY = ScrH() / 2
end
local x = MouseX
local y = MouseY
x = x - w / 2
y = y + 30
-- The fonts internal drop shadow looks lousy with AA on
draw.SimpleText( text, font, x + 1, y + 1, Color( 0, 0, 0, 120 ) )
draw.SimpleText( text, font, x + 2, y + 2, Color( 0, 0, 0, 50 ) )
draw.SimpleText( text, font, x, y, self:GetTeamColor( trace.Entity ) )
y = y + h + 5
-- Draw the health
text = trace.Entity:Health() .. "%"
font = "TargetIDSmall"
surface.SetFont( font )
w, h = surface.GetTextSize( text )
x = MouseX - w / 2
draw.SimpleText( text, font, x + 1, y + 1, Color( 0, 0, 0, 120 ) )
draw.SimpleText( text, font, x + 2, y + 2, Color( 0, 0, 0, 50 ) )
draw.SimpleText( text, font, x, y, self:GetTeamColor( trace.Entity ) )
end

View File

@@ -0,0 +1,154 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
local PlayerVoicePanels = {}
function PANEL:Init()
self.LabelName = vgui.Create( "DLabel", self )
self.LabelName:SetFont( "GModNotify" )
self.LabelName:Dock( FILL )
self.LabelName:DockMargin( 8, 0, 0, 0 )
self.LabelName:SetTextColor( color_white )
self.Avatar = vgui.Create( "AvatarImage", self )
self.Avatar:Dock( LEFT )
self.Avatar:SetSize( 32, 32 )
self.Color = color_transparent
self:SetSize( 250, 32 + 8 )
self:DockPadding( 4, 4, 4, 4 )
self:DockMargin( 2, 2, 2, 2 )
self:Dock( BOTTOM )
end
function PANEL:Setup( ply )
self.ply = ply
self.LabelName:SetText( ply:Nick() )
self.Avatar:SetPlayer( ply )
self.Color = team.GetColor( ply:Team() )
self:InvalidateLayout()
end
function PANEL:Paint( w, h )
if ( !IsValid( self.ply ) ) then return end
draw.RoundedBox( 4, 0, 0, w, h, Color( 0, self.ply:VoiceVolume() * 255, 0, 240 ) )
end
function PANEL:Think()
if ( IsValid( self.ply ) ) then
self.LabelName:SetText( self.ply:Nick() )
end
if ( self.fadeAnim ) then
self.fadeAnim:Run()
end
end
function PANEL:FadeOut( anim, delta, data )
if ( anim.Finished ) then
if ( IsValid( PlayerVoicePanels[ self.ply ] ) ) then
PlayerVoicePanels[ self.ply ]:Remove()
PlayerVoicePanels[ self.ply ] = nil
return
end
return end
self:SetAlpha( 255 - ( 255 * delta ) )
end
derma.DefineControl( "VoiceNotify", "", PANEL, "DPanel" )
function GM:PlayerStartVoice( ply )
if ( !IsValid( g_VoicePanelList ) ) then return end
-- There'd be an exta one if voice_loopback is on, so remove it.
GAMEMODE:PlayerEndVoice( ply )
if ( IsValid( PlayerVoicePanels[ ply ] ) ) then
if ( PlayerVoicePanels[ ply ].fadeAnim ) then
PlayerVoicePanels[ ply ].fadeAnim:Stop()
PlayerVoicePanels[ ply ].fadeAnim = nil
end
PlayerVoicePanels[ ply ]:SetAlpha( 255 )
return
end
if ( !IsValid( ply ) ) then return end
local pnl = g_VoicePanelList:Add( "VoiceNotify" )
pnl:Setup( ply )
PlayerVoicePanels[ ply ] = pnl
end
local function VoiceClean()
for k, v in pairs( PlayerVoicePanels ) do
if ( !IsValid( k ) ) then
GAMEMODE:PlayerEndVoice( k )
end
end
end
timer.Create( "VoiceClean", 10, 0, VoiceClean )
function GM:PlayerEndVoice( ply )
if ( IsValid( PlayerVoicePanels[ ply ] ) ) then
if ( PlayerVoicePanels[ ply ].fadeAnim ) then return end
PlayerVoicePanels[ ply ].fadeAnim = Derma_Anim( "FadeOut", PlayerVoicePanels[ ply ], PlayerVoicePanels[ ply ].FadeOut )
PlayerVoicePanels[ ply ].fadeAnim:Start( 2 )
end
end
local function CreateVoiceVGUI()
g_VoicePanelList = vgui.Create( "DPanel" )
g_VoicePanelList:ParentToHUD()
g_VoicePanelList:SetPos( ScrW() - 300, 100 )
g_VoicePanelList:SetSize( 250, ScrH() - 200 )
g_VoicePanelList:SetPaintBackground( false )
end
hook.Add( "InitPostEntity", "CreateVoiceVGUI", CreateVoiceVGUI )

View File

@@ -0,0 +1,46 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Name: gamemode:GravGunPunt()
Desc: We're about to punt an entity (primary fire).
Return true if we're allowed to.
-----------------------------------------------------------]]
function GM:GravGunPunt( ply, ent )
return true
end
--[[---------------------------------------------------------
Name: gamemode:GravGunPickupAllowed()
Desc: Return true if we're allowed to pickup entity
-----------------------------------------------------------]]
function GM:GravGunPickupAllowed( ply, ent )
return true
end
if ( SERVER ) then
--[[---------------------------------------------------------
Name: gamemode:GravGunOnPickedUp()
Desc: The entity has been picked up
-----------------------------------------------------------]]
function GM:GravGunOnPickedUp( ply, ent )
end
--[[---------------------------------------------------------
Name: gamemode:GravGunOnDropped()
Desc: The entity has been dropped
-----------------------------------------------------------]]
function GM:GravGunOnDropped( ply, ent )
end
end

View File

@@ -0,0 +1,190 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include( 'shared.lua' )
include( 'player.lua' )
include( 'npc.lua' )
include( 'variable_edit.lua' )
--[[---------------------------------------------------------
Name: gamemode:Initialize()
Desc: Called immediately after starting the gamemode
-----------------------------------------------------------]]
function GM:Initialize()
end
--[[---------------------------------------------------------
Name: gamemode:InitPostEntity()
Desc: Called as soon as all map entities have been spawned
-----------------------------------------------------------]]
function GM:InitPostEntity()
end
--[[---------------------------------------------------------
Name: gamemode:Think()
Desc: Called every frame
-----------------------------------------------------------]]
function GM:Think()
end
--[[---------------------------------------------------------
Name: gamemode:ShutDown()
Desc: Called when the Lua system is about to shut down
-----------------------------------------------------------]]
function GM:ShutDown()
end
--[[---------------------------------------------------------
Name: gamemode:DoPlayerDeath( )
Desc: Carries out actions when the player dies
-----------------------------------------------------------]]
function GM:DoPlayerDeath( ply, attacker, dmginfo )
if ( !dmginfo:IsDamageType( DMG_REMOVENORAGDOLL ) ) then
ply:CreateRagdoll()
end
ply:AddDeaths( 1 )
if ( attacker:IsValid() && attacker:IsPlayer() ) then
if ( attacker == ply ) then
attacker:AddFrags( -1 )
else
attacker:AddFrags( 1 )
end
end
end
--[[---------------------------------------------------------
Name: gamemode:PlayerShouldTakeDamage
Return true if this player should take damage from this attacker
-----------------------------------------------------------]]
function GM:PlayerShouldTakeDamage( ply, attacker )
return true
end
--[[---------------------------------------------------------
Name: gamemode:EntityTakeDamage( ent, info )
Desc: The entity has received damage
-----------------------------------------------------------]]
function GM:EntityTakeDamage( ent, info )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerHurt( )
Desc: Called when a player is hurt.
-----------------------------------------------------------]]
function GM:PlayerHurt( player, attacker, healthleft, healthtaken )
end
--[[---------------------------------------------------------
Name: gamemode:CreateEntityRagdoll( entity, ragdoll )
Desc: A ragdoll of an entity has been created
-----------------------------------------------------------]]
function GM:CreateEntityRagdoll( entity, ragdoll )
end
-- Set the ServerName every 30 seconds in case it changes..
-- This is for backwards compatibility only - client can now use GetHostName()
local function HostnameThink()
SetGlobalString( "ServerName", GetHostName() )
end
timer.Create( "HostnameThink", 30, 0, HostnameThink )
--[[---------------------------------------------------------
Show the default team selection screen
-----------------------------------------------------------]]
function GM:ShowTeam( ply )
if ( !GAMEMODE.TeamBased ) then return end
local TimeBetweenSwitches = GAMEMODE.SecondsBetweenTeamSwitches or 10
if ( ply.LastTeamSwitch && RealTime() - ply.LastTeamSwitch < TimeBetweenSwitches ) then
ply.LastTeamSwitch = ply.LastTeamSwitch + 1
ply:ChatPrint( Format( "Please wait %i more seconds before trying to change team again", ( TimeBetweenSwitches - ( RealTime() - ply.LastTeamSwitch ) ) + 1 ) )
return
end
-- For clientside see cl_pickteam.lua
ply:SendLua( "GAMEMODE:ShowTeam()" )
end
--
-- CheckPassword( steamid, networkid, server_password, password, name )
--
-- Called every time a non-localhost player joins the server. steamid is their 64bit
-- steamid. Return false and a reason to reject their join. Return true to allow
-- them to join.
--
function GM:CheckPassword( steamid, networkid, server_password, password, name )
-- The server has sv_password set
if ( server_password != "" ) then
-- The joining clients password doesn't match sv_password
if ( server_password != password ) then
return false
end
end
--
-- Returning true means they're allowed to join the server
--
return true
end
--[[---------------------------------------------------------
Name: gamemode:FinishMove( player, movedata )
-----------------------------------------------------------]]
function GM:VehicleMove( ply, vehicle, mv )
--
-- On duck toggle third person view
--
if ( mv:KeyPressed( IN_DUCK ) && vehicle.SetThirdPersonMode ) then
vehicle:SetThirdPersonMode( !vehicle:GetThirdPersonMode() )
end
--
-- Adjust the camera distance with the mouse wheel
--
local iWheel = ply:GetCurrentCommand():GetMouseWheel()
if ( iWheel != 0 && vehicle.SetCameraDistance ) then
-- The distance is a multiplier
-- Actual camera distance = ( renderradius + renderradius * dist )
-- so -1 will be zero.. clamp it there.
local newdist = math.Clamp( vehicle:GetCameraDistance() - iWheel * 0.03 * ( 1.1 + vehicle:GetCameraDistance() ), -1, 10 )
vehicle:SetCameraDistance( newdist )
end
end
--[[---------------------------------------------------------
Name: gamemode:PreUndo( undo )
-----------------------------------------------------------]]
function GM:PreUndo( undo )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PreUndo( undo )
-----------------------------------------------------------]]
function GM:PostUndo( undo, count )
end

View File

@@ -0,0 +1,211 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Backwards compatibility with addons
util.AddNetworkString( "PlayerKilledNPC" )
util.AddNetworkString( "NPCKilledNPC" )
util.AddNetworkString( "PlayerKilled" )
util.AddNetworkString( "PlayerKilledSelf" )
util.AddNetworkString( "PlayerKilledByPlayer" )
-- New way
util.AddNetworkString( "DeathNoticeEvent" )
DEATH_NOTICE_FRIENDLY_VICTIM = 1
DEATH_NOTICE_FRIENDLY_ATTACKER = 2
--DEATH_NOTICE_HEADSHOT = 4
--DEATH_NOTICE_PENETRATION = 8
function GM:SendDeathNotice( attacker, inflictor, victim, flags )
net.Start( "DeathNoticeEvent" )
if ( !attacker ) then
net.WriteUInt( 0, 2 )
elseif ( isstring( attacker ) ) then
net.WriteUInt( 1, 2 )
net.WriteString( attacker )
elseif ( IsValid( attacker ) ) then
net.WriteUInt( 2, 2 )
net.WriteEntity( attacker )
end
net.WriteString( inflictor )
if ( !victim ) then
net.WriteUInt( 0, 2 )
elseif ( isstring( victim ) ) then
net.WriteUInt( 1, 2 )
net.WriteString( victim )
elseif ( IsValid( victim ) ) then
net.WriteUInt( 2, 2 )
net.WriteEntity( victim )
end
net.WriteUInt( flags, 8 )
net.Broadcast()
end
function GM:GetDeathNoticeEntityName( ent )
-- Some specific HL2 NPCs, just for fun
-- TODO: Localization strings?
if ( ent:GetClass() == "npc_citizen" ) then
if ( ent:GetName() == "griggs" ) then return "Griggs" end
if ( ent:GetName() == "sheckley" ) then return "Sheckley" end
if ( ent:GetName() == "tobias" ) then return "Laszlo" end
if ( ent:GetName() == "stanley" ) then return "Sandy" end
end
-- Custom vehicle and NPC names from spawnmenu
if ( ent:IsVehicle() and ent.VehicleTable and ent.VehicleTable.Name ) then
return ent.VehicleTable.Name
end
if ( ent:IsNPC() and ent.NPCTable and ent.NPCTable.Name ) then
return ent.NPCTable.Name
end
-- Map spawned Odessa or Rebels, etc..
for unique_class, NPC in pairs( list.Get( "NPC" ) ) do
if ( unique_class == NPC.Class or ent:GetClass() != NPC.Class ) then continue end
local allGood = true
if ( NPC.Model and ent:GetModel() != NPC.Model ) then
allGood = false
end
if ( NPC.Skin and ent:GetSkin() != NPC.Skin ) then
allGood = false
end
-- For Rebels, etc.
if ( NPC.KeyValues ) then
for k, v in pairs( NPC.KeyValues ) do
local kL = k:lower()
if ( kL != "squadname" and kL != "numgrenades" and ent:GetInternalVariable( k ) != v ) then
allGood = false
break
end
end
-- They get unset often :(
--if ( NPC.SpawnFlags and ent:HasSpawnFlags( NPC.SpawnFlags ) ) then allGood = false end
end
-- Medics, ew..
if ( unique_class == "Medic" and !ent:HasSpawnFlags( SF_CITIZEN_MEDIC ) ) then allGood = false end
if ( unique_class == "Rebel" and ent:HasSpawnFlags( SF_CITIZEN_MEDIC ) ) then allGood = false end
if ( allGood ) then return NPC.Name end
end
-- Unfortunately the code above still doesn't work for Antlion Workers, because they change their classname..
if ( ent:GetClass() == "npc_antlion" and ent:GetModel() == "models/antlion_worker.mdl" ) then
return list.Get( "NPC" )[ "npc_antlion_worker" ].Name
end
-- Fallback to old behavior
return "#" .. ent:GetClass()
end
--[[---------------------------------------------------------
Name: gamemode:OnNPCKilled( entity, attacker, inflictor )
Desc: The NPC has died
-----------------------------------------------------------]]
function GM:OnNPCKilled( ent, attacker, inflictor )
-- Don't spam the killfeed with scripted stuff
if ( ent:GetClass() == "npc_bullseye" or ent:GetClass() == "npc_launcher" ) then return end
-- If killed by trigger_hurt, act as if NPC killed itself
if ( IsValid( attacker ) and attacker:GetClass() == "trigger_hurt" ) then attacker = ent end
-- NPC got run over..
if ( IsValid( attacker ) and attacker:IsVehicle() and IsValid( attacker:GetDriver() ) ) then
attacker = attacker:GetDriver()
end
if ( !IsValid( inflictor ) and IsValid( attacker ) ) then
inflictor = attacker
end
-- Convert the inflictor to the weapon that they're holding if we can.
if ( IsValid( inflictor ) and attacker == inflictor and ( inflictor:IsPlayer() or inflictor:IsNPC() ) ) then
inflictor = inflictor:GetActiveWeapon()
if ( !IsValid( attacker ) ) then inflictor = attacker end
end
local InflictorClass = "worldspawn"
local AttackerClass = game.GetWorld()
if ( IsValid( inflictor ) ) then InflictorClass = inflictor:GetClass() end
if ( IsValid( attacker ) ) then
AttackerClass = attacker
-- If there is no valid inflictor, use the attacker (i.e. manhacks)
if ( !IsValid( inflictor ) ) then InflictorClass = attacker:GetClass() end
if ( attacker:IsPlayer() ) then
local flags = 0
if ( ent:IsNPC() and ent:Disposition( attacker ) != D_HT ) then flags = flags + DEATH_NOTICE_FRIENDLY_VICTIM end
self:SendDeathNotice( attacker, InflictorClass, self:GetDeathNoticeEntityName( ent ), flags )
return
end
end
-- Floor turret got knocked over
if ( ent:GetClass() == "npc_turret_floor" ) then AttackerClass = ent end
-- It was NPC suicide..
if ( ent == AttackerClass ) then InflictorClass = "suicide" end
local flags = 0
if ( IsValid( Entity( 1 ) ) and ent:IsNPC() and ent:Disposition( Entity( 1 ) ) == D_LI ) then flags = flags + DEATH_NOTICE_FRIENDLY_VICTIM end
if ( IsValid( Entity( 1 ) ) and AttackerClass:IsNPC() and AttackerClass:Disposition( Entity( 1 ) ) == D_LI ) then flags = flags + DEATH_NOTICE_FRIENDLY_ATTACKER end
self:SendDeathNotice( self:GetDeathNoticeEntityName( AttackerClass ), InflictorClass, self:GetDeathNoticeEntityName( ent ), flags )
end
--[[---------------------------------------------------------
Name: gamemode:ScaleNPCDamage( ply, hitgroup, dmginfo )
Desc: Scale the damage based on being shot in a hitbox
-----------------------------------------------------------]]
function GM:ScaleNPCDamage( npc, hitgroup, dmginfo )
-- More damage if we're shot in the head
if ( hitgroup == HITGROUP_HEAD ) then
dmginfo:ScaleDamage( 2 )
end
-- Less damage if we're shot in the arms or legs
if ( hitgroup == HITGROUP_LEFTARM or
hitgroup == HITGROUP_RIGHTARM or
hitgroup == HITGROUP_LEFTLEG or
hitgroup == HITGROUP_RIGHTLEG or
hitgroup == HITGROUP_GEAR ) then
dmginfo:ScaleDamage( 0.25 )
end
end

View File

@@ -0,0 +1,223 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local meta = FindMetaTable( "Player" )
if ( !meta ) then return end
-- In this file we're adding functions to the player meta table.
-- This means you'll be able to call functions here straight from the player object
-- You can even override already existing functions.
--[[---------------------------------------------------------
Name: AddFrozenPhysicsObject
Desc: For the Physgun, adds a frozen object to the player's list
-----------------------------------------------------------]]
function meta:AddFrozenPhysicsObject( ent, phys )
-- Get the player's table
local tab = self:GetTable()
-- Make sure the physics objects table exists
tab.FrozenPhysicsObjects = tab.FrozenPhysicsObjects or {}
-- Make a new table that contains the info
local entry = {}
entry.ent = ent
entry.phys = phys
table.insert( tab.FrozenPhysicsObjects, entry )
gamemode.Call( "PlayerFrozeObject", self, ent, phys )
end
local function PlayerUnfreezeObject( ply, ent, object )
-- Not frozen!
if ( object:IsMoveable() ) then return 0 end
-- Unfreezable means it can't be frozen or unfrozen.
-- This prevents the player unfreezing the gmod_anchor entity.
if ( ent:GetUnFreezable() ) then return 0 end
-- NOTE: IF YOU'RE MAKING SOME KIND OF PROP PROTECTOR THEN HOOK "CanPlayerUnfreeze"
if ( !gamemode.Call( "CanPlayerUnfreeze", ply, ent, object ) ) then return 0 end
object:EnableMotion( true )
object:Wake()
gamemode.Call( "PlayerUnfrozeObject", ply, ent, object )
return 1
end
--[[---------------------------------------------------------
Name: UnfreezePhysicsObjects
Desc: For the Physgun, unfreezes all frozen physics objects
-----------------------------------------------------------]]
function meta:PhysgunUnfreeze()
-- Get the player's table
local tab = self:GetTable()
if ( !tab.FrozenPhysicsObjects ) then return 0 end
-- Detect double click. Unfreeze all objects on double click.
if ( tab.LastPhysUnfreeze && CurTime() - tab.LastPhysUnfreeze < 0.25 ) then
return self:UnfreezePhysicsObjects()
end
local tr = self:GetEyeTrace()
if ( tr.HitNonWorld && IsValid( tr.Entity ) ) then
local Ents = constraint.GetAllConstrainedEntities( tr.Entity )
local UnfrozenObjects = 0
for k, ent in pairs( Ents ) do
local objects = ent:GetPhysicsObjectCount()
for i = 1, objects do
local physobject = ent:GetPhysicsObjectNum( i - 1 )
UnfrozenObjects = UnfrozenObjects + PlayerUnfreezeObject( self, ent, physobject )
end
end
return UnfrozenObjects
end
tab.LastPhysUnfreeze = CurTime()
return 0
end
--[[---------------------------------------------------------
Name: UnfreezePhysicsObjects
Desc: For the Physgun, unfreezes all frozen physics objects
-----------------------------------------------------------]]
function meta:UnfreezePhysicsObjects()
-- Get the player's table
local tab = self:GetTable()
-- If the table doesn't exist then quit here
if ( !tab.FrozenPhysicsObjects ) then return 0 end
local Count = 0
-- Loop through each table in our table
for k, v in pairs( tab.FrozenPhysicsObjects ) do
-- Make sure the entity to which the physics object
-- is attached is still valid (still exists)
if ( isentity( v.ent ) && IsValid( v.ent ) ) then
-- We can't directly test to see if EnableMotion is false right now
-- but IsMovable seems to do the job just fine.
-- We only test so the count isn't wrong
if ( IsValid( v.phys ) && !v.phys:IsMoveable() ) then
-- We need to freeze/unfreeze all physobj's in jeeps to stop it spazzing
if ( v.ent:GetClass() == "prop_vehicle_jeep" ) then
-- How many physics objects we have
local objects = v.ent:GetPhysicsObjectCount()
-- Loop through each one
for i = 0, objects - 1 do
local physobject = v.ent:GetPhysicsObjectNum( i )
PlayerUnfreezeObject( self, v.ent, physobject )
end
end
Count = Count + PlayerUnfreezeObject( self, v.ent, v.phys )
end
end
end
-- Remove the table
tab.FrozenPhysicsObjects = nil
return Count
end
local g_UniqueIDTable = {}
--[[---------------------------------------------------------
This table will persist between client deaths and reconnects
-----------------------------------------------------------]]
function meta:UniqueIDTable( key )
local id = 0
if ( SERVER ) then id = self:SteamID64() end
g_UniqueIDTable[ id ] = g_UniqueIDTable[ id ] or {}
g_UniqueIDTable[ id ][ key ] = g_UniqueIDTable[ id ][ key ] or {}
return g_UniqueIDTable[ id ][ key ]
end
--[[---------------------------------------------------------
Player Eye Trace
-----------------------------------------------------------]]
function meta:GetEyeTrace()
if ( CLIENT ) then
local framenum = FrameNumber()
-- Cache the trace results for the current frame, unless we're serverside
-- in which case it wouldn't play well with lag compensation at all
if ( self.LastPlayerTrace == framenum ) then
return self.PlayerTrace
end
self.LastPlayerTrace = framenum
end
local tr = util.TraceLine( util.GetPlayerTrace( self ) )
self.PlayerTrace = tr
return tr
end
--[[---------------------------------------------------------
GetEyeTraceIgnoreCursor
Like GetEyeTrace but doesn't use the cursor aim vector..
-----------------------------------------------------------]]
function meta:GetEyeTraceNoCursor()
if ( CLIENT ) then
local framenum = FrameNumber()
if ( self.LastPlayerAimTrace == framenum ) then
return self.PlayerAimTrace
end
self.LastPlayerAimTrace = framenum
end
local tr = util.TraceLine( util.GetPlayerTrace( self, self:EyeAngles():Forward() ) )
self.PlayerAimTrace = tr
return tr
end

View File

@@ -0,0 +1,861 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Name: gamemode:OnPhysgunFreeze( weapon, phys, ent, player )
Desc: The physgun wants to freeze a prop
-----------------------------------------------------------]]
function GM:OnPhysgunFreeze( weapon, phys, ent, ply )
-- Non vphysics entity, we don't know how to handle that
if ( !IsValid( phys ) ) then return end
-- Object is already frozen (!?)
if ( !phys:IsMoveable() ) then return end
if ( ent:GetUnFreezable() ) then return end
phys:EnableMotion( false )
-- Add it to the player's frozen props
ply:AddFrozenPhysicsObject( ent, phys )
end
--[[---------------------------------------------------------
Name: gamemode:OnPhysgunReload( weapon, player )
Desc: The physgun wants to freeze a prop
-----------------------------------------------------------]]
function GM:OnPhysgunReload( weapon, ply )
ply:PhysgunUnfreeze()
end
--[[---------------------------------------------------------
Name: gamemode:PlayerAuthed()
Desc: Player's STEAMID has been authed
-----------------------------------------------------------]]
function GM:PlayerAuthed( ply, SteamID, UniqueID )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerCanPickupWeapon()
Desc: Called when a player tries to pickup a weapon.
return true to allow the pickup.
-----------------------------------------------------------]]
function GM:PlayerCanPickupWeapon( ply, entity )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerCanPickupItem()
Desc: Called when a player tries to pickup an item.
return true to allow the pickup.
-----------------------------------------------------------]]
function GM:PlayerCanPickupItem( ply, entity )
return true
end
--[[---------------------------------------------------------
Name: gamemode:CanPlayerUnfreeze()
Desc: Can the player unfreeze this entity & physobject
-----------------------------------------------------------]]
function GM:CanPlayerUnfreeze( ply, entity, physobject )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerDisconnected()
Desc: Player has disconnected from the server.
-----------------------------------------------------------]]
function GM:PlayerDisconnected( ply )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSay()
Desc: A player (or server) has used say. Return a string
for the player to say. Return an empty string if the
player should say nothing.
-----------------------------------------------------------]]
function GM:PlayerSay( ply, text, teamonly )
return text
end
--[[---------------------------------------------------------
Name: gamemode:PlayerDeathThink( player )
Desc: Called when the player is waiting to respawn
-----------------------------------------------------------]]
function GM:PlayerDeathThink( pl )
if ( pl.NextSpawnTime && pl.NextSpawnTime > CurTime() ) then return end
if ( pl:IsBot() || pl:KeyPressed( IN_ATTACK ) || pl:KeyPressed( IN_ATTACK2 ) || pl:KeyPressed( IN_JUMP ) ) then
pl:Spawn()
end
end
--[[---------------------------------------------------------
Name: gamemode:PlayerUse( player, entity )
Desc: A player has attempted to use a specific entity
Return true if the player can use it
------------------------------------------------------------]]
function GM:PlayerUse( ply, entity )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSilentDeath()
Desc: Called when a player dies silently
-----------------------------------------------------------]]
function GM:PlayerSilentDeath( Victim )
Victim.NextSpawnTime = CurTime() + 2
Victim.DeathTime = CurTime()
end
--[[---------------------------------------------------------
Name: gamemode:PlayerDeath()
Desc: Called when a player dies.
-----------------------------------------------------------]]
function GM:PlayerDeath( ply, inflictor, attacker )
-- Don't spawn for at least 2 seconds
ply.NextSpawnTime = CurTime() + 2
ply.DeathTime = CurTime()
if ( IsValid( attacker ) && attacker:GetClass() == "trigger_hurt" ) then attacker = ply end
if ( IsValid( attacker ) && attacker:IsVehicle() && IsValid( attacker:GetDriver() ) ) then
attacker = attacker:GetDriver()
end
if ( !IsValid( inflictor ) && IsValid( attacker ) ) then
inflictor = attacker
end
-- Convert the inflictor to the weapon that they're holding if we can.
-- This can be right or wrong with NPCs since combine can be holding a
-- pistol but kill you by hitting you with their arm.
if ( IsValid( inflictor ) && inflictor == attacker && ( inflictor:IsPlayer() || inflictor:IsNPC() ) ) then
inflictor = inflictor:GetActiveWeapon()
if ( !IsValid( inflictor ) ) then inflictor = attacker end
end
player_manager.RunClass( ply, "Death", inflictor, attacker )
if ( attacker == ply ) then
self:SendDeathNotice( nil, "suicide", ply, 0 )
MsgAll( attacker:Nick() .. " suicided!\n" )
return end
if ( attacker:IsPlayer() ) then
self:SendDeathNotice( attacker, inflictor:GetClass(), ply, 0 )
MsgAll( attacker:Nick() .. " killed " .. ply:Nick() .. " using " .. inflictor:GetClass() .. "\n" )
return end
local flags = 0
if ( attacker:IsNPC() and attacker:Disposition( ply ) != D_HT ) then flags = flags + DEATH_NOTICE_FRIENDLY_ATTACKER end
self:SendDeathNotice( self:GetDeathNoticeEntityName( attacker ), inflictor:GetClass(), ply, 0 )
MsgAll( ply:Nick() .. " was killed by " .. attacker:GetClass() .. "\n" )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerInitialSpawn()
Desc: Called just before the player's first spawn
-----------------------------------------------------------]]
function GM:PlayerInitialSpawn( pl, transiton )
pl:SetTeam( TEAM_UNASSIGNED )
if ( GAMEMODE.TeamBased ) then
pl:ConCommand( "gm_showteam" )
end
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSpawnAsSpectator()
Desc: Player spawns as a spectator
-----------------------------------------------------------]]
function GM:PlayerSpawnAsSpectator( pl )
pl:StripWeapons()
if ( pl:Team() == TEAM_UNASSIGNED ) then
pl:Spectate( OBS_MODE_FIXED )
return
end
pl:SetTeam( TEAM_SPECTATOR )
pl:Spectate( OBS_MODE_ROAMING )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSpawn()
Desc: Called when a player spawns
-----------------------------------------------------------]]
function GM:PlayerSpawn( pl, transiton )
--
-- If the player doesn't have a team in a TeamBased game
-- then spawn him as a spectator
--
if ( self.TeamBased && ( pl:Team() == TEAM_SPECTATOR || pl:Team() == TEAM_UNASSIGNED ) ) then
self:PlayerSpawnAsSpectator( pl )
return
end
-- Stop observer mode
pl:UnSpectate()
player_manager.OnPlayerSpawn( pl, transiton )
player_manager.RunClass( pl, "Spawn" )
-- If we are in transition, do not touch player's weapons
if ( !transiton ) then
-- Call item loadout function
hook.Call( "PlayerLoadout", GAMEMODE, pl )
end
-- Set player model
hook.Call( "PlayerSetModel", GAMEMODE, pl )
pl:SetupHands()
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSetModel()
Desc: Set the player's model
-----------------------------------------------------------]]
function GM:PlayerSetModel( pl )
player_manager.RunClass( pl, "SetModel" )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSetHandsModel()
Desc: Sets the player's view model hands model
-----------------------------------------------------------]]
function GM:PlayerSetHandsModel( pl, ent )
local info = player_manager.RunClass( pl, "GetHandsModel" )
if ( !info ) then
local playermodel = player_manager.TranslateToPlayerModelName( pl:GetModel() )
info = player_manager.TranslatePlayerHands( playermodel )
end
if ( info ) then
ent:SetModel( info.model )
ent:SetSkin( info.matchBodySkin and pl:GetSkin() or info.skin )
ent:SetBodyGroups( info.body )
end
end
--[[---------------------------------------------------------
Name: gamemode:PlayerLoadout()
Desc: Give the player the default spawning weapons/ammo
-----------------------------------------------------------]]
function GM:PlayerLoadout( pl )
player_manager.RunClass( pl, "Loadout" )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSelectTeamSpawn( player )
Desc: Find a spawn point entity for this player's team
-----------------------------------------------------------]]
function GM:PlayerSelectTeamSpawn( TeamID, pl )
local SpawnPoints = team.GetSpawnPoints( TeamID )
if ( !SpawnPoints || table.IsEmpty( SpawnPoints ) ) then return end
local ChosenSpawnPoint = nil
for i = 0, 6 do
ChosenSpawnPoint = table.Random( SpawnPoints )
if ( hook.Call( "IsSpawnpointSuitable", GAMEMODE, pl, ChosenSpawnPoint, i == 6 ) ) then
return ChosenSpawnPoint
end
end
return ChosenSpawnPoint
end
--[[---------------------------------------------------------
Name: gamemode:IsSpawnpointSuitable( player )
Desc: Find out if the spawnpoint is suitable or not
-----------------------------------------------------------]]
local spawnpointmin = Vector( -16, -16, 0 )
local spawnpointmax = Vector( 16, 16, 64 )
function GM:IsSpawnpointSuitable( pl, spawnpointent, bMakeSuitable )
local Pos = spawnpointent:GetPos()
-- Note that we're searching the default hull size here for a player in the way of our spawning.
-- This seems pretty rough, seeing as our player's hull could be different.. but it should do the job
-- (HL2DM kills everything within a 128 unit radius)
if ( pl:Team() == TEAM_SPECTATOR ) then return true end
local Blockers = 0
for k, v in ipairs( ents.FindInBox( Pos + spawnpointmin, Pos + spawnpointmax ) ) do
if ( IsValid( v ) && v != pl && v:GetClass() == "player" && v:Alive() ) then
Blockers = Blockers + 1
if ( bMakeSuitable ) then
v:Kill()
end
end
end
if ( bMakeSuitable ) then return true end
if ( Blockers > 0 ) then return false end
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSelectSpawn( player )
Desc: Find a spawn point entity for this player
-----------------------------------------------------------]]
function GM:PlayerSelectSpawn( pl, transiton )
-- If we are in transition, do not reset player's position
if ( transiton ) then return end
if ( self.TeamBased ) then
local ent = self:PlayerSelectTeamSpawn( pl:Team(), pl )
if ( IsValid( ent ) ) then return ent end
end
-- Save information about all of the spawn points
-- in a team based game you'd split up the spawns
if ( !IsTableOfEntitiesValid( self.SpawnPoints ) ) then
self.LastSpawnPoint = 0
self.SpawnPoints = ents.FindByClass( "info_player_start" )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_deathmatch" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_combine" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_rebel" ) )
-- CS Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_counterterrorist" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_terrorist" ) )
-- DOD Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_axis" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_allies" ) )
-- (Old) GMod Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "gmod_player_start" ) )
-- TF Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_teamspawn" ) )
-- INS Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "ins_spawnpoint" ) )
-- AOC Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "aoc_spawnpoint" ) )
-- Dystopia Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "dys_spawn_point" ) )
-- PVKII Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_pirate" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_viking" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_knight" ) )
-- DIPRIP Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "diprip_start_team_blue" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "diprip_start_team_red" ) )
-- OB Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_red" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_blue" ) )
-- SYN Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_coop" ) )
-- ZPS Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_human" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_zombie" ) )
-- ZM Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_zombiemaster" ) )
-- FOF Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_fof" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_desperado" ) )
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_player_vigilante" ) )
-- L4D Maps
self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_survivor_rescue" ) )
-- Removing this one for the time being, c1m4_atrium has one of these in a box under the map
--self.SpawnPoints = table.Add( self.SpawnPoints, ents.FindByClass( "info_survivor_position" ) )
end
local Count = table.Count( self.SpawnPoints )
if ( Count == 0 ) then
Msg("[PlayerSelectSpawn] Error! No spawn points!\n")
return nil
end
-- If any of the spawnpoints have a MASTER flag then only use that one.
-- This is needed for single player maps.
for k, v in pairs( self.SpawnPoints ) do
if ( v:HasSpawnFlags( 1 ) && hook.Call( "IsSpawnpointSuitable", GAMEMODE, pl, v, true ) ) then
return v
end
end
local ChosenSpawnPoint = nil
-- Try to work out the best, random spawnpoint
for i = 1, Count do
ChosenSpawnPoint = table.Random( self.SpawnPoints )
if ( IsValid( ChosenSpawnPoint ) && ChosenSpawnPoint:IsInWorld() ) then
if ( ( ChosenSpawnPoint == pl:GetVar( "LastSpawnpoint" ) || ChosenSpawnPoint == self.LastSpawnPoint ) && Count > 1 ) then continue end
if ( hook.Call( "IsSpawnpointSuitable", GAMEMODE, pl, ChosenSpawnPoint, i == Count ) ) then
self.LastSpawnPoint = ChosenSpawnPoint
pl:SetVar( "LastSpawnpoint", ChosenSpawnPoint )
return ChosenSpawnPoint
end
end
end
return ChosenSpawnPoint
end
--[[---------------------------------------------------------
Name: gamemode:WeaponEquip( weapon )
Desc: Player just picked up (or was given) weapon
-----------------------------------------------------------]]
function GM:WeaponEquip( weapon )
end
--[[---------------------------------------------------------
Name: gamemode:ScalePlayerDamage( ply, hitgroup, dmginfo )
Desc: Scale the damage based on being shot in a hitbox
Return true to not take damage
-----------------------------------------------------------]]
function GM:ScalePlayerDamage( ply, hitgroup, dmginfo )
-- More damage if we're shot in the head
if ( hitgroup == HITGROUP_HEAD ) then
dmginfo:ScaleDamage( 2 )
end
-- Less damage if we're shot in the arms or legs
if ( hitgroup == HITGROUP_LEFTARM ||
hitgroup == HITGROUP_RIGHTARM ||
hitgroup == HITGROUP_LEFTLEG ||
hitgroup == HITGROUP_RIGHTLEG ||
hitgroup == HITGROUP_GEAR ) then
dmginfo:ScaleDamage( 0.25 )
end
end
--[[---------------------------------------------------------
Name: gamemode:PlayerDeathSound()
Desc: Return true to not play the default sounds
-----------------------------------------------------------]]
function GM:PlayerDeathSound()
return false
end
--[[---------------------------------------------------------
Name: gamemode:SetupPlayerVisibility()
Desc: Add extra positions to the player's PVS
-----------------------------------------------------------]]
function GM:SetupPlayerVisibility( pPlayer, pViewEntity )
--AddOriginToPVS( vector_position_here )
end
--[[---------------------------------------------------------
Name: gamemode:OnDamagedByExplosion( ply, dmginfo)
Desc: Player has been hurt by an explosion
-----------------------------------------------------------]]
function GM:OnDamagedByExplosion( ply, dmginfo )
ply:SetDSP( 35, false )
end
--[[---------------------------------------------------------
Name: gamemode:CanPlayerSuicide( ply )
Desc: Player typed KILL in the console. Can they kill themselves?
-----------------------------------------------------------]]
function GM:CanPlayerSuicide( ply )
return true
end
--[[---------------------------------------------------------
Name: gamemode:CanPlayerEnterVehicle( player, vehicle, role )
Desc: Return true if player can enter vehicle
-----------------------------------------------------------]]
function GM:CanPlayerEnterVehicle( ply, vehicle, role )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerEnteredVehicle( player, vehicle, role )
Desc: Player entered the vehicle fine
-----------------------------------------------------------]]
function GM:PlayerEnteredVehicle( ply, vehicle, role )
end
--[[---------------------------------------------------------
Name: gamemode:CanExitVehicle()
Desc: If the player is allowed to leave the vehicle, return true
-----------------------------------------------------------]]
function GM:CanExitVehicle( vehicle, passenger )
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerLeaveVehicle()
Desc: Player left the vehicle
-----------------------------------------------------------]]
function GM:PlayerLeaveVehicle( ply, vehicle )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSwitchFlashlight()
Desc: Return true to allow action
-----------------------------------------------------------]]
function GM:PlayerSwitchFlashlight( ply, SwitchOn )
return ply:CanUseFlashlight()
end
--[[---------------------------------------------------------
Name: gamemode:PlayerCanJoinTeam( ply, teamid )
Desc: Allow mods/addons to easily determine whether a player
can join a team or not
-----------------------------------------------------------]]
function GM:PlayerCanJoinTeam( ply, teamid )
local TimeBetweenSwitches = GAMEMODE.SecondsBetweenTeamSwitches or 10
if ( ply.LastTeamSwitch && RealTime() - ply.LastTeamSwitch < TimeBetweenSwitches ) then
ply.LastTeamSwitch = ply.LastTeamSwitch + 1
ply:ChatPrint( Format( "Please wait %i more seconds before trying to change team again", ( TimeBetweenSwitches - ( RealTime() - ply.LastTeamSwitch ) ) + 1 ) )
return false
end
-- Already on this team!
if ( ply:Team() == teamid ) then
ply:ChatPrint( "You're already on that team" )
return false
end
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerRequestTeam()
Desc: Player wants to change team
-----------------------------------------------------------]]
function GM:PlayerRequestTeam( ply, teamid )
-- No changing teams if not teambased!
if ( !GAMEMODE.TeamBased ) then return end
-- This team isn't joinable
if ( !team.Joinable( teamid ) ) then
ply:ChatPrint( "You can't join that team" )
return end
-- This team isn't joinable
if ( !GAMEMODE:PlayerCanJoinTeam( ply, teamid ) ) then
-- Messages here should be outputted by this function
return end
GAMEMODE:PlayerJoinTeam( ply, teamid )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerJoinTeam()
Desc: Make player join this team
-----------------------------------------------------------]]
function GM:PlayerJoinTeam( ply, teamid )
local iOldTeam = ply:Team()
if ( ply:Alive() ) then
if ( iOldTeam == TEAM_SPECTATOR || iOldTeam == TEAM_UNASSIGNED ) then
ply:KillSilent()
else
ply:Kill()
end
end
ply:SetTeam( teamid )
ply.LastTeamSwitch = RealTime()
GAMEMODE:OnPlayerChangedTeam( ply, iOldTeam, teamid )
end
--[[---------------------------------------------------------
Name: gamemode:OnPlayerChangedTeam( ply, oldteam, newteam )
-----------------------------------------------------------]]
function GM:OnPlayerChangedTeam( ply, oldteam, newteam )
-- Here's an immediate respawn thing by default. If you want to
-- re-create something more like CS or some shit you could probably
-- change to a spectator or something while dead.
if ( newteam == TEAM_SPECTATOR ) then
-- If we changed to spectator mode, respawn where we are
local Pos = ply:EyePos()
ply:Spawn()
ply:SetPos( Pos )
elseif ( oldteam == TEAM_SPECTATOR ) then
-- If we're changing from spectator, join the game
ply:Spawn()
else
-- If we're straight up changing teams just hang
-- around until we're ready to respawn onto the
-- team that we chose
end
PrintMessage( HUD_PRINTTALK, Format( "%s joined '%s'", ply:Nick(), team.GetName( newteam ) ) )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerSpray()
Desc: Return true to prevent player spraying
-----------------------------------------------------------]]
function GM:PlayerSpray( ply )
return false
end
--[[---------------------------------------------------------
Name: gamemode:OnPlayerHitGround()
Desc: Return true to disable default action
-----------------------------------------------------------]]
function GM:OnPlayerHitGround( ply, bInWater, bOnFloater, flFallSpeed )
-- Apply damage and play collision sound here
-- then return true to disable the default action
--MsgN( ply, bInWater, bOnFloater, flFallSpeed )
--return true
end
--[[---------------------------------------------------------
Name: gamemode:GetFallDamage()
Desc: return amount of damage to do due to fall
-----------------------------------------------------------]]
local mp_falldamage = GetConVar( "mp_falldamage" )
function GM:GetFallDamage( ply, flFallSpeed )
if ( mp_falldamage:GetBool() ) then -- realistic fall damage is on
return ( flFallSpeed - 526.5 ) * ( 100 / 396 ) -- the Source SDK value
end
return 10
end
--[[---------------------------------------------------------
Name: gamemode:PlayerCanSeePlayersChat()
Desc: Can this player see the other player's chat?
-----------------------------------------------------------]]
function GM:PlayerCanSeePlayersChat( strText, bTeamOnly, pListener, pSpeaker )
if ( bTeamOnly ) then
if ( !IsValid( pSpeaker ) || !IsValid( pListener ) ) then return false end
if ( pListener:Team() != pSpeaker:Team() ) then return false end
end
return true
end
local sv_alltalk = GetConVar( "sv_alltalk" )
--[[---------------------------------------------------------
Name: gamemode:PlayerCanHearPlayersVoice()
Desc: Can this player see the other player's voice?
Returns 2 bools.
1. Can the player hear the other player
2. Can they hear them spacially
-----------------------------------------------------------]]
function GM:PlayerCanHearPlayersVoice( pListener, pTalker )
local alltalk = sv_alltalk:GetInt()
if ( alltalk >= 1 ) then return true, alltalk == 2 end
return pListener:Team() == pTalker:Team(), false
end
--[[---------------------------------------------------------
Name: gamemode:NetworkIDValidated()
Desc: Called when Steam has validated this as a valid player
-----------------------------------------------------------]]
function GM:NetworkIDValidated( name, steamid )
-- MsgN( "GM:NetworkIDValidated", name, steamid )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerShouldTaunt( ply, actid )
-----------------------------------------------------------]]
function GM:PlayerShouldTaunt( ply, actid )
-- The default behaviour is to always let them act
-- Some gamemodes will obviously want to stop this for certain players by returning false
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerStartTaunt( ply, actid, length )
-----------------------------------------------------------]]
function GM:PlayerStartTaunt( ply, actid, length )
end
--[[---------------------------------------------------------
Name: gamemode:AllowPlayerPickup( ply, object )
-----------------------------------------------------------]]
function GM:AllowPlayerPickup( ply, object )
-- Should the player be allowed to pick this object up (using ENTER)?
-- If no then return false. Default is HELL YEAH
return true
end
--[[---------------------------------------------------------
Name: gamemode:PlayerDroppedWeapon()
Desc: Player has dropped a weapon
-----------------------------------------------------------]]
function GM:PlayerDroppedWeapon( ply, weapon )
end
--[[---------------------------------------------------------
These are buttons that the client is pressing. They're used
in Sandbox mode to control things like wheels, thrusters etc.
-----------------------------------------------------------]]
function GM:PlayerButtonDown( ply, btn ) end
function GM:PlayerButtonUp( ply, btn ) end
concommand.Add( "changeteam", function( pl, cmd, args ) hook.Call( "PlayerRequestTeam", GAMEMODE, pl, tonumber( args[ 1 ] ) ) end )
--[[---------------------------------------------------------
Name: gamemode:HandlePlayerArmorReduction()
Desc: Handle player armor reduction
-----------------------------------------------------------]]
function GM:HandlePlayerArmorReduction( ply, dmginfo )
-- If no armor, or special damage types, bypass armor
if ( ply:Armor() <= 0 || bit.band( dmginfo:GetDamageType(), DMG_FALL + DMG_DROWN + DMG_POISON + DMG_RADIATION ) != 0 ) then return end
local flBonus = 1.0 -- Each Point of Armor is worth 1/x points of health
local flRatio = 0.2 -- Armor Takes 80% of the damage
if ( GetConVar( "player_old_armor" ):GetBool() ) then
flBonus = 0.5
end
local flNew = dmginfo:GetDamage() * flRatio
local flArmor = (dmginfo:GetDamage() - flNew) * flBonus
if ( !GetConVar( "player_old_armor" ):GetBool() ) then
if ( flArmor < 0.1 ) then flArmor = 0 end -- Let's not have tiny amounts of damage reduce a lot of our armor
else if ( flArmor < 1.0 ) then flArmor = 1.0 end
end
-- Does this use more armor than we have?
if ( flArmor > ply:Armor() ) then
flArmor = ply:Armor() * ( 1 / flBonus )
flNew = dmginfo:GetDamage() - flArmor
ply:SetArmor( 0 )
else
ply:SetArmor( ply:Armor() - flArmor )
end
dmginfo:SetDamage( flNew )
end

View File

@@ -0,0 +1,145 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
include( "taunt_camera.lua" )
local PLAYER = {}
PLAYER.DisplayName = "Default Class"
PLAYER.SlowWalkSpeed = 200 -- How fast to move when slow-walking (+WALK)
PLAYER.WalkSpeed = 400 -- How fast to move when not running
PLAYER.RunSpeed = 600 -- How fast to move when running
PLAYER.CrouchedWalkSpeed = 0.3 -- Multiply move speed by this when crouching
PLAYER.DuckSpeed = 0.3 -- How fast to go from not ducking, to ducking
PLAYER.UnDuckSpeed = 0.3 -- How fast to go from ducking, to not ducking
PLAYER.JumpPower = 200 -- How powerful our jump should be
PLAYER.CanUseFlashlight = true -- Can we use the flashlight
PLAYER.MaxHealth = 100 -- Max health we can have
PLAYER.MaxArmor = 100 -- Max armor we can have
PLAYER.StartHealth = 100 -- How much health we start with
PLAYER.StartArmor = 0 -- How much armour we start with
PLAYER.DropWeaponOnDie = false -- Do we drop our weapon when we die
PLAYER.TeammateNoCollide = true -- Do we collide with teammates or run straight through them
PLAYER.AvoidPlayers = true -- Automatically swerves around other players
PLAYER.UseVMHands = true -- Uses viewmodel hands
--
-- Name: PLAYER:SetupDataTables
-- Desc: Set up the network table accessors
-- Arg1:
-- Ret1:
--
function PLAYER:SetupDataTables()
end
--
-- Name: PLAYER:Init
-- Desc: Called when the class object is created (shared)
-- Arg1:
-- Ret1:
--
function PLAYER:Init()
end
--
-- Name: PLAYER:Spawn
-- Desc: Called serverside only when the player spawns
-- Arg1:
-- Ret1:
--
function PLAYER:Spawn()
end
--
-- Name: PLAYER:Loadout
-- Desc: Called on spawn to give the player their default loadout
-- Arg1:
-- Ret1:
--
function PLAYER:Loadout()
self.Player:Give( "weapon_pistol" )
self.Player:GiveAmmo( 255, "Pistol", true )
end
function PLAYER:SetModel()
local cl_playermodel = self.Player:GetInfo( "cl_playermodel" )
local modelname = player_manager.TranslatePlayerModel( cl_playermodel )
util.PrecacheModel( modelname )
self.Player:SetModel( modelname )
end
function PLAYER:Death( inflictor, attacker )
end
-- Clientside only
function PLAYER:CalcView( view ) end -- Setup the player's view
function PLAYER:CreateMove( cmd ) end -- Creates the user command on the client
function PLAYER:ShouldDrawLocal() end -- Return true if we should draw the local player
-- Shared
function PLAYER:StartMove( cmd, mv ) end -- Copies from the user command to the move
function PLAYER:Move( mv ) end -- Runs the move (can run multiple times for the same client)
function PLAYER:FinishMove( mv ) end -- Copy the results of the move back to the Player
--
-- Name: PLAYER:ViewModelChanged
-- Desc: Called when the player changes their weapon to another one causing their viewmodel model to change
-- Arg1: Entity|viewmodel|The viewmodel that is changing
-- Arg2: string|old|The old model
-- Arg3: string|new|The new model
-- Ret1:
--
function PLAYER:ViewModelChanged( vm, old, new )
end
--
-- Name: PLAYER:PreDrawViewmodel
-- Desc: Called before the viewmodel is being drawn (clientside)
-- Arg1: Entity|viewmodel|The viewmodel
-- Arg2: Entity|weapon|The weapon
-- Ret1:
--
function PLAYER:PreDrawViewModel( vm, weapon )
end
--
-- Name: PLAYER:PostDrawViewModel
-- Desc: Called after the viewmodel has been drawn (clientside)
-- Arg1: Entity|viewmodel|The viewmodel
-- Arg2: Entity|weapon|The weapon
-- Ret1:
--
function PLAYER:PostDrawViewModel( vm, weapon )
end
--
-- Name: PLAYER:GetHandsModel
-- Desc: Called on player spawn to determine which hand model to use
-- Arg1:
-- Ret1: table|info|A table containing model, skin and body
--
function PLAYER:GetHandsModel()
-- return { model = "models/weapons/c_arms_cstrike.mdl", skin = 1, body = "0100000" }
local playermodel = player_manager.TranslateToPlayerModelName( self.Player:GetModel() )
return player_manager.TranslatePlayerHands( playermodel )
end
player_manager.RegisterClass( "player_default", PLAYER, nil )

View File

@@ -0,0 +1,133 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
--
-- This is designed so you can call it like
--
-- tauntcam = TauntCamera()
--
-- Then you have your own copy.
--
function TauntCamera()
local CAM = {}
local WasOn = false
local CustomAngles = angle_zero
local PlayerLockAngles = nil
local InLerp = 0
local OutLerp = 1
--
-- Draw the local player if we're active in any way
--
CAM.ShouldDrawLocalPlayer = function( self, ply, on )
return on || OutLerp < 1
end
--
-- Implements the third person, rotation view (with lerping in/out)
--
CAM.CalcView = function( self, view, ply, on )
if ( !ply:Alive() || !IsValid( ply:GetViewEntity() ) || ply:GetViewEntity() != ply ) then on = false end
if ( WasOn != on ) then
if ( on ) then InLerp = 0 end
if ( !on ) then OutLerp = 0 end
WasOn = on
end
if ( !on && OutLerp >= 1 ) then
CustomAngles = view.angles * 1
CustomAngles.r = 0
PlayerLockAngles = nil
InLerp = 0
return
end
if ( PlayerLockAngles == nil ) then return end
--
-- Simple 3rd person camera
--
local TargetOrigin = view.origin - CustomAngles:Forward() * 100
local tr = util.TraceHull( { start = view.origin, endpos = TargetOrigin, mask = MASK_SHOT, filter = player.GetAll(), mins = Vector( -8, -8, -8 ), maxs = Vector( 8, 8, 8 ) } )
TargetOrigin = tr.HitPos + tr.HitNormal
if ( InLerp < 1 ) then
InLerp = InLerp + FrameTime() * 5.0
view.origin = LerpVector( InLerp, view.origin, TargetOrigin )
view.angles = LerpAngle( InLerp, PlayerLockAngles, CustomAngles )
return true
end
if ( OutLerp < 1 ) then
OutLerp = OutLerp + FrameTime() * 3.0
view.origin = LerpVector( 1-OutLerp, view.origin, TargetOrigin )
view.angles = LerpAngle( 1-OutLerp, PlayerLockAngles, CustomAngles )
return true
end
view.angles = CustomAngles * 1
view.origin = TargetOrigin
return true
end
--
-- Freezes the player in position and uses the input from the user command to
-- rotate the custom third person camera
--
CAM.CreateMove = function( self, cmd, ply, on )
if ( !ply:Alive() ) then on = false end
if ( !on ) then return end
if ( PlayerLockAngles == nil ) then
PlayerLockAngles = CustomAngles * 1
end
--
-- Rotate our view
--
CustomAngles.pitch = CustomAngles.pitch + cmd:GetMouseY() * 0.01
CustomAngles.yaw = CustomAngles.yaw - cmd:GetMouseX() * 0.01
--
-- Lock the player's controls and angles
--
cmd:SetViewAngles( PlayerLockAngles )
cmd:ClearButtons()
cmd:ClearMovement()
return true
end
return CAM
end

View File

@@ -0,0 +1,145 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
Name: gamemode:PlayerTraceAttack( )
Desc: A bullet has been fired and hit this player
Return true to completely override internals
-----------------------------------------------------------]]
function GM:PlayerTraceAttack( ply, dmginfo, dir, trace )
return false
end
--[[---------------------------------------------------------
Name: gamemode:SetPlayerSpeed( )
Desc: Sets the player's run/walk speed
-----------------------------------------------------------]]
function GM:SetPlayerSpeed( ply, walk, run )
ply:SetWalkSpeed( walk )
ply:SetRunSpeed( run )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerFootstep( ply, vPos, iFoot, strSoundName, fVolume, pFilter )
Desc: Called when a player steps
pFilter is the recipient filter to use for effects/sounds
and is only valid SERVERSIDE. Clientside needs no filter!
Return true to not play normal sound
-----------------------------------------------------------]]
function GM:PlayerFootstep( ply, vPos, iFoot, strSoundName, fVolume, pFilter )
if ( IsValid( ply ) and !ply:Alive() ) then
return true
end
--[[
-- Draw effect on footdown
local effectdata = EffectData()
effectdata:SetOrigin( vPos )
util.Effect( "phys_unfreeze", effectdata, true, pFilter )
--]]
--[[
-- Don't play left foot
if ( iFoot == 0 ) then return true end
--]]
end
--[[---------------------------------------------------------
Name: gamemode:PlayerStepSoundTime( ply, iType, bWalking )
Desc: Return the time between footsteps
-----------------------------------------------------------]]
function GM:PlayerStepSoundTime( ply, iType, bWalking )
local fStepTime = 350
local fMaxSpeed = ply:GetMaxSpeed()
if ( iType == STEPSOUNDTIME_NORMAL || iType == STEPSOUNDTIME_WATER_FOOT ) then
if ( fMaxSpeed <= 100 ) then
fStepTime = 400
elseif ( fMaxSpeed <= 300 ) then
fStepTime = 350
else
fStepTime = 250
end
elseif ( iType == STEPSOUNDTIME_ON_LADDER ) then
fStepTime = 450
elseif ( iType == STEPSOUNDTIME_WATER_KNEE ) then
fStepTime = 600
end
-- Step slower if crouching
if ( ply:Crouching() ) then
fStepTime = fStepTime + 50
end
return fStepTime
end
--[[---------------------------------------------------------
Name: gamemode:PlayerNoClip( player, bool )
Desc: Player pressed the noclip key, return true if
the player is allowed to noclip, false to block
-----------------------------------------------------------]]
function GM:PlayerNoClip( pl, on )
if ( !on ) then return true end
-- Allow noclip if we're in single player and living
return game.SinglePlayer() && IsValid( pl ) && pl:Alive()
end
--
-- FindUseEntity
--
function GM:FindUseEntity( ply, ent )
-- ent is what the game found to use by default
-- return what you REALLY want it to use
-- Simple fix to allow entities inside playerclip brushes to be used. Necessary for c1a0c map in Half-Life: Source
if ( !IsValid( ent ) ) then
local traceEnt = util.TraceLine( {
start = ply:GetShootPos(),
endpos = ply:GetShootPos() + ply:GetAimVector() * 72,
filter = ply
} ).Entity
if ( IsValid( traceEnt ) ) then return traceEnt end
end
return ent
end
--
-- Player tick
--
function GM:PlayerTick( ply, mv )
end
--
-- Player is switching weapon. Return true to prevent the switch.
--
function GM:PlayerSwitchWeapon( ply, oldwep, newwep )
return false
end

View File

@@ -0,0 +1,282 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--[[---------------------------------------------------------
This file should contain variables and functions that are
the same on both client and server.
This file will get sent to the client - so don't add
anything to this file that you don't want them to be
able to see.
-----------------------------------------------------------]]
include( "obj_player_extend.lua" )
include( "gravitygun.lua" )
include( "player_shd.lua" )
include( "animations.lua" )
include( "player_class/player_default.lua" )
GM.Name = "Base Gamemode"
GM.Author = "Garry Newman"
GM.Email = "garrynewman@gmail.com"
GM.Website = "www.garry.tv"
GM.TeamBased = false
--[[---------------------------------------------------------
Name: gamemode:KeyPress( )
Desc: Player pressed a key (see IN enums)
-----------------------------------------------------------]]
function GM:KeyPress( player, key )
end
--[[---------------------------------------------------------
Name: gamemode:KeyRelease( )
Desc: Player released a key (see IN enums)
-----------------------------------------------------------]]
function GM:KeyRelease( player, key )
end
--[[---------------------------------------------------------
Name: gamemode:PlayerConnect( )
Desc: Player has connects to the server (hasn't spawned)
-----------------------------------------------------------]]
function GM:PlayerConnect( name, address )
end
--[[---------------------------------------------------------
Name: gamemode:PropBreak( )
Desc: Prop has been broken
-----------------------------------------------------------]]
function GM:PropBreak( attacker, prop )
end
--[[---------------------------------------------------------
Name: gamemode:PhysgunPickup( )
Desc: Return true if player can pickup entity
-----------------------------------------------------------]]
function GM:PhysgunPickup( ply, ent )
-- Don't pick up players
if ( ent:GetClass() == "player" ) then return false end
return true
end
--[[---------------------------------------------------------
Name: gamemode:PhysgunDrop( )
Desc: Dropped an entity
-----------------------------------------------------------]]
function GM:PhysgunDrop( ply, ent )
end
--[[---------------------------------------------------------
Name: Text to show in the server browser
-----------------------------------------------------------]]
function GM:GetGameDescription()
return self.Name
end
--[[---------------------------------------------------------
Name: Saved
-----------------------------------------------------------]]
function GM:Saved()
end
--[[---------------------------------------------------------
Name: Restored
-----------------------------------------------------------]]
function GM:Restored()
end
--[[---------------------------------------------------------
Name: EntityRemoved
Desc: Called right before an entity is removed. Note that this
isn't going to be totally reliable on the client since the client
only knows about entities that it has had in its PVS.
-----------------------------------------------------------]]
function GM:EntityRemoved( ent )
end
--[[---------------------------------------------------------
Name: Tick
Desc: Like Think except called every tick on both client and server
-----------------------------------------------------------]]
function GM:Tick()
end
--[[---------------------------------------------------------
Name: OnEntityCreated
Desc: Called right after the Entity has been made visible to Lua
-----------------------------------------------------------]]
function GM:OnEntityCreated( Ent )
end
--[[---------------------------------------------------------
Name: gamemode:EntityKeyValue( ent, key, value )
Desc: Called when an entity has a keyvalue set
Returning a string it will override the value
-----------------------------------------------------------]]
function GM:EntityKeyValue( ent, key, value )
end
--[[---------------------------------------------------------
Name: gamemode:CreateTeams()
Desc: Note - HAS to be shared.
-----------------------------------------------------------]]
function GM:CreateTeams()
-- Don't do this if not teambased. But if it is teambased we
-- create a few teams here as an example. If you're making a teambased
-- gamemode you should override this function in your gamemode
if ( !GAMEMODE.TeamBased ) then return end
TEAM_BLUE = 1
team.SetUp( TEAM_BLUE, "Blue Team", Color( 0, 0, 255 ) )
team.SetSpawnPoint( TEAM_BLUE, "ai_hint" ) -- <-- This would be info_terrorist or some entity that is in your map
TEAM_ORANGE = 2
team.SetUp( TEAM_ORANGE, "Orange Team", Color( 255, 150, 0 ) )
team.SetSpawnPoint( TEAM_ORANGE, "sky_camera" ) -- <-- This would be info_terrorist or some entity that is in your map
TEAM_SEXY = 3
team.SetUp( TEAM_SEXY, "Sexy Team", Color( 255, 150, 150 ) )
team.SetSpawnPoint( TEAM_SEXY, "info_player_start" ) -- <-- This would be info_terrorist or some entity that is in your map
team.SetSpawnPoint( TEAM_SPECTATOR, "worldspawn" )
end
--[[---------------------------------------------------------
Name: gamemode:ShouldCollide( Ent1, Ent2 )
Desc: This should always return true unless you have
a good reason for it not to.
-----------------------------------------------------------]]
function GM:ShouldCollide( Ent1, Ent2 )
return true
end
--[[---------------------------------------------------------
Name: gamemode:Move
This basically overrides the NOCLIP, PLAYERMOVE movement stuff.
It's what actually performs the move.
Return true to not perform any default movement actions. (completely override)
-----------------------------------------------------------]]
function GM:Move( ply, mv )
if ( drive.Move( ply, mv ) ) then return true end
if ( player_manager.RunClass( ply, "Move", mv ) ) then return true end
end
--[[---------------------------------------------------------
-- Purpose: This is called pre player movement and copies all the data necessary
-- from the player for movement. Copy from the usercmd to move.
-----------------------------------------------------------]]
function GM:SetupMove( ply, mv, cmd )
if ( drive.StartMove( ply, mv, cmd ) ) then return true end
if ( player_manager.RunClass( ply, "StartMove", mv, cmd ) ) then return true end
end
--[[---------------------------------------------------------
Name: gamemode:FinishMove( player, movedata )
-----------------------------------------------------------]]
function GM:FinishMove( ply, mv )
if ( drive.FinishMove( ply, mv ) ) then return true end
if ( player_manager.RunClass( ply, "FinishMove", mv ) ) then return true end
end
--[[---------------------------------------------------------
Called after the player's think.
-----------------------------------------------------------]]
function GM:PlayerPostThink( ply )
end
--[[---------------------------------------------------------
A player has started driving an entity
-----------------------------------------------------------]]
function GM:StartEntityDriving( ent, ply )
drive.Start( ply, ent )
end
--[[---------------------------------------------------------
A player has stopped driving an entity
-----------------------------------------------------------]]
function GM:EndEntityDriving( ent, ply )
drive.End( ply, ent )
end
--[[---------------------------------------------------------
To update the player's animation during a drive
-----------------------------------------------------------]]
function GM:PlayerDriveAnimate( ply )
end
--[[---------------------------------------------------------
The gamemode has been reloaded
-----------------------------------------------------------]]
function GM:OnReloaded()
end
function GM:PreGamemodeLoaded()
end
function GM:OnGamemodeLoaded()
end
function GM:PostGamemodeLoaded()
end
--
-- Name: GM:OnViewModelChanged
-- Desc: Called when the player changes their weapon to another one - and their viewmodel model changes
-- Arg1: Entity|viewmodel|The viewmodel that is changing
-- Arg2: string|old|The old model
-- Arg3: string|new|The new model
-- Ret1:
--
function GM:OnViewModelChanged( vm, old, new )
local ply = vm:GetOwner()
if ( IsValid( ply ) ) then
player_manager.RunClass( ply, "ViewModelChanged", vm, old, new )
end
end
--[[---------------------------------------------------------
Disable properties serverside for all non-sandbox derived gamemodes.
-----------------------------------------------------------]]
function GM:CanProperty( pl, property, ent )
return false
end
--[[---------------------------------------------------------
Allow hooks to override bullet without ignoring all other hooks
-----------------------------------------------------------]]
function GM:EntityFireBullets( ent, bullets )
return true
end

View File

@@ -0,0 +1,42 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--
-- Called when we've received a call from a client who wants to edit
-- a particular entity.
--
function GM:VariableEdited( ent, ply, key, val, editor )
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ply ) ) then return end
--
-- Check with the gamemode that we can edit the entity
--
local CanEdit = hook.Run( "CanEditVariable", ent, ply, key, val, editor )
if ( !CanEdit ) then return end
--
-- Actually apply the edited value
--
ent:EditValue( key, val )
end
--
-- Your gamemode should use this hook to allow/dissallow editing
-- By default only admins can edit entities.
--
function GM:CanEditVariable( ent, ply, key, val, editor )
return ply:IsAdmin() || game.SinglePlayer()
end

32
gamemodes/base/send.txt Normal file
View File

@@ -0,0 +1,32 @@
#
# These files aren't fully sent to the client because they
# should never change. Instead we send the CRC of this file
# so the client can load their version - and we know it's kewl.
#
gamemodes\base\gamemode\player_class\player_default.lua
gamemodes\base\entities\weapons\weapon_base\cl_init.lua
gamemodes\base\entities\weapons\weapon_base\shared.lua
gamemodes\base\entities\weapons\weapon_base\ai_translations.lua
gamemodes\base\entities\weapons\weapon_base\sh_anim.lua
gamemodes\base\entities\entities\base_point.lua
gamemodes\base\entities\entities\base_ai\cl_init.lua
gamemodes\base\entities\entities\base_ai\shared.lua
gamemodes\base\entities\entities\base_anim.lua
gamemodes\base\entities\entities\base_entity\cl_init.lua
gamemodes\base\entities\entities\base_entity\shared.lua
gamemodes\base\entities\entities\prop_effect.lua
gamemodes\base\entities\effects\base.lua
gamemodes\base\entities\effects\dof_node.lua
gamemodes\base\gamemode\cl_init.lua
gamemodes\base\gamemode\shared.lua
gamemodes\base\gamemode\cl_scoreboard.lua
gamemodes\base\gamemode\cl_targetid.lua
gamemodes\base\gamemode\cl_hudpickup.lua
gamemodes\base\gamemode\cl_spawnmenu.lua
gamemodes\base\gamemode\cl_deathnotice.lua
gamemodes\base\gamemode\cl_pickteam.lua
gamemodes\base\gamemode\cl_voice.lua
gamemodes\base\gamemode\gravitygun.lua
gamemodes\base\gamemode\player_shd.lua
gamemodes\base\gamemode\animations.lua
gamemodes\base\gamemode\obj_player_extend.lua

21
gamemodes/darkrp/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Alexander Grist-Hucker, Igor Radovanovic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,45 @@
Willard Networks - WN:IX
A unique HL2RP schema built by the WN team
Copyright Atko 2023
All Rights Reserved
# Code Style
* General coding style
* Use tab-indentation with tab-width set to 4 spaces!
* Use 'and' and 'or', rather than '&&' or '||'. For negation the '!' is used over 'not'
* We use 'if (condition) then' for spacing, as well as 'func(arg1, arg2, arg3, ...)'. Arrays use array[index], except for double indexing in which case spaces get added array1[ array2[index] ] (to prevent [[ and ]] from forming long strings or comments)
* String concatenation is done without spacing like.."this".."."
* " " has the preference for strings, although ' ' can be used if your string contains a ". [[ ]] can be used for multiline strings, or strings that contain both " and '
* Unused loop variables or return variables are assigned to '\_' to indicate they are unused
* Variable and data fields
* Local vars use lower camel case (lowerCamelCase)
* Functions are upper camel case (UpperCamelCase). Local function vars use lower camel case (as per local var casing)
* Enums are in all caps, with underscores for spacing. This also counts if you make enum fields on a table (e.g. PLUGIN.MAX_VAR)
* Strings for internal use should be UpperCamelCase (data fields, net messages, ...). If some sort of identifiying prefix is used, lower camel casing is used (e.g. ixSendData, cmdCharSetHealth, ...)
* Try to give loop variables sensible names over k, v. E.g. 'for character, data in pairs(list) do', which creates much more readable code than 'for k, v in pairs(list) do'
* Avoid using variable names that overwrite library names.
* 'player' is generally replaced with 'client'
* 'table' should use something more descriptive, or 'tbl' if you really got nothing
* 'string' can use 'text' or 'str'
* Optimization
* Avoid creating and using global variables, the access time on them is extremely slow. The easiest workaround is to localize the variable at the top of the file (if it is a table, the variable will still update as tables are stored by reference rather than by value). Libraries (e.g. ix, math, string, ...) can also be localized like this, and is typically done if you absolutely need to squeeze out performance from some bit of code that will run a lot.
* Avoid using Think, Tick, etc. server-side. Basically any hook that gets called every frame (or even worse: every frame for every player) unless there is absolutely no way around it. A lot of stuff doesn't need to check every frame, but is fine if it checks every 0.5/1/2/... seconds. Use timers for this!
* If you must use Think-like hooks or have another performance critical bit of code:
* Keep it short, shorter code usually is more optimized
* Localize everything in it
* Avoid loops, make loops as small as possible. If you need to loop over a table to search one entry, you may need to rethink your table structure. E.g. looping over a table of all players is slower than looking up a player by SteamID (table[client:SteamID64()]).
* 'for i = 1, x do' is faster than 'for k, v in ipairs', which is faster than 'for k, v in pairs'
* Making tables is expensive compared to clearing out a small table. Array indexing (table[1]) is faster than hashmap lookups (table.x)
* Square roots (sqrt, Distance) and geometry functions (cos, acos, sin, asin, tan, ...) are SLOOOOW (compared to e.g. multiplication)! Avoid them in performance-critical code. Distance can often be replaced by DistToSqr (squared distance) when the goal is simple comparisons to avoid taking a square root (don't forget to square the other side of the comparison). E.g. 'x:Distance(y) > 100' becomes 'x:DistToSqr(y) > 100 * 100'
* Creating functions during runtime is SLOOOOOOOOOOOOOOW, but sometimes needed. Just avoid this happening in code that runs often/regularly. Try to limit it to e.g. character load, or when a player does a certain action. If possible, use a function created during compile and pass the needed arguments via varargs.
* Helix-specific stuff
* Use ix.log.AddType and ix.log.Add rather than ix.log.AddRaw. This creates a category that can be used with our log searching tool, and stores some extra searchable meta-data as well (client, arguments passed, location, ...)
* Categorize your logtypes by proceeding the type with the plugin name or some other descriptive prefix. This facilitates selecting it from the giant dropdown menu in the logsearch tool. E.g. medicalBleedout, itemPickup, ...
* Try to use localized text (via e.g. L(), NotifyLocalized, ...) and define a translation table in your plugin via ix.lang.AddTable. This makes life for our Russian friends a lot easier.
* Server-side only code always should be in an sv_file! This counts double for net hooks, security checks, etc. Any half-decent hacker will read your cl_ and sh_ files to find exploits, do not make their life easier. It is also harder to steal our code if they do not have the server-side code.
## Using the Linter in your IDE
See instructions [here](https://github.com/mpeterv/luacheck#editor-support).
For visual studio, simply downloading the vscode-luacheck plugin should be enough with no additional configuration required.

View File

@@ -0,0 +1,8 @@
"darkrp"
{
"base" "helix"
"title" "DarkRP"
"author" "willard.network"
"category" "rp"
"menusystem" "1"
}

View File

@@ -0,0 +1,245 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
if (!Schema:CanPlayerOpenCombineLock(client, self)) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
self:Toggle(client)
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_blue = Color(52, 73, 94, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_blue
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,295 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock (CMRU)"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock_cmru")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.accessLevel = 1
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
local character = client:GetCharacter()
local items = character:GetInventory():GetItems()
local cmruCards = {}
for _, item in pairs(items) do
if (item.uniqueID == "cmru_card" and item:GetData("cardID")) then
cmruCards[#cmruCards + 1] = item
end
end
local canOpen = false
for _, card in pairs(cmruCards) do
-- access level 5 should open all doors. access level 3 should open only 3, 2, and 1 doors, etc
if (items[card:GetData("cardID")] and (card:GetData("accessLevel", 1) >= self.accessLevel)) then
canOpen = true
end
end
if (!Schema:CanPlayerOpenCombineLock(client, self) and !canOpen) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
if (client:KeyDown(IN_SPEED) and (client:Team() == FACTION_ADMIN or client:Team() == FACTION_SERVERADMIN or client:IsCombine() or client:GetCharacter():HasFlags("M"))) then
net.Start("changeLockAccessCmru")
net.WriteEntity(self)
net.Send(client)
else
self:Toggle(client)
end
end
function ENT:OnOptionSelected(client, option, data)
if (option == "Set Level 1 Access") then
self.accessLevel = 1
client:Notify("Bu kilide Düzey 1 Erişimi'ni ayarladınız.")
elseif (option == "Set Level 2 Access") then
self.accessLevel = 2
client:Notify("Bu kilide Düzey 2 Erişimi'ni ayarladınız.")
elseif (option == "Set Level 3 Access") then
self.accessLevel = 3
client:Notify("Bu kilide Düzey 3 Erişimi'ni ayarladınız.")
elseif (option == "Set Level 4 Access") then
self.accessLevel = 4
client:Notify("Bu kilide Düzey 4 Erişimi'ni ayarladınız.")
elseif (option == "Set Level 5 Access") then
self.accessLevel = 5
client:Notify("Bu kilide Düzey 5 Erişimi'ni ayarladınız.")
end
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_magenta = Color(214, 55, 229, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_magenta
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,295 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock (Conscript)"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock_con")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.accessLevel = 1
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
local character = client:GetCharacter()
local items = character:GetInventory():GetItems()
local conCards = {}
for _, item in pairs(items) do
if (item.uniqueID == "con_card" and item:GetData("cardID")) then
conCards[#conCards + 1] = item
end
end
local canOpen = false
for _, card in pairs(conCards) do
-- access level 5 should open all doors. access level 3 should open only 3, 2, and 1 doors, etc
if (items[card:GetData("cardID")] and (card:GetData("accessLevel", 1) >= self.accessLevel)) then
canOpen = true
end
end
if (!Schema:CanPlayerOpenCombineLock(client, self) and !canOpen) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
if (client:KeyDown(IN_SPEED) and (client:Team() == FACTION_ADMIN or client:Team() == FACTION_SERVERADMIN or client:IsCombine() or client:GetCharacter():HasFlags("M"))) then
net.Start("changeLockAccessCon")
net.WriteEntity(self)
net.Send(client)
else
self:Toggle(client)
end
end
function ENT:OnOptionSelected(client, option, data)
if (option == "Set Level 1 Access") then
self.accessLevel = 1
client:Notify("You have set Level 1 Access to this lock.")
elseif (option == "Set Level 2 Access") then
self.accessLevel = 2
client:Notify("You have set Level 2 Access to this lock.")
elseif (option == "Set Level 3 Access") then
self.accessLevel = 3
client:Notify("You have set Level 3 Access to this lock.")
elseif (option == "Set Level 4 Access") then
self.accessLevel = 4
client:Notify("You have set Level 4 Access to this lock.")
elseif (option == "Set Level 5 Access") then
self.accessLevel = 5
client:Notify("You have set Level 5 Access to this lock.")
end
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_orange = Color(255, 180, 0, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_orange
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,284 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock (CWU)"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock_cwu")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.accessLevel = "Member Access"
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
local character = client:GetCharacter()
local items = character:GetInventory():GetItems()
local cwuCards = {}
for _, item in pairs(items) do
if (item.uniqueID == "cwu_card" and item:GetData("cardID")) then
cwuCards[#cwuCards + 1] = item
end
end
local canOpen = false
for _, cards in pairs(cwuCards) do
local accessLevel = cards:GetData("accessLevel", "Member Access")
if (items[cards:GetData("cardID")] and (accessLevel == "Management Access" or (accessLevel == "Member Access" and self.accessLevel == "Member Access"))) then
canOpen = true
end
end
if (!Schema:CanPlayerOpenCombineLock(client, self) and !canOpen) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
if (client:KeyDown(IN_SPEED) and (client:Team() == FACTION_ADMIN or client:Team() == FACTION_SERVERADMIN or client:IsCombine() or client:GetCharacter():HasFlags("M"))) then
net.Start("changeLockAccess")
net.WriteEntity(self)
net.Send(client)
else
self:Toggle(client)
end
end
function ENT:OnOptionSelected(client, option, data)
if (option == "Set Member Access") then
self.accessLevel = "Member Access"
client:Notify("Bu kilide Üye Erişimi'ni ayarladınız.")
elseif (option == "Set Management Access") then
self.accessLevel = "Management Access"
client:Notify("Yönetim Erişimi'ni bu kilide ayarladınız.")
end
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_blue = Color(37, 64, 213, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_blue
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,284 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock (DOB)"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock_dob")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.accessLevel = "Member Access"
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
local character = client:GetCharacter()
local items = character:GetInventory():GetItems()
local dobCards = {}
for _, item in pairs(items) do
if (item.uniqueID == "dob_card" and item:GetData("cardID")) then
dobCards[#dobCards + 1] = item
end
end
local canOpen = false
for _, cards in pairs(dobCards) do
local accessLevel = cards:GetData("accessLevel", "Member Access")
if (items[cards:GetData("cardID")] and (accessLevel == "Management Access" or (accessLevel == "Member Access" and self.accessLevel == "Member Access"))) then
canOpen = true
end
end
if (!Schema:CanPlayerOpenCombineLock(client, self) and !canOpen) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
if (client:KeyDown(IN_SPEED) and (client:Team() == FACTION_ADMIN or client:Team() == FACTION_SERVERADMIN or client:IsCombine() or client:GetCharacter():HasFlags("M"))) then
net.Start("changeLockAccess")
net.WriteEntity(self)
net.Send(client)
else
self:Toggle(client)
end
end
function ENT:OnOptionSelected(client, option, data)
if (option == "Set Member Access") then
self.accessLevel = "Member Access"
client:Notify("Bu kilide Üye Erişimi'ni ayarladınız.")
elseif (option == "Set Management Access") then
self.accessLevel = "Management Access"
client:Notify("Yönetim Erişimi'ni bu kilide ayarladınız.")
end
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_orange = Color(235, 125, 52, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_orange
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,284 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Combine Lock (MOE)"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.PhysgunDisable = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Bool", 0, "Locked")
self:NetworkVar("Bool", 1, "DisplayError")
self:NetworkVar("Bool", 2, "Disabled")
if (SERVER) then
self:NetworkVarNotify("Locked", self.OnLockChanged)
end
end
if (SERVER) then
function ENT:GetLockPosition(door, normal)
local index = door:LookupBone("handle")
local position = door:GetPos()
normal = normal or door:GetForward():Angle()
if (index and index >= 1) then
position = door:GetBonePosition(index)
end
position = position + normal:Forward() * 7.2 + normal:Up() * 10 + normal:Right() * 2
normal:RotateAroundAxis(normal:Up(), 90)
normal:RotateAroundAxis(normal:Forward(), 180)
normal:RotateAroundAxis(normal:Right(), 180)
return position, normal
end
function ENT:SetDoor(door, position, angles)
if (!IsValid(door) or !door:IsDoor()) then
return
end
local doorPartner = door:GetDoorPartner()
self.door = door
self.door:DeleteOnRemove(self)
door.ixLock = self
if (IsValid(doorPartner)) then
self.doorPartner = doorPartner
self.doorPartner:DeleteOnRemove(self)
doorPartner.ixLock = self
end
self:SetPos(position)
self:SetAngles(angles)
self:SetParent(door)
end
function ENT:SpawnFunction(client, trace)
local door = trace.Entity
if (!IsValid(door) or !door:IsDoor() or IsValid(door.ixLock)) then
return client:NotifyLocalized("dNotValid")
end
local normal = client:GetEyeTrace().HitNormal:Angle()
local position, angles = self:GetLockPosition(door, normal)
local entity = ents.Create("ix_combinelock_moe")
entity:SetPos(trace.HitPos)
entity:Spawn()
entity:Activate()
entity:SetDoor(door, position, angles)
ix.saveEnts:SaveEntity(entity)
Schema:SaveCombineLocks()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props_combine/wn_combine_lock.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self:SetUseType(SIMPLE_USE)
self:SetHealth(300)
self.accessLevel = "Member Access"
self.nextUseTime = 0
end
function ENT:OnRemove()
if (IsValid(self)) then
self:SetParent(nil)
end
if (IsValid(self.door)) then
self.door:Fire("unlock")
self.door.ixLock = nil
end
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
self.doorPartner.ixLock = nil
end
if (!ix.shuttingDown) then
Schema:SaveCombineLocks()
end
end
function ENT:OnLockChanged(name, bWasLocked, bLocked)
if (!IsValid(self.door) or self:GetDisabled()) then
return
end
ix.saveEnts:SaveEntity(self)
if (bLocked) then
self:EmitSound("buttons/combine_button2.wav")
self.door:Fire("lock")
self.door:Fire("close")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("lock")
self.doorPartner:Fire("close")
end
else
self:EmitSound("buttons/combine_button7.wav")
self.door:Fire("unlock")
if (IsValid(self.doorPartner)) then
self.doorPartner:Fire("unlock")
end
end
end
function ENT:DisplayError()
self:EmitSound("buttons/combine_button_locked.wav")
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:DisplayDamage()
self:SetDisplayError(true)
timer.Simple(1.2, function()
if (IsValid(self)) then
self:SetDisplayError(false)
end
end)
end
function ENT:Toggle(client)
if (self:GetDisabled()) then return end
if (self.nextUseTime > CurTime()) then
return
end
local character = client:GetCharacter()
local items = character:GetInventory():GetItems()
local moeCards = {}
for _, item in pairs(items) do
if (item.uniqueID == "moe_card" and item:GetData("cardID")) then
moeCards[#moeCards + 1] = item
end
end
local canOpen = false
for _, cards in pairs(moeCards) do
local accessLevel = cards:GetData("accessLevel", "Member Access")
if (items[cards:GetData("cardID")] and (accessLevel == "Management Access" or (accessLevel == "Member Access" and self.accessLevel == "Member Access"))) then
canOpen = true
end
end
if (!Schema:CanPlayerOpenCombineLock(client, self) and !canOpen) then
self:DisplayError()
self.nextUseTime = CurTime() + 2
return
end
self:SetLocked(!self:GetLocked())
self.nextUseTime = CurTime() + 2
end
function ENT:Use(client)
if (client:KeyDown(IN_SPEED) and (client:Team() == FACTION_ADMIN or client:Team() == FACTION_SERVERADMIN or client:IsCombine() or client:GetCharacter():HasFlags("M"))) then
net.Start("changeLockAccess")
net.WriteEntity(self)
net.Send(client)
else
self:Toggle(client)
end
end
function ENT:OnOptionSelected(client, option, data)
if (option == "Set Member Access") then
self.accessLevel = "Member Access"
client:Notify("Bu kilide Üye Erişimi'ni ayarladınız.")
elseif (option == "Set Management Access") then
self.accessLevel = "Management Access"
client:Notify("Yönetim Erişimi'ni bu kilide ayarladınız.")
end
end
function ENT:OnTakeDamage(dmgInfo)
self:SetHealth(self:Health() - dmgInfo:GetDamage())
self:EmitSound("physics/metal/metal_sheet_impact_hard"..math.random(6, 8)..".wav")
self:DisplayDamage()
if (self:Health() <= 0) then
local pos = self:GetPos()
local curTime = CurTime()
if (!self.nextSpark or self.nextSpark <= curTime) then
local effect = EffectData()
effect:SetStart(pos)
effect:SetOrigin(pos)
effect:SetScale(2)
util.Effect("cball_explode", effect)
self.nextSpark = curTime + 0.1
end
local attacker = dmgInfo:GetAttacker()
self:EmitSound("npc/manhack/gib.wav")
ix.combineNotify:AddImportantNotification("WRN:// Bio-Restrictor failure", nil, attacker:IsPlayer() and attacker, self:GetPos())
ix.item.Spawn("trash_biolock", Vector(self:GetPos().x, self:GetPos().y, self:GetPos().z))
self:Remove()
end
end
else
local glowMaterial = ix.util.GetMaterial("sprites/glow04_noz")
local color_green = Color(0, 255, 0, 255)
local color_magenta = Color(214, 55, 229, 255)
local color_red = Color(255, 50, 50, 255)
function ENT:Draw()
self:DrawModel()
if (self:GetDisabled()) then return end
local color = color_green
if (self:GetDisplayError()) then
color = color_red
elseif (self:GetLocked()) then
color = color_magenta
end
local position = self:GetPos() + self:GetUp() * -8.7 + self:GetForward() * -3.85 + self:GetRight() * -6
render.SetMaterial(glowMaterial)
render.DrawSprite(position, 10, 10, color)
end
end

View File

@@ -0,0 +1,445 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Forcefield"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.RenderGroup = RENDERGROUP_BOTH
ENT.PhysgunDisabled = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Mode")
self:NetworkVar("Entity", 0, "Dummy")
self:NetworkVar("Bool", 0, "Malfunctioning")
end
local MODE_OFFLINE = 1
local MODE_ALLOW_ALL = 2
local MODE_ALLOW_COMBINE = 3
local MODE_ALLOW_COMBINE_INF = 4
if (SERVER) then
function ENT:SpawnFunction(client, trace)
local angles = (client:GetPos() - trace.HitPos):Angle()
angles.p = 0
angles.r = 0
angles:RotateAroundAxis(angles:Up(), 270)
local entity = ents.Create("ix_forcefield")
entity:SetPos(trace.HitPos + Vector(0, 0, 40))
entity:SetAngles(angles:SnapTo("y", 90))
entity:Spawn()
entity:Activate()
Schema:SaveForceFields()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props/forcefield_left.mdl")
self:SetSkin(3)
self:SetSolid(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:PhysicsInit(SOLID_VPHYSICS)
local data = {}
data.start = self:GetPos() + self:GetRight() * -16
data.endpos = self:GetPos() + self:GetRight() * -480
data.filter = self
local trace = util.TraceLine(data)
local angles = self:GetAngles()
angles:RotateAroundAxis(angles:Up(), 90)
self.dummy = ents.Create("prop_physics")
self.dummy:SetModel("models/willardnetworks/props/forcefield_right.mdl")
self.dummy:SetSkin(3)
self.dummy:SetPos(trace.HitPos)
self.dummy:SetAngles(self:GetAngles())
self.dummy:Spawn()
self.dummy.PhysgunDisabled = true
self.dummy:SetCollisionGroup(COLLISION_GROUP_WORLD)
self:DeleteOnRemove(self.dummy)
local verts = {
{pos = Vector(0, 0, -25)},
{pos = Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) + Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) + Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) - Vector(0, 0, 25)},
{pos = Vector(0, 0, -25)}
}
self:PhysicsFromMesh(verts)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:AddSolidFlags(FSOLID_CUSTOMBOXTEST)
self:SetCustomCollisionCheck(true)
self:SetDummy(self.dummy)
physObj = self.dummy:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:SetMoveType(MOVETYPE_NOCLIP)
self:SetMoveType(MOVETYPE_PUSH)
self:MakePhysicsObjectAShadow()
self:SetMode(MODE_OFFLINE)
end
function ENT:StartTouch(entity)
if (!self.buzzer) then
self.buzzer = CreateSound(entity, "ambient/machines/combine_shield_touch_loop1.wav")
self.buzzer:Play()
self.buzzer:ChangeVolume(0.8, 0)
self.buzzer:SetSoundLevel(60)
else
self.buzzer:ChangeVolume(0.8, 0.5)
self.buzzer:Play()
end
self.entities = (self.entities or 0) + 1
end
function ENT:EndTouch(entity)
self.entities = math.max((self.entities or 0) - 1, 0)
if (self.buzzer and self.entities == 0) then
self.buzzer:FadeOut(0.5)
end
end
function ENT:OnRemove()
if (self.buzzer) then
self.buzzer:Stop()
self.buzzer = nil
end
if (!ix.shuttingDown and !self.ixIsSafe) then
Schema:SaveForceFields()
end
end
ENT.MODES = {
{
function(entity)
return false
end,
"field disengaged.",
"disengaged",
3
},
{
function(entity)
if (!entity:IsPlayer()) then return true end
local character = entity:GetCharacter()
if (!character or !character:GetInventory()) then
return true
end
if (!character:GetInventory():HasItem("id_card", {active = true})) then
if character:GetInventory():HasItem("fake_id_card") then
return false
end
if character:IsVortigaunt() and
character:GetCollarItemID() and
ix.item.instances[character:GetCollarItemID()] and
-ix.config.Get("blacklistSCAmount", 40) <= ix.item.instances[character:GetCollarItemID()]:GetData("sterilizedCredits", 0) then
return false
end
return true
else
return false
end
end,
"allow only registered individuals with active ID Card.",
"engaged",
0
},
{
function(entity)
return true
end,
"disallow non-functionary units.",
"restricted",
1
},
{
function(entity)
return true
end,
"disallow non-functionary units (infestation control specific)",
"restricted",
2
}
}
function ENT:Use(activator)
if ((self.nextUse or 0) < CurTime()) then
self.nextUse = CurTime() + 1.5
else
return
end
local bForced = CAMI.PlayerHasAccess(activator, "Helix - Basic Admin Commands", nil) and activator:GetMoveType() == MOVETYPE_NOCLIP
if (activator:HasActiveCombineSuit() or ix.faction.Get(activator:Team()).allowForcefieldControl or bForced) then
self:SetMode(self:GetMode() + 1)
local action = "modified"
if (self:GetMode() > #self.MODES) then
self:SetMode(MODE_OFFLINE)
self:CollisionRulesChanged()
self:SetSkin(self.MODES[1][4])
self.dummy:SetSkin(self.MODES[1][4])
self:EmitSound("npc/turret_floor/die.wav")
else
self:CollisionRulesChanged()
self:SetSkin(self.MODES[self:GetMode()][4])
self.dummy:SetSkin(self.MODES[self:GetMode()][4])
end
self:EmitSound("buttons/combine_button5.wav", 140, 100 + (self:GetMode() - 1) * 15)
activator:ChatPrint("Changed barrier mode to: " .. self.MODES[self:GetMode()][2])
Schema:SaveForceFields()
if (bForced) then return end
ix.combineNotify:AddNotification("NTC:// Containment Field " .. self.MODES[self:GetMode()][3] .. " by " .. activator:GetCombineTag(), nil, activator)
end
end
function ENT:Malfunction()
local bMalfunctioning = self:GetMalfunctioning()
if (!bMalfunctioning) then return end
timer.Simple(math.random(0.2, 1), function()
if (!self:IsValid()) then return end
self:SetMode(MODE_OFFLINE)
self:CollisionRulesChanged()
self:SetSkin(self.MODES[1][4])
self.dummy:SetSkin(self.MODES[1][4])
self:EmitSound("buttons/combine_button5.wav", 65, 100 + (self:GetMode() - 1) * 15)
self:EmitSound("npc/turret_floor/die.wav", 55)
local target = math.random(2) == 1 and self or self:GetDummy()
local vPoint = target:GetPos() + Vector(0, 0, math.random(-10, 100)) + target:GetRight() * (target == self and -10 or 10)
local effectdata = EffectData()
effectdata:SetOrigin(vPoint)
util.Effect("ManhackSparks", effectdata)
if (math.random(2) == 1) then
target = math.random(2) == 1 and self or self:GetDummy()
vPoint = target:GetPos() + Vector(0, 0, math.random(-10, 100)) + target:GetRight() * (target == self and -10 or 10)
effectdata = EffectData()
effectdata:SetOrigin(vPoint)
util.Effect("ManhackSparks", effectdata)
end
self:EmitSound("ambient/energy/zap" .. math.random(1, 9) .. ".wav", 65)
timer.Simple(math.random(1, 5), function()
if (!self:IsValid()) then return end
self:SetMode(math.random(2, 4))
self:CollisionRulesChanged()
self:SetSkin(self.MODES[self:GetMode()][4])
self.dummy:SetSkin(self.MODES[self:GetMode()][4])
self:EmitSound("buttons/combine_button5.wav", 65, 100 + (self:GetMode() - 1) * 15)
self:Malfunction()
end)
end)
end
hook.Add("ShouldCollide", "ix_forcefields", function(a, b)
local entity
local forcefield
if (a:GetClass() == "ix_forcefield") then
entity = b
forcefield = a
elseif (b:GetClass() == "ix_forcefield") then
entity = a
forcefield = b
end
if (IsValid(forcefield)) then
if (IsValid(entity)) then
if (entity:IsPlayer() and (entity:HasActiveCombineSuit() or ix.faction.Get(entity:Team()).allowForcefieldPassage) or entity:GetClass() == "ix_scanner") then
return false
end
if (entity:IsPlayer() and forcefield:GetMode() == MODE_ALLOW_COMBINE_INF and ix.faction.Get(entity:Team()).allowForcefieldInfestationPassage) then
return false
end
local mode = forcefield:GetMode() or MODE_OFFLINE
return istable(forcefield.MODES[mode]) and forcefield.MODES[mode][1](entity)
else
return forcefield:GetMode() != 5
end
end
end)
else
SHIELD_MATERIALS = {
nil,
ix.util.GetMaterial("models/effects/shield_blue"),
ix.util.GetMaterial("models/effects/shield_red"),
ix.util.GetMaterial("models/effects/shield_yellow")
}
function ENT:Initialize()
local data = {}
data.start = self:GetPos() + self:GetRight()*-16
data.endpos = self:GetPos() + self:GetRight()*-480
data.filter = self
local trace = util.TraceLine(data)
self:SetCustomCollisionCheck(true)
self:PhysicsInitConvex({
vector_origin,
Vector(0, 0, 150),
trace.HitPos + Vector(0, 0, 150),
trace.HitPos
})
self.distance = self:GetPos():Distance(trace.HitPos)
end
function ENT:Draw()
self:DrawModel()
if (self:GetMode() == MODE_OFFLINE) then
return
end
local pos = self:GetPos()
local angles = self:GetAngles()
local matrix = Matrix()
matrix:Translate(pos + self:GetUp() * -40)
matrix:Rotate(angles)
render.SetMaterial(SHIELD_MATERIALS[self:GetMode()])
local dummy = self:GetDummy()
if (IsValid(dummy)) then
local dummyPos = dummy:GetPos()
local vertex = self:WorldToLocal(dummyPos)
self:SetRenderBounds(vector_origin, vertex + self:GetUp() * 150)
cam.PushModelMatrix(matrix)
self:DrawShield(vertex)
cam.PopModelMatrix()
matrix:Translate(vertex)
matrix:Rotate(Angle(0, 180, 0))
cam.PushModelMatrix(matrix)
self:DrawShield(vertex)
cam.PopModelMatrix()
end
end
function ENT:DrawShield(vertex)
mesh.Begin(MATERIAL_QUADS, 1)
mesh.Position(vector_origin)
mesh.TexCoord(0, 0, 0)
mesh.AdvanceVertex()
mesh.Position(self:GetUp() * 190)
mesh.TexCoord(0, 0, 3)
mesh.AdvanceVertex()
mesh.Position(vertex + self:GetUp() * 190)
mesh.TexCoord(0, 3, 3)
mesh.AdvanceVertex()
mesh.Position(vertex)
mesh.TexCoord(0, 3, 0)
mesh.AdvanceVertex()
mesh.End()
end
end
properties.Add("ixForcefieldStartMalfunction", {
MenuLabel = "Start Malfunctioning",
Order = 500,
MenuIcon = "icon16/lightning_add.png",
Filter = function(self, entity, client)
if (entity:GetClass() == "ix_forcefield" and !entity:GetMalfunctioning() and CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then return true end
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
entity:SetMalfunctioning(true)
entity:Malfunction()
end
})
properties.Add("ixForcefieldStopMalfunction", {
MenuLabel = "Stop Malfunctioning",
Order = 500,
MenuIcon = "icon16/lightning_delete.png",
Filter = function(self, entity, client)
if (entity:GetClass() == "ix_forcefield" and entity:GetMalfunctioning() and CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then return true end
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
entity:SetMalfunctioning(false)
end
})

View File

@@ -0,0 +1,437 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Hacked Forcefield"
ENT.Category = "HL2 RP"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.RenderGroup = RENDERGROUP_BOTH
ENT.PhysgunDisabled = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Mode")
self:NetworkVar("Entity", 0, "Dummy")
self:NetworkVar("Bool", 0, "Malfunctioning")
end
local MODE_OFFLINE = 1
local MODE_ALLOW_ALL = 2
local MODE_ALLOW_COMBINE = 3
local MODE_ALLOW_COMBINE_INF = 4
if (SERVER) then
function ENT:SpawnFunction(client, trace)
local angles = (client:GetPos() - trace.HitPos):Angle()
angles.p = 0
angles.r = 0
angles:RotateAroundAxis(angles:Up(), 270)
local entity = ents.Create("ix_rebelfield")
entity:SetPos(trace.HitPos + Vector(0, 0, 40))
entity:SetAngles(angles:SnapTo("y", 90))
entity:Spawn()
entity:Activate()
Schema:SaveRebelForceFields()
return entity
end
function ENT:Initialize()
self:SetModel("models/willardnetworks/props/forcefield_left.mdl")
self:SetSkin(3)
self:SetSolid(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:PhysicsInit(SOLID_VPHYSICS)
local data = {}
data.start = self:GetPos() + self:GetRight() * -16
data.endpos = self:GetPos() + self:GetRight() * -480
data.filter = self
local trace = util.TraceLine(data)
local angles = self:GetAngles()
angles:RotateAroundAxis(angles:Up(), 90)
self.dummy = ents.Create("prop_physics")
self.dummy:SetModel("models/willardnetworks/props/forcefield_right.mdl")
self.dummy:SetSkin(3)
self.dummy:SetPos(trace.HitPos)
self.dummy:SetAngles(self:GetAngles())
self.dummy:Spawn()
self.dummy.PhysgunDisabled = true
self.dummy:SetCollisionGroup(COLLISION_GROUP_WORLD)
self:DeleteOnRemove(self.dummy)
local verts = {
{pos = Vector(0, 0, -25)},
{pos = Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) + Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) + Vector(0, 0, 150)},
{pos = self:WorldToLocal(self.dummy:GetPos()) - Vector(0, 0, 25)},
{pos = Vector(0, 0, -25)}
}
self:PhysicsFromMesh(verts)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:AddSolidFlags(FSOLID_CUSTOMBOXTEST)
self:SetCustomCollisionCheck(true)
self:SetDummy(self.dummy)
physObj = self.dummy:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(false)
physObj:Sleep()
end
self:SetMoveType(MOVETYPE_NOCLIP)
self:SetMoveType(MOVETYPE_PUSH)
self:MakePhysicsObjectAShadow()
self:SetMode(MODE_OFFLINE)
end
function ENT:StartTouch(entity)
if (!self.buzzer) then
self.buzzer = CreateSound(entity, "ambient/machines/combine_shield_touch_loop1.wav")
self.buzzer:Play()
self.buzzer:ChangeVolume(0.8, 0)
self.buzzer:SetSoundLevel(60)
else
self.buzzer:ChangeVolume(0.8, 0.5)
self.buzzer:Play()
end
self.entities = (self.entities or 0) + 1
end
function ENT:EndTouch(entity)
self.entities = math.max((self.entities or 0) - 1, 0)
if (self.buzzer and self.entities == 0) then
self.buzzer:FadeOut(0.5)
end
end
function ENT:OnRemove()
if (self.buzzer) then
self.buzzer:Stop()
self.buzzer = nil
end
if (!ix.shuttingDown and !self.ixIsSafe) then
Schema:SaveRebelForceFields()
end
end
ENT.MODES = {
{
function(entity)
return false
end,
"field disengaged.",
"disengaged",
3
},
{
function(entity)
if (!entity:IsPlayer()) then return true end
local character = entity:GetCharacter()
if (!character or !character:GetInventory()) then
return true
end
if (!character:GetInventory():HasItem("id_card", {active = true})) then
if character:IsVortigaunt() and
character:GetCollarItemID() and
ix.item.instances[character:GetCollarItemID()] and
-ix.config.Get("blacklistSCAmount", 40) <= ix.item.instances[character:GetCollarItemID()]:GetData("sterilizedCredits", 0) then
return false
end
return false
else
return false
end
end,
"allow all individuals",
"engaged",
0
},
{
function(entity)
return true
end,
"disallow combine forces.",
"restricted",
1
},
{
function(entity)
return true
end,
"disallow non-functionary units (Unused Variant... ignore and change!!!)",
"restricted",
2
}
}
function ENT:Use(activator)
if ((self.nextUse or 0) < CurTime()) then
self.nextUse = CurTime() + 1.5
else
return
end
local bForced = CAMI.PlayerHasAccess(activator, "Helix - Basic Admin Commands", nil) and activator:GetMoveType() == MOVETYPE_NOCLIP
if (activator:GetCharacter():HasFlags("F") or bForced) then
self:SetMode(self:GetMode() + 1)
local action = "modified"
if (self:GetMode() > #self.MODES) then
self:SetMode(MODE_OFFLINE)
self:CollisionRulesChanged()
self:SetSkin(self.MODES[1][4])
self.dummy:SetSkin(self.MODES[1][4])
self:EmitSound("npc/turret_floor/die.wav")
else
self:CollisionRulesChanged()
self:SetSkin(self.MODES[self:GetMode()][4])
self.dummy:SetSkin(self.MODES[self:GetMode()][4])
end
self:EmitSound("buttons/combine_button5.wav", 140, 100 + (self:GetMode() - 1) * 15)
activator:ChatPrint("Changed barrier mode to: " .. self.MODES[self:GetMode()][2])
Schema:SaveRebelForceFields()
if (bForced) then return end
end
end
function ENT:Malfunction()
local bMalfunctioning = self:GetMalfunctioning()
if (!bMalfunctioning) then return end
timer.Simple(math.random(0.2, 1), function()
if (!self:IsValid()) then return end
self:SetMode(MODE_OFFLINE)
self:CollisionRulesChanged()
self:SetSkin(self.MODES[1][4])
self.dummy:SetSkin(self.MODES[1][4])
self:EmitSound("buttons/combine_button5.wav", 65, 100 + (self:GetMode() - 1) * 15)
self:EmitSound("npc/turret_floor/die.wav", 55)
local target = math.random(2) == 1 and self or self:GetDummy()
local vPoint = target:GetPos() + Vector(0, 0, math.random(-10, 100)) + target:GetRight() * (target == self and -10 or 10)
local effectdata = EffectData()
effectdata:SetOrigin(vPoint)
util.Effect("ManhackSparks", effectdata)
if (math.random(2) == 1) then
target = math.random(2) == 1 and self or self:GetDummy()
vPoint = target:GetPos() + Vector(0, 0, math.random(-10, 100)) + target:GetRight() * (target == self and -10 or 10)
effectdata = EffectData()
effectdata:SetOrigin(vPoint)
util.Effect("ManhackSparks", effectdata)
end
self:EmitSound("ambient/energy/zap" .. math.random(1, 9) .. ".wav", 65)
timer.Simple(math.random(1, 5), function()
if (!self:IsValid()) then return end
self:SetMode(math.random(2, 4))
self:CollisionRulesChanged()
self:SetSkin(self.MODES[self:GetMode()][4])
self.dummy:SetSkin(self.MODES[self:GetMode()][4])
self:EmitSound("buttons/combine_button5.wav", 65, 100 + (self:GetMode() - 1) * 15)
self:Malfunction()
end)
end)
end
hook.Add("ShouldCollide", "ix_rebelfields", function(a, b)
local entity
local forcefield
if (a:GetClass() == "ix_rebelfield") then
entity = b
forcefield = a
elseif (b:GetClass() == "ix_rebelfield") then
entity = a
forcefield = b
end
if (IsValid(forcefield)) then
if (IsValid(entity)) then
if (entity:IsPlayer() and ix.faction.Get(entity:Team()).allowRebelForcefieldPassage) then
return false
end
local mode = forcefield:GetMode() or MODE_OFFLINE
return istable(forcefield.MODES[mode]) and forcefield.MODES[mode][1](entity)
else
return forcefield:GetMode() != 5
end
end
end)
else
SHIELD_MATERIALS = {
nil,
ix.util.GetMaterial("models/effects/shield_blue"),
ix.util.GetMaterial("models/effects/shield_red"),
ix.util.GetMaterial("models/effects/shield_yellow")
}
function ENT:Initialize()
local data = {}
data.start = self:GetPos() + self:GetRight()*-16
data.endpos = self:GetPos() + self:GetRight()*-480
data.filter = self
local trace = util.TraceLine(data)
self:SetCustomCollisionCheck(true)
self:PhysicsInitConvex({
vector_origin,
Vector(0, 0, 150),
trace.HitPos + Vector(0, 0, 150),
trace.HitPos
})
self.distance = self:GetPos():Distance(trace.HitPos)
end
function ENT:Draw()
self:DrawModel()
if (self:GetMode() == MODE_OFFLINE) then
return
end
local pos = self:GetPos()
local angles = self:GetAngles()
local matrix = Matrix()
matrix:Translate(pos + self:GetUp() * -40)
matrix:Rotate(angles)
render.SetMaterial(SHIELD_MATERIALS[self:GetMode()])
local dummy = self:GetDummy()
if (IsValid(dummy)) then
local dummyPos = dummy:GetPos()
local vertex = self:WorldToLocal(dummyPos)
self:SetRenderBounds(vector_origin, vertex + self:GetUp() * 150)
cam.PushModelMatrix(matrix)
self:DrawShield(vertex)
cam.PopModelMatrix()
matrix:Translate(vertex)
matrix:Rotate(Angle(0, 180, 0))
cam.PushModelMatrix(matrix)
self:DrawShield(vertex)
cam.PopModelMatrix()
end
end
function ENT:DrawShield(vertex)
mesh.Begin(MATERIAL_QUADS, 1)
mesh.Position(vector_origin)
mesh.TexCoord(0, 0, 0)
mesh.AdvanceVertex()
mesh.Position(self:GetUp() * 190)
mesh.TexCoord(0, 0, 3)
mesh.AdvanceVertex()
mesh.Position(vertex + self:GetUp() * 190)
mesh.TexCoord(0, 3, 3)
mesh.AdvanceVertex()
mesh.Position(vertex)
mesh.TexCoord(0, 3, 0)
mesh.AdvanceVertex()
mesh.End()
end
end
properties.Add("ixRebelfieldStartMalfunction", {
MenuLabel = "Start Malfunctioning",
Order = 500,
MenuIcon = "icon16/lightning_add.png",
Filter = function(self, entity, client)
if (entity:GetClass() == "ix_rebelfield" and !entity:GetMalfunctioning() and CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then return true end
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
entity:SetMalfunctioning(true)
entity:Malfunction()
end
})
properties.Add("ixRebelfieldStopMalfunction", {
MenuLabel = "Stop Malfunctioning",
Order = 500,
MenuIcon = "icon16/lightning_delete.png",
Filter = function(self, entity, client)
if (entity:GetClass() == "ix_rebelfield" and entity:GetMalfunctioning() and CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands", nil)) then return true end
end,
Action = function(self, entity)
self:MsgStart()
net.WriteEntity(entity)
self:MsgEnd()
end,
Receive = function(self, length, client)
local entity = net.ReadEntity()
if (!IsValid(entity)) then return end
if (!self:Filter(entity, client)) then return end
entity:SetMalfunctioning(false)
end
})

View File

@@ -0,0 +1,346 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
-- Variables that are used on both client and server
SWEP.PrintName = "Tool Gun"
SWEP.Author = ""
SWEP.Contact = ""
SWEP.Purpose = ""
SWEP.Instructions = ""
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
SWEP.UseHands = true
SWEP.Spawnable = true
-- Be nice, precache the models
util.PrecacheModel( SWEP.ViewModel )
util.PrecacheModel( SWEP.WorldModel )
-- Todo, make/find a better sound.
-- SWEP.ShootSound = Sound( "Airboat.FireGunRevDown" )
SWEP.ShootSound = Sound( "" )
SWEP.Tool = {}
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.CanHolster = true
SWEP.CanDeploy = true
function SWEP:InitializeTools()
local temp = {}
for k,v in pairs( self.Tool ) do
temp[k] = table.Copy( v )
temp[k].SWEP = self
temp[k].Owner = self.Owner
temp[k].Weapon = self.Weapon
temp[k]:Init()
end
self.Tool = temp
end
function SWEP:SetupDataTables()
self:NetworkVar( "Entity", 0, "TargetEntity1" )
self:NetworkVar( "Entity", 1, "TargetEntity2" )
self:NetworkVar( "Entity", 2, "TargetEntity3" )
self:NetworkVar( "Entity", 3, "TargetEntity4" )
end
-- Convenience function to check object limits
function SWEP:CheckLimit( str )
return self:GetOwner():CheckLimit( str )
end
function SWEP:Initialize()
self:SetHoldType( "revolver" )
self:InitializeTools()
-- We create these here. The problem is that these are meant to be constant values.
-- in the toolmode they're not because some tools can be automatic while some tools aren't.
-- Since this is a global table it's shared between all instances of the gun.
-- By creating new tables here we're making it so each tool has its own instance of the table
-- So changing it won't affect the other tools.
self.Primary = {
ClipSize = -1,
DefaultClip = -1,
Automatic = false,
Ammo = "none"
}
self.Secondary = {
ClipSize = -1,
DefaultClip = -1,
Automatic = false,
Ammo = "none"
}
end
function SWEP:OnRestore()
self:InitializeTools()
end
function SWEP:Precache()
util.PrecacheSound( self.ShootSound )
end
function SWEP:Reload()
-- This makes the reload a semi-automatic thing rather than a continuous thing
if ( !self.Owner:KeyPressed( IN_RELOAD ) ) then return end
local mode = self:GetMode()
local trace = self.Owner:GetEyeTrace()
if ( !trace.Hit ) then return end
local tool = self:GetToolObject()
if ( !tool ) then return end
tool:CheckObjects()
-- Does the server setting say it's ok?
if ( !tool:Allowed() ) then return end
-- Ask the gamemode if it's ok to do this
if ( !gamemode.Call( "CanTool", self.Owner, trace, mode ) ) then return end
if ( !tool:Reload( trace ) ) then return end
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
end
-- Returns the mode we're in
function SWEP:GetMode()
return self.Mode
end
-- Think does stuff every frame
function SWEP:Think()
self.Mode = self.Owner:GetInfo( "gmod_toolmode" )
local tool = self:GetToolObject()
if ( !tool ) then return end
tool:CheckObjects()
self.last_mode = self.current_mode
self.current_mode = self.Mode
-- Release ghost entities if we're not allowed to use this new mode?
if ( !tool:Allowed() ) then
self:GetToolObject( self.last_mode ):ReleaseGhostEntity()
return
end
if ( self.last_mode != self.current_mode ) then
if ( !self:GetToolObject( self.last_mode ) ) then return end
-- We want to release the ghost entity just in case
self:GetToolObject( self.last_mode ):Holster()
end
self.Primary.Automatic = tool.LeftClickAutomatic or false
self.Secondary.Automatic = tool.RightClickAutomatic or false
self.RequiresTraceHit = tool.RequiresTraceHit or true
tool:Think()
end
-- The shoot effect
function SWEP:DoShootEffect( hitpos, hitnormal, entity, physbone, bFirstTimePredicted )
self:EmitSound( self.ShootSound )
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) -- View model animation
-- There's a bug with the model that's causing a muzzle to
-- appear on everyone's screen when we fire this animation.
self.Owner:SetAnimation( PLAYER_ATTACK1 ) -- 3rd Person Animation
if ( !bFirstTimePredicted ) then return end
--[[
local effectdata = EffectData()
effectdata:SetOrigin( hitpos )
effectdata:SetNormal( hitnormal )
effectdata:SetEntity( entity )
effectdata:SetAttachment( physbone )
util.Effect( "selection_indicator", effectdata )
local effectdata = EffectData()
effectdata:SetOrigin( hitpos )
effectdata:SetStart( self.Owner:GetShootPos() )
effectdata:SetAttachment( 1 )
effectdata:SetEntity( self )
util.Effect( "ToolTracer", effectdata )
--]]
end
if (SERVER) then
ix.log.AddType("toolgunFired", function(client, name)
return string.format("%s has fired a toolgun with the name: %s", client:GetName(), name)
end)
end
-- Trace a line then send the result to a mode function
function SWEP:PrimaryAttack()
local mode = self:GetMode()
local tr = util.GetPlayerTrace( self.Owner )
tr.mask = bit.bor( CONTENTS_SOLID, CONTENTS_MOVEABLE, CONTENTS_MONSTER, CONTENTS_WINDOW, CONTENTS_DEBRIS, CONTENTS_GRATE, CONTENTS_AUX )
local trace = util.TraceLine( tr )
if ( !trace.Hit ) then return end
local tool = self:GetToolObject()
if ( !tool ) then return end
tool:CheckObjects()
-- Does the server setting say it's ok?
if ( !tool:Allowed() ) then return end
-- Ask the gamemode if it's ok to do this
if ( !gamemode.Call( "CanTool", self.Owner, trace, mode ) ) then return end
if (SERVER) then
ix.log.Add(self:GetOwner(), "toolgunFired", self:GetMode())
end
if ( !tool:LeftClick( trace ) ) then return end
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
end
function SWEP:SecondaryAttack()
local mode = self:GetMode()
local tr = util.GetPlayerTrace( self.Owner )
tr.mask = bit.bor( CONTENTS_SOLID, CONTENTS_MOVEABLE, CONTENTS_MONSTER, CONTENTS_WINDOW, CONTENTS_DEBRIS, CONTENTS_GRATE, CONTENTS_AUX )
local trace = util.TraceLine( tr )
if ( !trace.Hit ) then return end
local tool = self:GetToolObject()
if ( !tool ) then return end
tool:CheckObjects()
-- Ask the gamemode if it's ok to do this
if ( !tool:Allowed() ) then return end
if ( !gamemode.Call( "CanTool", self.Owner, trace, mode ) ) then return end
if ( !tool:RightClick( trace ) ) then return end
self:DoShootEffect( trace.HitPos, trace.HitNormal, trace.Entity, trace.PhysicsBone, IsFirstTimePredicted() )
end
function SWEP:Holster()
-- Just do what the SWEP wants to do if there's no tool
if ( !self:GetToolObject() ) then return self.CanHolster end
local CanHolster = self:GetToolObject():Holster()
if ( CanHolster ~= nil ) then return CanHolster end
return self.CanHolster
end
-- Delete ghosts here in case the weapon gets deleted all of a sudden somehow
function SWEP:OnRemove()
if ( !self:GetToolObject() ) then return end
self:GetToolObject():ReleaseGhostEntity()
end
-- This will remove any ghosts when a player dies and drops the weapon
function SWEP:OwnerChanged()
if ( !self:GetToolObject() ) then return end
self:GetToolObject():ReleaseGhostEntity()
end
-- Deploy
function SWEP:Deploy()
-- Just do what the SWEP wants to do if there is no tool
if ( !self:GetToolObject() ) then return self.CanDeploy end
self:GetToolObject():UpdateData()
local CanDeploy = self:GetToolObject():Deploy()
if ( CanDeploy ~= nil ) then return CanDeploy end
return self.CanDeploy
end
function SWEP:GetToolObject( tool )
local mode = tool or self:GetMode()
if ( !self.Tool[ mode ] ) then return false end
return self.Tool[ mode ]
end
function SWEP:FireAnimationEvent( pos, ang, event, options )
-- Disables animation based muzzle event
if ( event == 21 ) then return true end
-- Disable thirdperson muzzle flash
if ( event == 5003 ) then return true end
end
include( "stool.lua" )

View File

@@ -0,0 +1,162 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
TOOL.Category = "Render"
TOOL.Name = "#tool.paint.name"
TOOL.LeftClickAutomatic = true
TOOL.RightClickAutomatic = true
TOOL.RequiresTraceHit = true
TOOL.ClientConVar[ "decal" ] = "Blood"
TOOL.Information = {
{ name = "left" },
{ name = "right" },
{ name = "reload" }
}
local function PlaceDecal( ply, ent, data )
if ( !IsValid( ent ) && !ent:IsWorld() ) then return end
local bone = ent:GetPhysicsObjectNum( data.bone or 0 )
if ( !IsValid( bone ) ) then bone = ent end
if ( SERVER ) then
util.Decal( data.decal, bone:LocalToWorld( data.Pos1 ), bone:LocalToWorld( data.Pos2 ), ply )
local i = ent.DecalCount or 0
i = i + 1
duplicator.StoreEntityModifier( ent, "decal" .. i, data )
ent.DecalCount = i
end
end
--
-- Register decal duplicator
--
for i = 1, 32 do
duplicator.RegisterEntityModifier( "decal" .. i, function( ply, ent, data )
timer.Simple( i * 0.05, function() PlaceDecal( ply, ent, data ) end )
end )
end
function TOOL:Reload( trace )
if ( !IsValid( trace.Entity ) ) then return false end
trace.Entity:RemoveAllDecals()
if ( SERVER ) then
for i = 1, 32 do
duplicator.ClearEntityModifier( trace.Entity, "decal" .. i )
end
trace.Entity.DecalCount = nil
end
return true
end
function TOOL:LeftClick( trace )
return self:RightClick( trace, true )
end
function TOOL:RightClick( trace, bNoDelay )
local decal = self:GetClientInfo( "decal" )
local Pos1 = trace.HitPos + trace.HitNormal
local Pos2 = trace.HitPos - trace.HitNormal
local Bone = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone or 0 )
if ( !IsValid( Bone ) ) then Bone = trace.Entity end
Pos1 = Bone:WorldToLocal( Pos1 )
Pos2 = Bone:WorldToLocal( Pos2 )
PlaceDecal( self:GetOwner(), trace.Entity, { Pos1 = Pos1, Pos2 = Pos2, bone = trace.PhysicsBone, decal = decal } )
if ( bNoDelay ) then
self:GetWeapon():SetNextPrimaryFire( CurTime() + 0.05 )
self:GetWeapon():SetNextSecondaryFire( CurTime() + 0.05 )
else
self:GetWeapon():SetNextPrimaryFire( CurTime() + 0.2 )
self:GetWeapon():SetNextSecondaryFire( CurTime() + 0.2 )
end
return false
end
game.AddDecal( "Eye", "decals/eye" )
game.AddDecal( "Dark", "decals/dark" )
game.AddDecal( "Smile", "decals/smile" )
game.AddDecal( "Light", "decals/light" )
game.AddDecal( "Cross", "decals/cross" )
game.AddDecal( "Nought", "decals/nought" )
game.AddDecal( "Noughtsncrosses", "decals/noughtsncrosses" )
list.Add( "PaintMaterials", "Eye" )
list.Add( "PaintMaterials", "Smile" )
list.Add( "PaintMaterials", "Light" )
list.Add( "PaintMaterials", "Dark" )
list.Add( "PaintMaterials", "Blood" )
list.Add( "PaintMaterials", "YellowBlood" )
list.Add( "PaintMaterials", "Impact.Metal" )
list.Add( "PaintMaterials", "Scorch" )
list.Add( "PaintMaterials", "BeerSplash" )
list.Add( "PaintMaterials", "ExplosiveGunshot" )
list.Add( "PaintMaterials", "BirdPoop" )
list.Add( "PaintMaterials", "PaintSplatPink" )
list.Add( "PaintMaterials", "PaintSplatGreen" )
list.Add( "PaintMaterials", "PaintSplatBlue" )
list.Add( "PaintMaterials", "ManhackCut" )
list.Add( "PaintMaterials", "FadingScorch" )
list.Add( "PaintMaterials", "Antlion.Splat" )
list.Add( "PaintMaterials", "Splash.Large" )
list.Add( "PaintMaterials", "BulletProof" )
list.Add( "PaintMaterials", "GlassBreak" )
list.Add( "PaintMaterials", "Impact.Sand" )
list.Add( "PaintMaterials", "Impact.BloodyFlesh" )
list.Add( "PaintMaterials", "Impact.Antlion" )
list.Add( "PaintMaterials", "Impact.Glass" )
list.Add( "PaintMaterials", "Impact.Wood" )
list.Add( "PaintMaterials", "Impact.Concrete" )
list.Add( "PaintMaterials", "Noughtsncrosses" )
list.Add( "PaintMaterials", "Nought" )
list.Add( "PaintMaterials", "Cross" )
function TOOL.BuildCPanel( CPanel )
-- Remove duplicates.
local Options = {}
for id, str in pairs( list.Get( "PaintMaterials" ) ) do
if ( !table.HasValue( Options, str ) ) then
table.insert( Options, str )
end
end
table.sort( Options )
local listbox = CPanel:AddControl( "ListBox", { Label = "#tool.paint.texture", Height = 17 + table.Count( Options ) * 17 } )
for k, decal in pairs( Options ) do
local line = listbox:AddLine( decal )
line.data = { paint_decal = decal }
if ( GetConVarString( "paint_decal" ) == tostring( decal ) ) then line:SetSelected( true ) end
end
end

View File

@@ -0,0 +1,105 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
TOOL.Category = "HL2RP Staff QoL"
TOOL.Name = "NPC Spawner Editor"
TOOL.RequiresTraceHit = true
TOOL.Information = {
{ name = "left" },
{ name = "right" },
{ name = "reload" }
}
function TOOL:GetPlayerBoundsTrace()
local client = self:GetOwner()
return util.TraceLine({
start = client:GetShootPos(),
endpos = client:GetShootPos() + client:GetForward() * 96,
filter = client
})
end
function TOOL:LeftClick( trace )
if (SERVER) then
if !CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") then return false end
local entity = trace.Entity
if !entity or entity and !IsValid(entity) then return end
if !self.GetOwner then return end
if !self:GetOwner() then return end
if !IsValid(self:GetOwner()) then return end
if entity:GetClass() != "ix_npcspawner" then return end
entity:Use(self:GetOwner())
end
end
function TOOL:RightClick( trace )
local entity = trace.Entity
local client = self:GetOwner()
if !entity or entity and !IsValid(entity) then
client.npcEditStart = nil
client.npcEnt = nil
return
end
if !self.GetOwner then return end
if !self:GetOwner() then return end
if !IsValid(self:GetOwner()) then return end
if entity:GetClass() != "ix_npcspawner" then return end
if client.npcEditStart then
client.npcEditStart = nil
client.npcEnt = nil
else
client.npcEditStart = entity:GetPos() + (entity:GetForward() * -60 + entity:GetRight()*-40 + entity:GetUp()*128)
client.npcEnt = entity
end
end
function TOOL:Reload(trace)
local client = self:GetOwner()
if !CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") then return false end
if !self.GetOwner then return end
if !self:GetOwner() then return end
if !IsValid(self:GetOwner()) then return end
if !client.npcEditStart or !client.npcEnt then return end
local tr = util.TraceLine({
start = client:GetShootPos(),
endpos = client:GetShootPos() + client:GetForward() * 96,
filter = client
})
client.npcEnt:SetSpawnPosStart(client.npcEditStart)
client.npcEnt:SetSpawnPosEnd(tr.HitPos)
client.npcEditStart = nil
client.npcEnt = nil
end
if CLIENT then
hook.Add("PostDrawTranslucentRenderables", "NPCSpawnEdit", function(bDepth, bSkybox)
if ( bSkybox ) then return end
if LocalPlayer().npcEditStart then
local tr = util.TraceLine({
start = LocalPlayer():GetShootPos(),
endpos = LocalPlayer():GetShootPos() + LocalPlayer():GetForward() * 96,
filter = LocalPlayer()
})
local center, min, max = LocalPlayer().npcEnt:SpawnAreaPosition(LocalPlayer().npcEditStart, tr.HitPos)
local color = Color(255, 255, 255, 255)
render.DrawWireframeBox(center, angle_zero, min, max, color)
end
end)
language.Add( "Tool.sh_npcspawnedit.name", "NPC Spawner Configurator" )
language.Add( "Tool.sh_npcspawnedit.desc", "You can edit NPC spawner entities with it." )
language.Add( "Tool.sh_npcspawnedit.left", "Open spawner menu" )
language.Add( "Tool.sh_npcspawnedit.right", "Edit spawner area bounds. Click again to stop changing bounds." )
language.Add( "Tool.sh_npcspawnedit.reload", "Save your area bound changes." )
end

View File

@@ -0,0 +1,74 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
TOOL.Category = "HL2RP Staff QoL"
TOOL.Name = "Panel Add"
TOOL.RequiresTraceHit = true
TOOL.ClientConVar[ "url" ] = ""
TOOL.ClientConVar[ "scale" ] = 1
TOOL.ClientConVar[ "brightness" ] = 100
TOOL.Information = {
{ name = "left" },
{ name = "right" },
{ name = "reload" }
}
function TOOL:LeftClick( trace )
if (SERVER) then
if !CAMI.PlayerHasAccess(self:GetOwner(), "Helix - Manage Panels") then return false end
local position = trace.HitPos
local angles = trace.HitNormal:Angle()
angles:RotateAroundAxis(angles:Up(), 90)
angles:RotateAroundAxis(angles:Forward(), 90)
if !ix.plugin.list then return end
if !ix.plugin.list["3dpanel"] then return end
if !ix.plugin.list["3dpanel"].AddPanel then return end
local url = self:GetClientInfo( "url", "" )
local scale = self:GetClientNumber( "scale", 0 )
local brightness = self:GetClientNumber( "brightness", 0 )
ix.plugin.list["3dpanel"]:AddPanel(position + angles:Up() * 0.1, angles, url, scale, brightness)
return "@panelAdded"
end
end
function TOOL:RightClick( trace )
if !ix.plugin.list then return end
if !ix.plugin.list["3dpanel"] then return end
if !ix.plugin.list["3dpanel"].RemovePanel then return end
local position = trace.HitPos
-- Remove the panel(s) and get the amount removed.
local amount = ix.plugin.list["3dpanel"]:RemovePanel(position, false)
return "@panelRemoved", amount
end
function TOOL.BuildCPanel( CPanel )
CPanel:AddControl( "Header", { Description = "Enter URL!" } )
CPanel:AddControl( "textbox", { Label = "URL", Command = "sh_paneladd_url", Help = false } )
CPanel:AddControl( "Slider", { Label = "Scale", Command = "sh_paneladd_scale", Type = "Float", Min = 0.001, Max = 5, Help = false } )
CPanel:AddControl( "Slider", { Label = "Brightness", Command = "sh_paneladd_brightness", Type = "Float", Min = 0, Max = 255, Help = false } )
end
if CLIENT then
language.Add( "Tool.sh_paneladd.name", "Panel Add" )
language.Add( "Tool.sh_paneladd.desc", "Same as /paneladd" )
language.Add( "Tool.sh_paneladd.left", "Primary: Add Panel" )
language.Add( "Tool.sh_paneladd.right", "Right Click: Remove Panel" )
language.Add( "Tool.sh_paneladd.reload", "Nothing." )
end

View File

@@ -0,0 +1,84 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
TOOL.Category = "HL2RP Staff QoL"
TOOL.Name = "Persist"
TOOL.RequiresTraceHit = true
TOOL.Information = {
{ name = "left" },
{ name = "right" },
{ name = "reload" }
}
local function GetRealModel(entity)
return entity:GetClass() == "prop_effect" and entity.AttachedEntity:GetModel() or entity:GetModel()
end
function TOOL:LeftClick( trace )
if (SERVER) then
if !CAMI.PlayerHasAccess(client, "Helix - Basic Admin Commands") then return false end
local entity = trace.Entity
if !entity or entity and !IsValid(entity) then return end
if entity:IsPlayer() or entity:IsVehicle() or entity.bNoPersist then return end
if !self.GetOwner then return end
if !self:GetOwner() then return end
if !IsValid(self:GetOwner()) then return end
if !ix.plugin.list then return end
if !ix.plugin.list["persistence"] then return end
if !ix.plugin.list["persistence"].stored then return end
local lampCount = 0
for _, v in pairs(ix.plugin.list["persistence"].stored) do
if IsValid(v) and v:GetClass() == "gmod_lamp" then
lampCount = lampCount + 1
end
end
if !entity:GetNetVar("Persistent") then
if entity:GetClass() == "gmod_lamp" and lampCount >= ix.config.Get("maxLamps", 1) then
return self:GetOwner():Notify("Max persisted lamps reached.")
end
ix.plugin.list["persistence"].stored[#ix.plugin.list["persistence"].stored + 1] = entity
entity:SetNetVar("Persistent", true)
ix.saveEnts:SaveEntity(entity)
ix.log.Add(self:GetOwner(), "persist", GetRealModel(entity), true)
self:GetOwner():Notify("Bu varlığı kalıcı hale getirdiniz.")
else
for k, v in ipairs(ix.plugin.list["persistence"].stored) do
if (v == entity) then
table.remove(ix.plugin.list["persistence"].stored, k)
break
end
end
entity:SetNetVar("Persistent", false)
ix.saveEnts:DeleteEntity(entity)
ix.log.Add(self:GetOwner(), "persist", GetRealModel(entity), false)
self:GetOwner():Notify("Bu varlığı kalıcı hale getirmediniz.")
end
end
end
if CLIENT then
language.Add( "Tool.sh_persist.name", "Persist" )
language.Add( "Tool.sh_persist.desc", "Same as persist in context menu" )
language.Add( "Tool.sh_persist.left", "Primary: Persist/Unpersist" )
language.Add( "Tool.sh_persist.right", "Nothing." )
language.Add( "Tool.sh_persist.reload", "Nothing." )
end

View File

@@ -0,0 +1,79 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
TOOL.Category = "HL2RP Staff QoL"
TOOL.Name = "Text Add"
TOOL.RequiresTraceHit = true
TOOL.ClientConVar[ "text" ] = ""
TOOL.ClientConVar[ "scale" ] = 1
TOOL.Information = {
{ name = "left" },
{ name = "right" },
{ name = "reload" }
}
function TOOL:LeftClick( trace )
if (SERVER) then
if !CAMI.PlayerHasAccess(self:GetOwner(), "Helix - Basic Admin Commands") then return false end
local position = trace.HitPos
local angles = trace.HitNormal:Angle()
angles:RotateAroundAxis(angles:Up(), 90)
angles:RotateAroundAxis(angles:Forward(), 90)
if !ix.plugin.list then return end
if !ix.plugin.list["3dtext"] then return end
if !ix.plugin.list["3dtext"].AddText then return end
local text = self:GetClientInfo( "text", "" )
local scale = self:GetClientNumber( "scale", 0 )
local index = ix.plugin.list["3dtext"]:AddText(position + angles:Up() * 0.1, angles, text, scale)
undo.Create("ix3dText")
undo.SetPlayer(self:GetOwner())
undo.AddFunction(function()
if (ix.plugin.list["3dtext"]:RemoveTextByID(index)) then
ix.log.Add(self:GetOwner(), "undo3dText")
end
end)
undo.Finish()
return "@textAdded"
end
end
function TOOL:RightClick( trace )
if !ix.plugin.list then return end
if !ix.plugin.list["3dtext"] then return end
if !ix.plugin.list["3dtext"].RemoveText then return end
local position = trace.HitPos + trace.HitNormal * 2
local amount = ix.plugin.list["3dtext"]:RemoveText(position, false)
return "@textRemoved", amount
end
function TOOL.BuildCPanel( CPanel )
CPanel:AddControl( "Header", { Description = "Enter Text!" } )
CPanel:AddControl( "textbox", { Label = "Text", Command = "sh_textadd_text", Help = false } )
CPanel:AddControl( "Slider", { Label = "Scale", Command = "sh_textadd_scale", Type = "Float", Min = 0.001, Max = 5, Help = false } )
end
if CLIENT then
language.Add( "Tool.sh_textadd.name", "Text Add" )
language.Add( "Tool.sh_textadd.desc", "Same as /textadd" )
language.Add( "Tool.sh_textadd.left", "Primary: Add Text" )
language.Add( "Tool.sh_textadd.right", "Right Click: Remove Text." )
language.Add( "Tool.sh_textadd.reload", "Nothing." )
end

View File

@@ -0,0 +1,313 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
if (CLIENT) then
SWEP.PrintName = "CV-2000 Şok Çubuğu"
SWEP.Slot = 0
SWEP.SlotPos = 5
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false
end
SWEP.Category = "HL2 RP"
SWEP.Author = "Chessnut"
SWEP.Instructions = "Primary Fire: Stun.\nALT + Primary Fire: Toggle stun.\nSecondary Fire: Push/Knock."
SWEP.Purpose = "Hitting things and knocking on doors."
SWEP.Drop = false
SWEP.HoldType = "melee"
SWEP.Spawnable = true
SWEP.AdminOnly = true
SWEP.ViewModelFOV = 47
SWEP.ViewModelFlip = false
SWEP.AnimPrefix = "melee"
SWEP.ViewTranslation = 4
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Primary.Damage = 15
SWEP.Primary.Delay = 0.7
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
SWEP.ViewModel = Model("models/weapons/c_stunstick.mdl")
SWEP.WorldModel = Model("models/weapons/w_stunbaton.mdl")
SWEP.UseHands = true
SWEP.LowerAngles = Angle(15, -10, -20)
SWEP.FireWhenLowered = true
function SWEP:SetupDataTables()
self:NetworkVar("Bool", 0, "Activated")
end
function SWEP:Precache()
util.PrecacheSound("physics/wood/wood_crate_impact_hard3.wav")
end
function SWEP:Initialize()
self:SetHoldType(self.HoldType)
end
function SWEP:OnRaised()
self.lastRaiseTime = CurTime()
end
function SWEP:OnLowered()
self:SetActivated(false)
end
function SWEP:Holster(nextWep)
self:OnLowered()
return true
end
local STUNSTICK_GLOW_MATERIAL2 = Material("effects/blueflare1")
local STUNSTICK_GLOW_MATERIAL_NOZ = Material("sprites/light_glow02_add_noz")
function SWEP:DrawWorldModel()
self:DrawModel()
if (self:GetActivated()) then
local size = math.Rand(4.0, 6.0)
local glow = math.Rand(0.6, 0.8) * 255
local color = Color(glow / 2, glow / 1.5, glow / 1.1)
local attachment = self:GetAttachment(1)
if (attachment) then
local position = attachment.Pos
render.SetMaterial(STUNSTICK_GLOW_MATERIAL2)
render.DrawSprite(position, size * 2, size * 2, color)
end
end
end
local NUM_BEAM_ATTACHEMENTS = 9
local BEAM_ATTACH_CORE_NAME = "sparkrear"
function SWEP:PostDrawViewModel()
if (!self:GetActivated()) then
return
end
local viewModel = LocalPlayer():GetViewModel()
if (!IsValid(viewModel)) then
return
end
cam.Start3D(EyePos(), EyeAngles())
local size = math.Rand(3.0, 4.0)
local color = Color(75, 100, 150, 50 + math.sin(RealTime() * 2)*20)
STUNSTICK_GLOW_MATERIAL_NOZ:SetFloat("$alpha", color.a / 255)
render.SetMaterial(STUNSTICK_GLOW_MATERIAL_NOZ)
local attachment = viewModel:GetAttachment(viewModel:LookupAttachment(BEAM_ATTACH_CORE_NAME))
if (attachment) then
render.DrawSprite(attachment.Pos, size * 10, size * 15, color)
end
for i = 1, NUM_BEAM_ATTACHEMENTS do
attachment = viewModel:GetAttachment(viewModel:LookupAttachment("spark"..i.."a"))
size = math.Rand(2.5, 5.0)
if (attachment and attachment.Pos) then
render.DrawSprite(attachment.Pos, size, size, color)
end
attachment = viewModel:GetAttachment(viewModel:LookupAttachment("spark"..i.."b"))
size = math.Rand(2.5, 5.0)
if (attachment and attachment.Pos) then
render.DrawSprite(attachment.Pos, size, size, color)
end
end
cam.End3D()
end
function SWEP:PrimaryAttack()
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
if (!self:GetOwner():IsWepRaised()) then
return
end
if (self:GetOwner():KeyDown(IN_WALK)) then
if (SERVER) then
self:SetActivated(!self:GetActivated())
local state = self:GetActivated()
if (state) then
self:GetOwner():EmitSound("Weapon_StunStick.Activate")
else
self:GetOwner():EmitSound("Weapon_StunStick.Deactivate")
end
local model = string.lower(self:GetOwner():GetModel())
if (ix.anim.GetModelClass(model) == "metrocop") then
self:GetOwner():ForceSequence(state and "activatebaton" or "deactivatebaton", nil, nil, true)
end
end
return
end
local result = hook.Run("CanDoMeleeAttack", self)
if (result == false) then
return
end
self:EmitSound("Weapon_StunStick.Swing")
self:SendWeaponAnim(ACT_VM_HITCENTER)
local damage = self.Primary.Damage
if (self:GetActivated()) then
damage = 10
end
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:GetOwner():ViewPunch(Angle(1, 0, 0.125))
self:GetOwner():LagCompensation(true)
local data = {}
data.start = self:GetOwner():GetShootPos()
data.endpos = data.start + self:GetOwner():GetAimVector()*72
data.filter = self:GetOwner()
local trace = util.TraceLine(data)
self:GetOwner():LagCompensation(false)
if (SERVER and trace.Hit) then
if (self:GetActivated()) then
local effect = EffectData()
effect:SetStart(trace.HitPos)
effect:SetNormal(trace.HitNormal)
effect:SetOrigin(trace.HitPos)
util.Effect("StunstickImpact", effect, true, true)
end
self:GetOwner():EmitSound("Weapon_StunStick.Melee_HitWorld")
local entity = trace.Entity
if (IsValid(entity)) then
if (entity:IsPlayer()) then
if (self:GetActivated()) then
entity.ixStuns = (entity.ixStuns or 0) + 1
timer.Simple(10, function()
if (!entity.ixStuns) then return end
entity.ixStuns = math.max(entity.ixStuns - 1, 0)
end)
end
entity:ViewPunch(Angle(-20, math.random(-15, 15), math.random(-10, 10)))
if (self:GetActivated() and entity.ixStuns > 2) then
entity:SetRagdolled(true, 60)
ix.log.Add(entity, "knockedOut", "hit by stunstick owned by "..self:GetOwner():GetName())
entity.ixStuns = 0
return
end
elseif (entity:IsRagdoll()) then
damage = self:GetActivated() and 2 or 10
end
local damageInfo = DamageInfo()
damageInfo:SetAttacker(self:GetOwner())
damageInfo:SetInflictor(self)
damageInfo:SetDamage(damage)
damageInfo:SetDamageType(DMG_CLUB)
damageInfo:SetDamagePosition(trace.HitPos)
damageInfo:SetDamageForce(self:GetOwner():GetAimVector() * 10000)
entity:DispatchTraceAttack(damageInfo, data.start, data.endpos)
end
end
end
function SWEP:SecondaryAttack()
self:GetOwner():LagCompensation(true)
local data = {}
data.start = self:GetOwner():GetShootPos()
data.endpos = data.start + self:GetOwner():GetAimVector()*72
data.filter = self:GetOwner()
data.mins = Vector(-8, -8, -30)
data.maxs = Vector(8, 8, 10)
local trace = util.TraceHull(data)
local entity = trace.Entity
self:GetOwner():LagCompensation(false)
if (SERVER and IsValid(entity)) then
local bPushed = false
if (entity:IsDoor()) then
if (hook.Run("PlayerCanKnockOnDoor", self:GetOwner(), entity) == false) then
return
end
self:GetOwner():ViewPunch(Angle(-1.3, 1.8, 0))
self:GetOwner():EmitSound("physics/wood/wood_crate_impact_hard3.wav")
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:SetNextSecondaryFire(CurTime() + 0.4)
self:SetNextPrimaryFire(CurTime() + 1)
elseif (entity:IsPlayer()) then
local direction = self:GetOwner():GetAimVector() * (300 + (self:GetOwner():GetCharacter():GetAttribute("str", 0) * 3))
direction.z = 0
entity:SetVelocity(direction)
hook.Run("PlayerPushedPlayer", self:GetOwner(), entity)
bPushed = true
else
local physObj = entity:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:SetVelocity(self:GetOwner():GetAimVector() * 180)
end
bPushed = true
end
if (bPushed) then
self:SetNextSecondaryFire(CurTime() + 1.5)
self:SetNextPrimaryFire(CurTime() + 1.5)
self:GetOwner():EmitSound("Weapon_Crossbow.BoltHitBody")
local model = string.lower(self:GetOwner():GetModel())
if (ix.anim.GetModelClass(model) == "metrocop") then
self:GetOwner():ForceSequence("pushplayer")
end
end
end
end

View File

@@ -0,0 +1,12 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
DeriveGamemode("helix")

View File

@@ -0,0 +1,13 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile("cl_init.lua")
DeriveGamemode("helix")

View File

@@ -0,0 +1,35 @@
{
"lint_maxScopeDepth": 20,
"lint_syntaxErrors": true,
"lint_syntaxInconsistencies": true,
"lint_deprecated": true,
"lint_trailingWhitespace": true,
"lint_whitespaceStyle": false,
"lint_beginnerMistakes": true,
"lint_emptyBlocks": true,
"lint_shadowing": true,
"lint_gotos": true,
"lint_doubleNegations": true,
"lint_redundantIfStatements": false,
"lint_redundantParentheses": true,
"lint_duplicateTableKeys": true,
"lint_profanity": true,
"lint_unusedVars": true,
"lint_unusedParameters": false,
"lint_unusedLoopVars": false,
"lint_inconsistentVariableStyle": false,
"lint_ignoreFiles": [],
"prettyprint_spaceAfterParens": false,
"prettyprint_spaceAfterBrackets": false,
"prettyprint_spaceAfterBraces": false,
"prettyprint_spaceEmptyBrackets": true,
"prettyprint_spaceAfterLabel": false,
"prettyprint_spaceBeforeComma": false,
"prettyprint_spaceAfterComma": true,
"prettyprint_semicolons": false,
"prettyprint_cStyle": false,
"prettyprint_rejectInvalidCode": false,
"prettyprint_indentation": " ",
"log_format": "auto"
}

View File

@@ -0,0 +1,131 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.name = "Ambient"
PLUGIN.description = "Ambient Sounds"
PLUGIN.author = "DrodA"
PLUGIN.version = 1.0
ix.option.Add("enableAmbient", ix.type.bool, false, {
category = "Background Music",
OnChanged = function(old_value, new_value)
if (!new_value) then
PLUGIN:StopSound()
return
end
PLUGIN:PlaySound(PLUGIN.ambients[math.random(1, #PLUGIN.ambients)])
end
})
ix.option.Add("ambientVolume", ix.type.number, 0.7, {
category = "Background Music",
min = 0.1, max = 1, decimals = 1,
OnChanged = function(old_value, new_value)
PLUGIN:SetVolume(new_value)
end
})
ix.lang.AddTable("english", {
optAmbientVolume = "Ambiyans müzik düzeyi",
optdAmbientVolume = "Ambiyans müziği ne kadar şiddetli olmalı?",
optEnableAmbient = "Ambiyans müziğini aktifleştir",
optdEnableAmbient = "Ambiyans müziği aktif olmalı mı?"
})
if (SERVER) then return end
local timer_id = "ix_ambient_track"
PLUGIN.ambients = {
{path = "music/passive/passivemusic_01.ogg", length = 85},
{path = "music/passive/passivemusic_02.ogg", length = 130},
{path = "music/passive/passivemusic_03.ogg", length = 95},
{path = "music/passive/passivemusic_04.ogg", length = 125},
{path = "music/passive/passivemusic_05.ogg", length = 215},
{path = "music/passive/passivemusic_06.ogg", length = 210},
{path = "music/passive/passivemusic_07.ogg", length = 245},
{path = "music/passive/passivemusic_08.ogg", length = 268},
{path = "music/passive/passivemusic_09.ogg", length = 150},
{path = "music/passive/passivemusic_10.ogg", length = 260},
{path = "music/passive/passivemusic_11.ogg", length = 340},
{path = "music/passive/passivemusic_12.ogg", length = 260},
{path = "music/passive/passivemusic_13.ogg", length = 440},
{path = "music/passive/passivemusic_14.ogg", length = 130},
{path = "music/passive/passivemusic_15.ogg", length = 130},
{path = "music/passive/passivemusic_16.ogg", length = 250},
{path = "music/passive/passivemusic_17.ogg", length = 270},
{path = "music/passive/passivemusic_18.ogg", length = 320},
{path = "music/passive/passivemusic_19.ogg", length = 100},
{path = "music/passive/passivemusic_20.ogg", length = 210}
}
for _, v in pairs(PLUGIN.ambients) do
util.PrecacheSound(v.path)
end
function PLUGIN:StopSound()
if (timer.Exists(timer_id)) then
timer.Remove(timer_id)
end
if (self.ambient) then
self.ambient:Stop()
self.ambient = nil
end
end
function PLUGIN:SetVolume(volume)
if !self.ambient then return end
self.ambient:ChangeVolume(volume)
end
function PLUGIN:PlaySound(data)
if (!ix.option.Get("enableAmbient")) then
self:StopSound()
return
end
if (timer.Exists(timer_id)) then
self:StopSound()
end
self.ambient = CreateSound(LocalPlayer(), data.path)
self.ambient:Play()
self.ambient:ChangeVolume(ix.option.Get("ambientVolume"), 0)
timer.Create(timer_id, data.length, 1, function()
PLUGIN:StopSound()
timer.Simple(math.random(30, 60), function()
PLUGIN:PlaySound(PLUGIN.ambients[math.random(1, #PLUGIN.ambients)])
end)
end)
end
function PLUGIN:CharacterLoaded(character)
if (!timer.Exists(timer_id) and ix.option.Get("enableAmbient")) then
self:PlaySound(PLUGIN.ambients[math.random(1, #PLUGIN.ambients)])
end
end
function PLUGIN:PostPlaySound(sound, isGlobal)
if (isGlobal) then
self:StopSound()
timer.Simple(SoundDuration(sound) + math.random(30, 60), function()
PLUGIN:PlaySound(PLUGIN.ambients[math.random(1, #PLUGIN.ambients)])
end)
end
end

View File

@@ -0,0 +1,43 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
PLUGIN.name = "Ammo Limit"
PLUGIN.author = "Gr4Ss"
PLUGIN.description = "Limit how much ammo can be loaded from ammo boxes."
ix.lang.AddTable("english", {
ammoLimitReached = "Mevcut mermi limitine ulaştınız!"
})
ix.config.Add("ammoBoxLimit", 4, "The maximum amount of ammo boxes someone is allowed to equip", nil, {
data = {min = 0, max = 10, decimals = 1},
category = "Other"
})
function PLUGIN:CanPlayerInteractItem(client, action, item, data)
if (isentity(item)) then
if (IsValid(item)) then
item = ix.item.instances[item.ixItemID]
else
return
end
elseif (isnumber(item)) then
item = ix.item.instances[item]
end
if (!item) then return end
if (action == "use" and item.ammo and item.ammoAmount and client:GetAmmoCount(item.ammo) >= item.ammoAmount * ix.config.Get("ammoBoxLimit")) then
client:NotifyLocalized("ammoLimitReached")
return false
end
end

View File

@@ -0,0 +1,55 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local chatTypeWhitelist = {
["scoreboard"] = true,
["radio"] = true
}
function PLUGIN:GetHookCallPriority(hook)
if (hook == "GetCharacterName" or hook == "PopulateCharacterInfo") then
return 1500
end
end
function PLUGIN:GetCharacterName(client, chatType)
if (!IsValid(client)) then return end
if (LocalPlayer():IsCombine() or chatTypeWhitelist[chatType]) then return end
if (LocalPlayer():GetMoveType() == MOVETYPE_NOCLIP and !LocalPlayer():InVehicle()) then return end
if (ix.faction.Get(LocalPlayer():Team()).recogniseAll) then return end
if (client:Team() == FACTION_OTA) then
return client:GetCharacter():GetClass() == CLASS_EOW and "Elite Overwatch Soldier" or "Transhuman Arm Soldier"
elseif (client:GetNetVar("combineMaskEquipped")) then
return "Sivil Koruma Birimi"
end
end
function PLUGIN:PopulateCharacterInfo(client, character, container)
if (LocalPlayer():IsCombine() or !client:GetNetVar("combineMaskEquipped") and client:Team() != FACTION_OTA) then return end
timer.Simple(0.1, function()
local description = container:GetRow("description")
if (IsValid(description)) then
description:Remove()
end
local geneticDesc = container:GetRow("geneticDesc")
if (IsValid(geneticDesc)) then
local height = character:GetHeight()
geneticDesc:SetText(height .. " TALL")
end
end)
end

Some files were not shown because too many files have changed in this diff Show More