This commit is contained in:
lifestorm
2024-08-05 18:40:29 +03:00
parent 9f505a0646
commit c6d9b6f580
8044 changed files with 1853472 additions and 21 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

View File

@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2015 Brian Hang, Kyu Yeon Lee
Copyright (c) 2018-2021 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.

72
gamemodes/helix/README.md Normal file
View File

@@ -0,0 +1,72 @@
This is a private branch from the [public helix](https://github.com/nebulousCloud/helix) repository.
In order to keep this repository up to date with any changes made to the public helix repository, you can pull changes from the public repo to your local PC, and then push those changes to our private repository.
Setup the public helix repository as another remote called 'public':
```
git remote add public https://github.com/NebulousCloud/helix.git
```
To pull in changes made on the public repository to your local PC:
```
git pull public master
```
Fix any merge conflicts after pulling changes from the public repository on your local PC. Once all has been merged (or there were no conflicts), you can:
```
git push
```
All commits will now have been nicely added to our private branch (including who made the commit, etc.).
<p align="center">
<img src="https://raw.githubusercontent.com/NebulousCloud/helix/master/docs/banner.gif" alt="Helix" />
</p>
<p align="center">
<a href="https://discord.gg/2AutUcF">
<img src="https://img.shields.io/discord/505957257125691423.svg" alt="Discord" />
</a>
<a href="https://github.com/NebulousCloud/helix/actions">
<img src="https://img.shields.io/github/workflow/status/NebulousCloud/helix/CI" alt="Build Status" />
</a>
</p>
Helix is a framework for roleplay gamemodes in [Garry's Mod](https://gmod.facepunch.com/), based off of [NutScript 1.1](https://github.com/rebel1324/NutScript). Helix provides a stable, feature-filled, open-source, and DRM-free base so you can focus more on the things you want: making gameplay.
## Getting Started
Visit the getting started guide in the [documentation](https://docs.gethelix.co/manual/getting-started/) for an in-depth guide.
If you know what you're doing, a quick start for bootstrapping your own schema is forking/copying the skeleton schema at https://github.com/nebulouscloud/helix-skeleton. The skeleton contains all the important elements you need to have a functioning schema so you can get to coding right away.
You can also use our HL2 RP schema at https://github.com/nebulouscloud/helix-hl2rp as a base to work off of if you need something more fleshed out.
## Plugins
If you'd like to enhance your gamemode, you can use any of the freely provided plugins available at the [Helix Plugin Center](https://plugins.gethelix.co). It is also encouraged to submit your own plugins for others to find and use at https://github.com/nebulouscloud/helix-plugins
## Documentation
Up-to-date documentation can be found at https://docs.gethelix.co. This is automatically updated when commits are pushed to the master branch.
If you'd like to ask some questions or integrate with the community, you can always join our [Discord](https://discord.gg/2AutUcF) server. We highly encourage you to search through the documentation before posting a question - the docs contain a good deal of information about how the various systems in Helix work, and it might explain what you're looking for.
### Building documentation
If you're planning on contributing to the documentation, you'll probably want to preview your changes before you commit. The documentation can be built using [LDoc](https://github.com/impulsh/ldoc) - note that we use a forked version to add some functionality. You'll need [LuaRocks](https://luarocks.org/) installed in order to get started.
```shell
# installing ldoc
git clone https://github.com/impulsh/ldoc
cd ldoc
luarocks make
# navigate to the helix repo folder and run
ldoc .
```
You may not see the syntax highlighting work on your local copy - you'll need to copy the files in `docs/js` and `docs/css` over into the `docs/html` folder after it's done building.
## Contributing
Feel free to submit a pull request with any fixes/changes that you might find beneficial. Currently, there are no solid contributing guidelines other than keeping your code consistent with the rest of the framework.
## Acknowledgements
Helix is a fork of NutScript 1.1 by [Chessnut](https://github.com/brianhang) and [rebel1324](https://github.com/rebel1324).

77
gamemodes/helix/config.ld Normal file
View File

@@ -0,0 +1,77 @@
file = {
"gamemode",
"plugins",
"docs/hooks",
exclude = {"gamemode/core/libs/thirdparty"}
}
module_file = {
Character = "gamemode/core/meta/sh_character.lua",
Entity = "gamemode/core/meta/sh_entity.lua",
Inventory = "gamemode/core/meta/sh_inventory.lua",
Item = "gamemode/core/meta/sh_item.lua",
Player = "gamemode/core/meta/sh_player.lua"
}
dir = "docs/html"
project = "Helix"
title = "Helix Documentation"
no_space_before_args = true
style = "docs/css"
template = "docs/templates"
format = "markdown"
ignore = true
topics = "docs/manual"
use_markdown_titles = true
kind_names = {module = "Libraries", topic = "Manual"}
merge = true
sort = true
sort_modules = true
simple_args_string = true -- we show optionals/defaults outside of the display name
strip_metamethod_prefix = true -- remove the name of the table when displaying metamethod names
no_viewed_topic_at_top = true -- don't put the currently viewed topic at the top
use_new_templates = true -- new templating system
pretty_urls = true -- avoid showing .html in urls
pretty_topic_names = true -- strips extension from manual filenames, this does not check filename collisions
custom_tags = {
{"realm", hidden = true},
{"internal", hidden = true}
}
custom_display_name_handler = function(item, default_handler)
if (item.type == "function" and item.module) then
if (item.module.type == "classmod" or item.module.type == "panel") then
return item.module.mod_name .. ":" .. default_handler(item)
elseif (item.module.type == "hooks") then
return item.module.mod_name:upper() .. ":" .. default_handler(item)
end
end
return default_handler(item)
end
new_type("hooks", "Hooks", true)
new_type("panel", "Panels", true)
-- helix types
tparam_alias("char", "Character")
tparam_alias("inventory", "Inventory")
tparam_alias("item", "Item")
tparam_alias("ixtype", "ix.type")
tparam_alias("date", "date")
-- standard types
tparam_alias("string", "string")
tparam_alias("bool", "boolean")
tparam_alias("func", "function")
tparam_alias("player", "Player")
tparam_alias("entity", "Entity")
tparam_alias("color", "color")
tparam_alias("tab", "table")
tparam_alias("material", "material")
tparam_alias("vector", "vector")
tparam_alias("angle", "angle")

View File

@@ -0,0 +1 @@
GIF89a8h<01>

After

Width:  |  Height:  |  Size: 12 B

View File

@@ -0,0 +1,96 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
color: #333;
}
.hljs-comment,
.hljs-quote {
color: #535346;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,522 @@
:root {
--content-width: 1200px;
--sidebar-width: 330px;
--padding-big: 48px;
--padding-normal: 24px;
--padding-small: 16px;
--padding-tiny: 10px;
--font-massive: 32px;
--font-huge: 24px;
--font-big: 18px;
--font-normal: 16px;
--font-tiny: 12px;
--font-style-normal: Segoe UI, Helvetica, Arial, sans-serif;
--font-style-code: Consolas, monospace;
--color-accent: rgb(115, 53, 142);
--color-accent-dark: rgb(85, 39, 105);
--color-white: rgb(255, 255, 255);
--color-offwhite: rgb(200, 200, 200);
--color-white-accent: rgb(203, 190, 209);
--color-black: rgb(0, 0, 0);
--color-lightgrey: rgb(160, 160, 160);
--color-background-light: rgb(240, 240, 240);
--color-background-dark: rgb(33, 33, 33);
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
background-color: var(--color-background-light);
font-family: var(--font-style-normal);
display: flex;
flex-direction: column;
}
a {
color: inherit;
text-decoration: inherit;
}
h1, h2, h3, h4 {
font-weight: 400;
}
ul li {
margin-left: var(--padding-small);
}
/* landing */
.landing {
background-color: var(--color-accent);
color: var(--color-white);
padding: 128px 0 128px 0;
}
.landing h1 {
margin: 0;
padding: 0;
border: none;
font-weight: 100;
font-size: var(--font-massive);
text-align: center;
}
.wrapper {
padding: var(--padding-small);
}
details {
user-select: none;
}
details summary {
outline: none;
}
code {
font-family: "Source Code Pro", monospace;
font-size: 85%;
white-space: pre;
tab-size: 4;
-moz-tab-size: 4;
padding: 2px 4px;
background-color: rgb(33, 33, 33, 0.1);
}
pre {
background-color: rgb(33, 33, 33, 0.1);
margin-top: var(--padding-small);
padding: var(--padding-tiny);
overflow: auto;
}
pre code {
background-color: transparent;
}
span.realm {
width: 14px;
height: 14px;
border-radius: 3px;
display: inline-block;
margin-right: 6px;
}
span.realm.shared {
background: linear-gradient(45deg, #f80 0%, #f80 50%, #08f 51%, #08f 100%);
}
span.realm.client {
background-color: #f80;
}
span.realm.server {
background-color: #08f;
}
/* wrapper element for sidebar/content */
main {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-start;
width: var(--content-width);
margin: auto;
}
/* sidebar */
nav {
color: var(--color-offwhite);
background-color: var(--color-background-dark);
position: fixed;
display: flex;
flex-direction: column;
width: var(--sidebar-width);
height: 100%;
}
/* sidebar header */
nav header {
color: var(--color-white);
background-color: var(--color-accent);
padding: var(--padding-small);
}
nav header h1 {
font-size: var(--font-huge);
font-weight: 100;
text-align: center;
margin-bottom: var(--padding-small);
}
#search {
background-color: var(--color-accent-dark);
color: var(--color-white);
border: none;
font-size: var(--font-normal);
outline: none;
width: 100%;
padding: 6px;
}
#search::placeholder {
color: var(--color-white-accent);
}
#search::-webkit-search-cancel-button {
display: none;
}
/* sidebar contents */
nav section {
padding: var(--padding-small);
overflow: auto;
}
nav section ul {
list-style-type: none;
}
nav section::-webkit-scrollbar,
pre::-webkit-scrollbar {
width: 8px;
height: 8px;
}
nav section::-webkit-scrollbar-track,
pre::-webkit-scrollbar-track {
background: transparent;
}
nav section::-webkit-scrollbar-thumb {
background-color: var(--color-lightgrey);
}
pre::-webkit-scrollbar-thumb {
background-color: var(--color-lightgrey);
}
/* sidebar contents category */
nav section details.category {
padding-top: var(--padding-tiny);
}
nav section details.category > ul > li {
margin: 0;
line-height: 1.5;
}
nav section details.category > ul > li a {
display: inline-block;
width: 90%;
}
nav section details.category:first-of-type {
padding-top: calc(var(--padding-tiny) * -1);
}
nav section details.category summary::-webkit-details-marker {
opacity: 0.5;
cursor: pointer;
}
nav section details.category summary h2 {
color: var(--color-accent);
font-size: var(--font-big);
letter-spacing: 2px;
text-transform: uppercase;
cursor: pointer;
padding-bottom: var(--padding-tiny);
}
/* content */
article {
background-color: rgb(255, 255, 255);
width: calc(100% - var(--sidebar-width));
min-height: 100vh;
margin-left: var(--sidebar-width);
}
article .wrapper > *:first-child {
margin-top: 0;
}
/* header */
article header {
color: rgb(255, 255, 255);
background-color: rgb(115, 53, 142);
padding: var(--padding-tiny);
}
article header h1 {
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
padding-bottom: 8px;
font-family: var(--font-style-code);
margin: 0;
}
article header h2 {
padding-top: var(--padding-tiny);
margin: 0;
font-size: var(--font-normal);
font-weight: normal;
}
article header.module a {
color: white !important;
text-decoration: underline;
}
details.category > summary {
list-style: none;
}
details.category > summary::-webkit-details-marker {
display: none;
}
article h1 {
font-size: 28px;
font-weight: 600;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
margin-top: 24px;
margin-bottom: 16px;
padding-bottom: 8px;
}
article h2 {
font-size: 20px;
font-weight: 600;
margin-top: 12px;
}
article h3 {
color: rgb(115, 53, 142);
margin-top: var(--padding-tiny);
text-transform: uppercase;
}
article p {
margin-top: var(--padding-small);
}
article p a,
article ul li a,
article h1 a,
article h2 a {
color: rgb(115, 53, 142);
font-weight: 600;
}
article h1.title {
color: rgb(255, 255, 255);
background-color: rgb(115, 53, 142);
margin-top: var(--padding-small);
margin-bottom: 0;
padding: var(--padding-tiny);
font-size: var(--font-big);
font-weight: 100;
letter-spacing: 2px;
text-transform: uppercase;
}
a.reference {
color: rgb(115, 53, 142);
float: right;
margin-top: 8px;
padding-left: 8px;
font-size: 14px;
font-weight: 600;
}
.notice {
--color-notice-background: var(--color-accent);
--color-notice-text: var(--color-notice-background);
margin-top: var(--padding-tiny);
border: 2px solid var(--color-notice-background);
}
.notice.error {
--color-notice-background: rgb(194, 52, 130);
}
.notice.warning {
--color-notice-background: rgb(224, 169, 112);
--color-notice-text: rgb(167, 104, 37);
}
.notice .title {
color: var(--color-white);
background-color: var(--color-notice-background);
padding: var(--padding-tiny);
font-size: var(--font-normal);
text-transform: uppercase;
letter-spacing: 2px;
}
.notice p {
color: var(--color-notice-text);
margin: 0 !important;
padding: var(--padding-tiny);
}
/* function/table */
.method {
display: flex;
flex-flow: column;
background-color: rgb(230, 230, 230);
padding: var(--padding-tiny);
margin-top: var(--padding-small);
}
.method header {
color: rgb(0, 0, 0);
background-color: inherit;
padding: 0;
order: -1;
}
.method header .anchor {
color: inherit;
text-decoration: inherit;
}
.method header .anchor:target h1 {
background-color: rgba(115, 53, 142, 0.2);
background-clip: content-box;
}
.method header h1 {
font-family: "Source Code Pro", monospace;
padding-bottom: var(--padding-tiny);
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
font-size: 20px;
}
.method header p:first-of-type {
margin-top: var(--padding-tiny);
}
.method h3 {
color: rgb(115, 53, 142);
font-size: var(--font-normal);
letter-spacing: 2px;
text-transform: uppercase;
}
.method pre {
margin-top: var(--padding-tiny);
}
@media only screen and (max-width: 1100px) {
main nav {
position: inherit;
}
main article {
margin-left: 0;
}
}
.method ul {
margin-top: var(--padding-tiny);
background-color: inherit;
}
.method ul li {
list-style: none;
margin: 4px 0 0 var(--padding-normal);
}
.method ul li:first-of-type {
margin-top: 0;
}
.method ul li p {
margin: 4px 0 0 var(--padding-normal);
}
.method ul li pre {
margin: 4px 0 0 var(--padding-normal);
}
.method ul li a {
color: rgb(115, 53, 142);
font-weight: 600;
}
/* we have to manually specify these instead of making a shared class since you cannot customize the parameter class in ldoc */
.parameter, .type, .default {
display: inline-block;
color: rgb(255, 255, 255) !important;
padding: 4px;
font-size: 14px;
font-family: "Source Code Pro", monospace;
}
.parameter {
background-color: rgb(115, 53, 142);
}
.type {
background-color: rgb(31, 141, 155);
}
a.type {
font-weight: 300 !important;
text-decoration: underline;
}
.default {
background-color: rgb(193, 114, 11);
}
.type a {
padding: 0;
}
.or {
color: rgba(115, 53, 142, 0.5);
background-color: inherit;
width: calc(100% - 32px);
height: 8px;
margin: 0 0 8px 32px;
text-align: center;
font-weight: 600;
border-bottom: 1px solid rgba(115, 53, 142, 0.5);
}
.or span {
background-color: inherit;
padding: 0 8px 0 8px;
}

View File

@@ -0,0 +1,52 @@
--[[
| 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/
--]]
-- luacheck: ignore 111
--[[--
Class setup hooks.
As with `Faction`s, `Class`es get their own hooks for when players leave/join a class, etc. These hooks are only
valid in class tables that are created in `schema/classes/sh_classname.lua`, and cannot be used like regular gamemode hooks.
]]
-- @hooks Class
--- Whether or not a player can switch to this class.
-- @realm shared
-- @player client Client that wants to switch to this class
-- @treturn bool True if the player is allowed to switch to this class
-- @usage function CLASS:CanSwitchTo(client)
-- return client:IsAdmin() -- only admins allowed in this class!
-- end
function CanSwitchTo(client)
end
--- Called when a character has left this class and has joined a different one. You can get the class the character has
-- has joined by calling `character:GetClass()`.
-- @realm server
-- @player client Player who left this class
function OnLeave(client)
end
--- Called when a character has joined this class.
-- @realm server
-- @player client Player who has joined this class
-- @usage function CLASS:OnSet(client)
-- client:SetModel("models/police.mdl")
-- end
function OnSet(client)
end
--- Called when a character in this class has spawned in the world.
-- @realm server
-- @player client Player that has just spawned
function OnSpawn(client)
end

View File

@@ -0,0 +1,58 @@
--[[
| 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/
--]]
-- luacheck: ignore 111
--[[--
Faction setup hooks.
Factions get their own hooks that are called for various reasons, but the most common one is to set up a character
once it's created and assigned to a certain faction. For example, giving a police faction character a weapon on creation.
These hooks are used in faction tables that are created in `schema/factions/sh_factionname.lua` and cannot be used like
regular gamemode hooks.
]]
-- @hooks Faction
--- Called when the default name for a character needs to be retrieved (i.e upon initial creation).
-- @realm shared
-- @player client Client to get the default name for
-- @treturn string Default name for the newly created character
-- @usage function FACTION:GetDefaultName(client)
-- return "MPF-RCT." .. tostring(math.random(1, 99999))
-- end
function GetDefaultName(client)
end
--- Called when a character has been initally created and assigned to this faction.
-- @realm server
-- @player client Client that owns the character
-- @char character Character that has been created
-- @usage function FACTION:OnCharacterCreated(client, character)
-- local inventory = character:GetInventory()
-- inventory:Add("pistol")
-- end
function OnCharacterCreated(client, character)
end
--- Called when a character in this faction has spawned in the world.
-- @realm server
-- @player client Player that has just spawned
function OnSpawn(client)
end
--- Called when a player's character has been transferred to this faction.
-- @realm server
-- @char character Character that was transferred
-- @usage function FACTION:OnTransferred(character)
-- character:SetModel(self.models[1])
-- end
function OnTransferred(character)
end

View File

@@ -0,0 +1,938 @@
--[[
| 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/
--]]
-- luacheck: ignore 111
--[[--
Global hooks for general use.
Plugin hooks are regular hooks that can be used in your schema with `Schema:HookName(args)`, in your plugin with
`PLUGIN:HookName(args)`, or in your addon with `hook.Add("HookName", function(args) end)`.
]]
-- @hooks Plugin
--- Adjusts the data used just before creating a new character.
-- @realm server
-- @player client Player that is creating the character
-- @tab payload Table of data to be used for character creation
-- @tab newPayload Table of data be merged with the current payload
-- @usage function PLUGIN:AdjustCreationPayload(client, payload, newPayload)
-- newPayload.money = payload.attributes["stm"] -- Sets the characters initial money to the stamina attribute value.
-- end
function AdjustCreationPayload(client, payload, newPayload)
end
--- Adjusts a player's current stamina offset amount. This is called when the player's stamina is about to be changed; every
-- `0.25` seconds on the server, and every frame on the client.
-- @realm shared
-- @player client Player whose stamina is changing
-- @number baseOffset Amount the stamina is changing by. This can be a positive or negative number depending if they are
-- exhausting or regaining stamina
-- @treturn number New offset to use
-- @usage function PLUGIN:AdjustStaminaOffset(client, baseOffset)
-- return baseOffset * 2 -- Drain/Regain stamina twice as fast.
-- end
function AdjustStaminaOffset(client, baseOffset)
end
--- Creates the business panel in the tab menu.
-- @realm client
-- @treturn bool Whether or not to create the business menu
-- @usage function PLUGIN:BuildBusinessMenu()
-- return LocalPlayer():IsAdmin() -- Only builds the business menu for admins.
-- end
function BuildBusinessMenu()
end
--- Whether or not a message can be auto formatted with punctuation and capitalization.
-- @realm server
-- @player speaker Player that sent the message
-- @string chatType Chat type of the message. This will be something registered with `ix.chat.Register` - like `ic`, `ooc`, etc.
-- @string text Unformatted text of the message
-- @treturn bool Whether or not to allow auto formatting on the message
-- @usage function PLUGIN:CanAutoFormatMessage(speaker, chatType, text)
-- return false -- Disable auto formatting outright.
-- end
function CanAutoFormatMessage(speaker, chatType, text)
end
--- Whether or not certain information can be displayed in the character info panel in the tab menu.
-- @realm client
-- @tab suppress Information to **NOT** display in the UI - modify this to change the behaviour. This is a table of the names of
-- some panels to avoid displaying. Valid names include:
--
-- - `time` - current in-game time
-- - `name` - name of the character
-- - `description` - description of the character
-- - `characterInfo` - entire panel showing a list of additional character info
-- - `faction` - faction name of the character
-- - `class` - name of the character's class if they're in one
-- - `money` - current money the character has
-- - `attributes` - attributes list for the character
--
-- Note that schemas/plugins can add additional character info panels.
-- @usage function PLUGIN:CanCreateCharacterInfo(suppress)
-- suppress.attributes = true -- Hides the attributes panel from the character info tab
-- end
function CanCreateCharacterInfo(suppress)
end
--- Whether or not the ammo HUD should be drawn.
-- @realm client
-- @entity weapon Weapon the player currently is holding
-- @treturn bool Whether or not to draw the ammo hud
-- @usage function PLUGIN:CanDrawAmmoHUD(weapon)
-- if (weapon:GetClass() == "weapon_frag") then -- Hides the ammo hud when holding grenades.
-- return false
-- end
-- end
function CanDrawAmmoHUD(weapon)
end
--- Called when a player tries to use abilities on the door, such as locking.
-- @realm shared
-- @player client The client trying something on the door.
-- @entity door The door entity itself.
-- @number access The access level used when called.
-- @treturn bool Whether or not to allow the client access.
-- @usage function PLUGIN:CanPlayerAccessDoor(client, door, access)
-- return true -- Always allow access.
-- end
function CanPlayerAccessDoor(client, door, access)
end
--- Whether or not a player is allowed to create a new character with the given payload.
-- @realm server
-- @player client Player attempting to create a new character
-- @tab payload Data that is going to be used for creating the character
-- @treturn bool Whether or not the player is allowed to create the character. This function defaults to `true`, so you
-- should only ever return `false` if you're disallowing creation. Otherwise, don't return anything as you'll prevent any other
-- calls to this hook from running.
-- @treturn string Language phrase to use for the error message
-- @treturn ... Arguments to use for the language phrase
-- @usage function PLUGIN:CanPlayerCreateCharacter(client, payload)
-- if (!client:IsAdmin()) then
-- return false, "notNow" -- only allow admins to create a character
-- end
-- end
-- -- non-admins will see the message "You are not allowed to do this right now!"
function CanPlayerCreateCharacter(client, payload)
end
--- Whether or not a player is allowed to drop the given `item`.
-- @realm server
-- @player client Player attempting to drop an item
-- @number item instance ID of the item being dropped
-- @treturn bool Whether or not to allow the player to drop the item
-- @usage function PLUGIN:CanPlayerDropItem(client, item)
-- return false -- Never allow dropping items.
-- end
function CanPlayerDropItem(client, item)
end
--- Whether or not a player can earn money at regular intervals. This hook runs only if the player's character faction has
-- a salary set - i.e `FACTION.pay` is set to something other than `0` for their faction.
-- @realm server
-- @player client Player to give money to
-- @tab faction Faction of the player's character
-- @treturn bool Whether or not to allow the player to earn salary
-- @usage function PLUGIN:CanPlayerEarnSalary(client, faction)
-- return client:IsAdmin() -- Restricts earning salary to admins only.
-- end
function CanPlayerEarnSalary(client, faction)
end
--- Whether or not the player is allowed to enter observer mode. This is allowed only for admins by default and can be
-- customized by server owners if the server is using a CAMI-compliant admin mod.
-- @realm server
-- @player client Player attempting to enter observer
-- @treturn bool Whether or not to allow the player to enter observer
-- @usage function PLUGIN:CanPlayerEnterObserver(client)
-- return true -- Always allow observer.
-- end
function CanPlayerEnterObserver(client)
end
--- Whether or not a player can equip the given `item`. This is called for items with `outfit`, `pacoutfit`, or `weapons` as
-- their base. Schemas/plugins can utilize this hook for their items.
-- @realm server
-- @player client Player attempting to equip the item
-- @tab item Item being equipped
-- @treturn bool Whether or not to allow the player to equip the item
-- @see CanPlayerUnequipItem
-- @usage function PLUGIN:CanPlayerEquipItem(client, item)
-- return client:IsAdmin() -- Restrict equipping items to admins only.
-- end
function CanPlayerEquipItem(client, item)
end
--- Whether or not a player is allowed to hold an entity with the hands SWEP.
-- @realm server
-- @player client Player attempting to hold an entity
-- @entity entity Entity being held
-- @treturn bool Whether or not to allow the player to hold the entity
-- @usage function PLUGIN:CanPlayerHoldObject(client, entity)
-- return !(client:GetMoveType() == MOVETYPE_NOCLIP and !client:InVehicle()) -- Disallow players in observer holding objects.
-- end
function CanPlayerHoldObject(client, entity)
end
--- Whether or not a player is allowed to interact with an entity's interaction menu if it has one.
-- @realm server
-- @player client Player attempting interaction
-- @entity entity Entity being interacted with
-- @string option Option selected by the player
-- @param data Any data passed with the interaction option
-- @treturn bool Whether or not to allow the player to interact with the entity
-- @usage function PLUGIN:CanPlayerInteractEntity(client, entity, option, data)
-- return false -- Disallow interacting with any entity.
-- end
function CanPlayerInteractEntity(client, entity, option, data)
end
--- Whether or not a player is allowed to interact with an item via an inventory action (e.g picking up, dropping, transferring
-- inventories, etc). Note that this is for an item *table*, not an item *entity*. This is called after `CanPlayerDropItem`
-- and `CanPlayerTakeItem`.
-- @realm server
-- @player client Player attempting interaction
-- @string action The action being performed
-- @param item Item's instance ID or item table
-- @param data Any data passed with the action
-- @treturn bool Whether or not to allow the player to interact with the item
-- @usage function PLUGIN:CanPlayerInteractItem(client, action, item, data)
-- return false -- Disallow interacting with any item.
-- end
function CanPlayerInteractItem(client, action, item, data)
end
--- Whether or not a plyer is allowed to join a class.
-- @realm shared
-- @player client Player attempting to join
-- @number class ID of the class
-- @tab info The class table
-- @treturn bool Whether or not to allow the player to join the class
-- @usage function PLUGIN:CanPlayerJoinClass(client, class, info)
-- return client:IsAdmin() -- Restrict joining classes to admins only.
-- end
function CanPlayerJoinClass(client, class, info)
end
--- Whether or not a player can knock on the door with the hands SWEP.
-- @realm server
-- @player client Player attempting to knock
-- @entity entity Door being knocked on
-- @treturn bool Whether or not to allow the player to knock on the door
-- @usage function PLUGIN:CanPlayerKnock(client, entity)
-- return false -- Disable knocking on doors outright.
-- end
function CanPlayerKnock(client, entity)
end
--- Whether or not a player can open a shipment spawned from the business menu.
-- @realm server
-- @player client Player attempting to open the shipment
-- @entity entity Shipment entity
-- @treturn bool Whether or not to allow the player to open the shipment
-- @usage function PLUGIN:CanPlayerOpenShipment(client, entity)
-- return client:Team() == FACTION_BMD -- Restricts opening shipments to FACTION_BMD.
-- end
function CanPlayerOpenShipment(client, entity)
end
--- Whether or not a player is allowed to spawn a container entity.
-- @realm server
-- @player client Player attempting to spawn a container
-- @string model Model of the container being spawned
-- @entity entity Container entity
-- @treturn bool Whether or not to allow the player to spawn the container
-- @usage function PLUGIN:CanPlayerSpawnContainer(client, model, entity)
-- return client:IsAdmin() -- Restrict spawning containers to admins.
-- end
function CanPlayerSpawnContainer(client, model, entity)
end
--- Whether or not a player is allowed to take an item and put it in their inventory.
-- @realm server
-- @player client Player attempting to take the item
-- @entity item Entity corresponding to the item
-- @treturn bool Whether or not to allow the player to take the item
-- @usage function PLUGIN:CanPlayerTakeItem(client, item)
-- return !(client:GetMoveType() == MOVETYPE_NOCLIP and !client:InVehicle()) -- Disallow players in observer taking items.
-- end
function CanPlayerTakeItem(client, item)
end
--- Whether or not the player is allowed to punch with the hands SWEP.
-- @realm shared
-- @player client Player attempting throw a punch
-- @treturn bool Whether or not to allow the player to punch
-- @usage function PLUGIN:CanPlayerThrowPunch(client)
-- return client:GetCharacter():GetAttribute("str", 0) > 0 -- Only allow players with strength to punch.
-- end
function CanPlayerThrowPunch(client)
end
--- Whether or not a player can trade with a vendor.
-- @realm server
-- @player client Player attempting to trade
-- @entity entity Vendor entity
-- @string uniqueID The uniqueID of the item being traded.
-- @bool isSellingToVendor If the client is selling to the vendor
-- @treturn bool Whether or not to allow the client to trade with the vendor
-- @usage function PLUGIN:CanPlayerTradeWithVendor(client, entity, uniqueID, isSellingToVendor)
-- return false -- Disallow trading with vendors outright.
-- end
function CanPlayerTradeWithVendor(client, entity, uniqueID, isSellingToVendor)
end
--- Whether or not a player can unequip an item.
-- @realm server
-- @player client Player attempting to unequip an item
-- @tab item Item being unequipped
-- @treturn bool Whether or not to allow the player to unequip the item
-- @see CanPlayerEquipItem
-- @usage function PLUGIN:CanPlayerUnequipItem(client, item)
-- return false -- Disallow unequipping items.
-- end
function CanPlayerUnequipItem(client, item)
end
--- @realm shared
function CanPlayerUseBusiness(client, uniqueID)
end
--- @realm shared
function CanPlayerUseCharacter(client, character)
end
--- @realm server
function CanPlayerUseDoor(client, entity)
end
--- @realm server
function CanPlayerUseVendor(activator)
end
--- @realm client
function CanPlayerViewInventory()
end
--- @realm server
function CanSaveContainer(entity, inventory)
end
--- @realm shared
function CanTransferItem(item, currentInv, oldInv)
end
--- @realm shared
function CharacterAttributeBoosted(client, character, attribID, boostID, boostAmount)
end
--- @realm shared
function CharacterAttributeUpdated(client, self, key, value)
end
--- @realm shared
function CharacterDeleted(client, id, isCurrentChar)
end
--- @realm shared
function CharacterHasFlags(self, flags)
end
--- @realm server
function CharacterLoaded(character)
end
--- @realm server
function CharacterPostSave(character)
end
--- @realm shared
function CharacterPreSave(character)
end
--- @realm shared
function CharacterRecognized()
end
--- @realm server
function CharacterRestored(character)
end
--- @realm shared
function CharacterVarChanged(character, key, oldVar, value)
end
--- @realm shared
function CharacterVendorTraded(client, entity, uniqueID, isSellingToVendor)
end
--- @realm client
function ChatboxCreated()
end
--- @realm client
function ChatboxPositionChanged(x, y, width, height)
end
--- @realm client
function ColorSchemeChanged(color)
end
--- @realm server
function ContainerRemoved(container, inventory)
end
--- @realm client
function CreateCharacterInfo(panel)
end
--- @realm client
function CreateCharacterInfoCategory(panel)
end
--- @realm client
function CreateItemInteractionMenu(icon, menu, itemTable)
end
--- @realm client
function CreateMenuButtons(tabs)
end
--- @realm server
function CreateShipment(client, entity)
end
--- @realm server
function DatabaseConnected()
end
--- @realm server
function DatabaseConnectionFailed(error)
end
--- @realm shared
function DoPluginIncludes(path, pluginTable)
end
--- @realm client
function DrawCharacterOverview()
end
--- @realm client
function DrawHelixModelView(panel, entity)
end
--- @realm client
function DrawPlayerRagdoll(entity)
end
--- @realm client
function GetCharacterDescription(client)
end
--- @realm shared
function GetCharacterName(speaker, chatType)
end
--- @realm shared
function GetChatPrefixInfo(text)
end
--- @realm client
function GetCrosshairAlpha(curAlpha)
end
--- @realm shared
function GetDefaultAttributePoints(client, count)
end
--- @realm shared
function GetDefaultCharacterName(client, faction)
end
--- @realm shared
function GetMaxPlayerCharacter(client)
end
--- Returns the sound to emit from the player upon death. If nothing is returned then it will use the default male/female death
-- sounds.
-- @realm server
-- @player client Player that died
-- @treturn[1] string Sound to play
-- @treturn[2] bool `false` if a sound shouldn't be played at all
-- @usage function PLUGIN:GetPlayerDeathSound(client)
-- -- play impact sound every time someone dies
-- return "physics/body/body_medium_impact_hard1.wav"
-- end
-- @usage function PLUGIN:GetPlayerDeathSound(client)
-- -- don't play a sound at all
-- return false
-- end
function GetPlayerDeathSound(client)
end
--- @realm client
function GetPlayerEntityMenu(client, options)
end
--- @realm client
function GetPlayerIcon(speaker)
end
--- @realm server
function GetPlayerPainSound(client)
end
--- @realm shared
function GetPlayerPunchDamage(client, damage, context)
end
--- @realm server
function GetSalaryAmount(client, faction)
end
--- @realm client
function GetTypingIndicator(character, text)
end
--- Registers chat classes after the core framework chat classes have been registered. You should usually create your chat
-- classes in this hook - especially if you want to reference the properties of a framework chat class.
-- @realm shared
-- @usage function PLUGIN:InitializedChatClasses()
-- -- let's say you wanted to reference an existing chat class's color
-- ix.chat.Register("myclass", {
-- format = "%s says \"%s\"",
-- GetColor = function(self, speaker, text)
-- -- make the chat class slightly brighter than the "ic" chat class
-- local color = ix.chat.classes.ic:GetColor(speaker, text)
--
-- return Color(color.r + 35, color.g + 35, color.b + 35)
-- end,
-- -- etc.
-- })
-- end
-- @see ix.chat.Register
-- @see ix.chat.classes
function InitializedChatClasses()
end
--- @realm shared
function InitializedConfig()
end
--- @realm shared
function InitializedPlugins()
end
--- @realm shared
function InitializedSchema()
end
--- @realm server
function InventoryItemAdded(oldInv, inventory, item)
end
--- @realm server
function InventoryItemRemoved(inventory, item)
end
--- @realm shared
function IsCharacterRecognized(character, id)
end
--- @realm client
function IsPlayerRecognized(client)
end
--- @realm client
function IsRecognizedChatType(chatType)
end
--- @realm server
function LoadData()
end
--- @realm client
function LoadFonts(font, genericFont)
end
--- @realm client
function LoadIntro()
end
--- @realm client
function MenuSubpanelCreated(subpanelName, panel)
end
--- @realm client
function MessageReceived(client, info)
end
--- @realm client
function OnAreaChanged(oldID, newID)
end
--- @realm shared
function OnCharacterCreated(client, character)
end
--- @realm shared
function OnCharacterDisconnect(client, character)
end
--- @realm server
function OnCharacterFallover(client, entity, bFallenOver)
end
--- Called when a character has gotten up from the ground.
-- @realm server
-- @player client Player that has gotten up
-- @entity ragdoll Ragdoll used to represent the player
function OnCharacterGetup(client, ragdoll)
end
--- @realm client
function OnCharacterMenuCreated(panel)
end
--- Called whenever an item entity has spawned in the world. You can access the entity's item table with
-- `entity:GetItemTable()`.
-- @realm server
-- @entity entity Spawned item entity
-- @usage function PLUGIN:OnItemSpawned(entity)
-- local item = entity:GetItemTable()
-- -- do something with the item here
-- end
function OnItemSpawned(entity)
end
--- @realm shared
function OnItemTransferred(item, curInv, inventory)
end
--- @realm client
function OnLocalVarSet(key, var)
end
--- @realm client
function OnPAC3PartTransferred(part)
end
--- @realm server
function OnPickupMoney(client, self)
end
--- @realm shared
function OnPlayerAreaChanged(client, oldID, newID)
end
--- @realm server
function OnPlayerObserve(client, state)
end
--- @realm server
function OnPlayerOptionSelected(client, callingClient, option)
end
--- @realm server
function OnPlayerPurchaseDoor(client, entity, bBuying, bCallOnDoorChild)
end
--- @realm server
function OnPlayerRestricted(client)
end
--- @realm server
function OnPlayerUnRestricted(client)
end
--- @realm server
function OnSavedItemLoaded(loadedItems)
end
--- @realm server
function OnWipeTables()
end
--- @realm shared
function PlayerEnterSequence(client, sequence, callback, time, bNoFreeze)
end
--- @realm server
function PlayerInteractEntity(client, entity, option, data)
end
--- @realm server
function PlayerInteractItem(client, action, item)
end
--- @realm server
function PlayerJoinedClass(client, class, oldClass)
end
--- @realm shared
function PlayerLeaveSequence(entity)
end
--- @realm server
function PlayerLoadedCharacter(client, character, currentChar)
end
--- @realm server
function PlayerLockedDoor(client, door, partner)
end
--- @realm server
function PlayerLockedVehicle(client, vehicle)
end
--- @realm server
function PlayerMessageSend(speaker, chatType, text, anonymous, receivers, rawText)
end
--- @realm shared
function PlayerModelChanged(client, model)
end
--- @realm server
function PlayerStaminaGained(client)
end
--- @realm server
function PlayerStaminaLost(client)
end
--- @realm shared
function PlayerThrowPunch(client, trace)
end
--- @realm server
function PlayerUnlockedDoor(client, door, partner)
end
--- @realm server
function PlayerUnlockedVehicle(client, door)
end
--- @realm server
function PlayerUse(client, entity)
end
--- @realm server
function PlayerUseDoor(client, entity)
end
--- @realm shared
function PlayerWeaponChanged(client, weapon)
end
--- @realm shared
function PluginLoaded(uniqueID, pluginTable)
end
--- @realm shared
function PluginShouldLoad(uniqueID)
end
--- @realm shared
function PluginUnloaded(uniqueID)
end
--- @realm client
function PopulateCharacterInfo(client, character, tooltip)
end
--- @realm client
function PopulateEntityInfo(entity, tooltip)
end
--- @realm client
function PopulateHelpMenu(categories)
end
--- @realm client
function PopulateImportantCharacterInfo(entity, character, tooltip)
end
--- @realm client
function PopulateItemTooltip(tooltip, item)
end
--- @realm client
function PopulatePlayerTooltip(client, tooltip)
end
--- @realm client
function PopulateScoreboardPlayerMenu(client, menu)
end
--- @realm client
function PostChatboxDraw(width, height, alpha)
end
--- @realm client
function PostDrawHelixModelView(panel, entity)
end
--- @realm client
function PostDrawInventory(panel)
end
--- @realm server
function PostLoadData()
end
--- @realm server
function PostPlayerLoadout(client)
end
--- @realm server
function PostPlayerSay(client, chatType, message, anonymous)
end
--- @realm shared
function PostSetupActs()
end
--- @realm server
function PreCharacterDeleted(client, character)
end
--- @realm server
function PrePlayerLoadedCharacter(client, character, currentChar)
end
--- Called before a message sent by a player is processed to be sent to other players - i.e this is ran as early as possible
-- and before things like the auto chat formatting. Can be used to prevent the message from being sent at all.
-- @realm server
-- @player client Player sending the message
-- @string chatType Chat class of the message
-- @string message Contents of the message
-- @bool bAnonymous Whether or not the player is sending the message anonymously
-- @treturn bool Whether or not to prevent the message from being sent
-- @usage function PLUGIN:PrePlayerMessageSend(client, chatType, message, bAnonymous)
-- if (!client:IsAdmin()) then
-- return false -- only allow admins to talk in chat
-- end
-- end
function PrePlayerMessageSend(client, chatType, message, bAnonymous)
end
--- @realm server
function SaveData()
end
--- @realm client
function ScreenResolutionChanged(width, height)
end
--- @realm shared
function SetupActs()
end
--- @realm shared
function SetupAreaProperties()
end
--- @realm server
function ShipmentItemTaken(client, uniqueID, amount)
end
--- @realm client
function ShouldBarDraw(bar)
end
--- @realm server
function ShouldDeleteSavedItems()
end
--- @realm client
function ShouldDisplayArea(newID)
end
--- @realm client
function ShouldDrawCrosshair(client, weapon)
end
--- @realm client
function ShouldDrawItemSize(item)
end
--- @realm client
function ShouldHideBars()
end
--- Whether or not a character should be permakilled upon death. This is only called if the `permakill` server config is
-- enabled.
-- @realm server
-- @player client Player to permakill
-- @char character Player's current character
-- @entity inflictor Entity that inflicted the killing blow
-- @entity attacker Other player or entity that killed the player
-- @treturn bool `false` if the player should not be permakilled
-- @usage function PLUGIN:ShouldPermakillCharacter(client, character, inflictor, attacker)
-- if (client:IsAdmin()) then
-- return false -- all non-admin players will have their character permakilled
-- end
-- end
function ShouldPermakillCharacter(client, character, inflictor, attacker)
end
--- @realm server
function ShouldPlayerDrowned(v)
end
--- @realm server
function ShouldRemoveRagdollOnDeath(client)
end
--- @realm server
function ShouldRestoreInventory(characterID, inventoryID, inventoryType)
end
--- @realm client
function ShouldShowPlayerOnScoreboard(client)
end
--- @realm server
function ShouldSpawnClientRagdoll(client)
end
--- @realm client
function ShowEntityMenu(entity)
end
--- @realm client
function ThirdPersonToggled(oldValue, value)
end
--- @realm client
function UpdateCharacterInfo(panel, character)
end
--- @realm client
function UpdateCharacterInfoCategory(panel, character)
end
--- @realm server
function VoiceDistanceChanged(newValue)
end
--- @realm client
function WeaponCycleSound()
end
--- @realm client
function WeaponSelectSound(weapon)
end

View File

@@ -0,0 +1,168 @@
const skippedCategories = ["manual"];
class Node
{
constructor(name, element, expandable, noAutoCollapse, children = [])
{
this.name = name;
this.element = element;
this.expandable = expandable;
this.noAutoCollapse = noAutoCollapse;
this.children = children;
}
AddChild(name, element, expandable, noAutoCollapse, children)
{
let newNode = new Node(name, element, expandable, noAutoCollapse, children);
this.children.push(newNode);
return newNode;
}
}
class SearchManager
{
constructor(input, contents)
{
this.input = input;
this.input.addEventListener("input", event =>
{
this.OnInputUpdated(this.input.value.toLowerCase().replace(/:/g, "."));
});
// setup search tree
this.tree = new Node("", document.createElement("null"), true, true);
this.entries = {};
const categoryElements = contents.querySelectorAll(".category");
// iterate each kind (hooks/libraries/classes/etc)
for (const category of categoryElements)
{
const nameElement = category.querySelector(":scope > summary > h2");
if (!nameElement)
{
continue;
}
const categoryName = nameElement.textContent.trim().toLowerCase();
if (skippedCategories.includes(categoryName))
{
continue;
}
let categoryNode = this.tree.AddChild(categoryName, category, true, true);
const sectionElements = category.querySelectorAll(":scope > ul > li");
for (const section of sectionElements)
{
const entryElements = section.querySelectorAll(":scope > details > ul > li > a");
const sectionName = section.querySelector(":scope > details > summary > a")
.textContent
.trim()
.toLowerCase();
let sectionNode = categoryNode.AddChild(sectionName, section.querySelector(":scope > details"), true);
for (let i = 0; i < entryElements.length; i++)
{
const entryElement = entryElements[i];
const entryName = entryElement.textContent.trim().toLowerCase();
sectionNode.AddChild(sectionName + "." + entryName, entryElement.parentElement);
}
}
}
}
ResetVisibility(current)
{
current.element.style.display = "";
if (current.noAutoCollapse)
{
current.element.open = true;
}
else if (current.expandable)
{
current.element.open = false;
}
for (let node of current.children)
{
this.ResetVisibility(node);
}
}
Search(input, current)
{
let matched = false;
if (current.name.indexOf(input) != -1)
{
matched = true;
}
for (let node of current.children)
{
let childMatched = this.Search(input, node);
matched = matched || childMatched;
}
if (matched)
{
current.element.style.display = "";
if (current.expandable)
{
current.element.open = true;
}
}
else
{
current.element.style.display = "none";
if (current.expandable)
{
current.element.open = false;
}
}
return matched;
}
OnInputUpdated(input)
{
if (input.length <= 1)
{
this.ResetVisibility(this.tree);
return;
}
this.Search(input, this.tree);
}
}
window.onload = function()
{
const openDetails = document.querySelector(".category > ul > li > details[open]");
if (openDetails)
{
openDetails.scrollIntoView();
}
}
document.addEventListener("DOMContentLoaded", function()
{
const searchInput = document.getElementById("search");
const contents = document.querySelector("body > main > nav > section");
if (searchInput && contents)
{
new SearchManager(searchInput, contents);
}
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,329 @@
# Clockwork to Helix Migration
If you are here, you probably want to be converting your code from another framework to Helix. Doing so should not be a difficult task. Most of the previous functions are probably within Helix in one form or another! This means all you need to do is match *x* function found in the old framework to *y* function in Helix. Some headings will contain a link - this will bring you to the documentation for Helix's equivalent library or class.
This tutorial assumes basic to intermediate knowledge and experience with Garry's Mod Lua.
**Before you start!** You will notice that Helix uses client for the variable that represents a player. Clockwork uses player for the variable instead, but this will conflict with the player library. So if you see `_player` being used in Clockwork, it means the Garry's Mod player library. This is just a preference and does not affect anything besides appear. So keep in mind throughout the tutorial, you may see player being used for Clockwork code and client being used for Helix code. They represent the same thing, just with a different name.
If you are converting Clockwork code to Helix, keep in mind that `_player` is not defined so you will need to either define `_player` yourself or switch it to player instead and change the variable name to client for player objects.
# Basics of Conversion
## Folders
Clockwork code and file structure is not too different from Helix. In the schema, the plugins folder and schema folder stay in the same place. There are some minor differences in naming however:
- The `schema/entities` folder should be moved outside out of the schema folder.
- The `libraries` folder needs to be renamed to `libs` to load.
- The `commands` tab will not load as each command is now defined in a single shared file, does not matter which one.
## Deriving from Helix
This is pretty important. If you want to use Helix as the base, you need to set it as the base. So, go to your Clockwork schema's `gamemode` folder. Inside should be two files: `init.lua `and `cl_init.lua`. Open both, and you should see something along the lines of `DeriveGamemode("Clockwork")`. Change this to `DeriveGamemode("helix")`.
# The Schema
## Introduction
Inside of the `schema` folder of the actual schema, you should see a file named `sh_schema.lua`. This is the main schema file in both Clockwork and Helix. Most of your changes may actually be within this file.
## Including Files
Both frameworks come with a utility function to include a file without worrying about sending them to the client and stuff. In Clockwork, this function is `Clockwork.kernel:IncludePrefixed("sh_myfile.lua")`. Change this to `ix.util.Include("sh_myfile.lua") `and save.
# The Plugin
## Introduction
Plugins serve as a means to add on to a schema or framework without directly modifying either. This allows for easier modifications that can be added/removed with ease. It is recommended that you keep all custom modifications left to plugins rather than editing the framework or the schema if possible.
## Structure
All plugins in Clockwork and Helix go into the `plugins` folder. However, there are many differences with the CW plugin structure. First of all, there are two things you see when you open a plugin folder: `plugin` again and `plugin.ini`.
Helix only has one file needed: `sh_plugin.lua` which acts like `sh_schema.lua` but for plugins.
## Conversion
The first step is to move all of the contents from the `plugin` folder to the main folder of the plugin folder. The `sh_plugin.lua` file needs to be changed to provide basic information about the plugin.You need to define three things in `sh_plugin.lua` which can be found within the `plugin.ini` file:
- `PLUGIN.name = "Plugin Name"`
- `PLUGIN.author = "Plugin Author"`
- `PLUGIN.description = "Plugin Description"`
If the plugin uses a special variable (e.g. `cwPluginName`) for the plugin, change it to `PLUGIN`.
- Note that the `PLUGIN` table is removed after the plugin is loaded. So if you want to use `PLUGIN` after the plugin has loaded (such as in console commands, in entities, etc.), add `local PLUGIN = PLUGIN` at the top.
- You can see if a global variable is defined for it by looking for `PLUGIN:SetGlobalAlias("cwMyPlugin")`. So, one would change `cwMyPlugin` to `PLUGIN`.
# The `Character` Object
One main thing that is very notable is how the character is referenced using `client:GetCharacter()` which returns a character object. The way the object works is just like an entity you spawn. It has its own properties like the model, color, etc. that makes it unique. You can access all the characters in a table which stores loaded characters with `ix.char.loaded`.
The character object comes with many predefined methods. You can look at how they are defined [by clicking here](https://github.com/NebulousCloud/helix/blob/master/gamemode/core/meta/sh_character.lua). The character object makes it very simple to manager character information.
You will notice throughout the framework, the character object is used a lot. The use of the character object makes a large barrier between what belongs to the character and what belongs to the player. For example: flags, models, factions, data, and other things are stored on the character and can be accessed by the character object.
In Clockwork, there is no use of an object. Instead, the character information is intertwined with the player object. For example:
```
-- in Clockwork
player:SetCharacterData("foo", "bar")
-- in Helix
client:GetCharacter():SetData("foo", "bar")
```
The use of the character object allows you to access other characters a player might own without needing to have them be the active character, or even access them when the player is not on the server. Overall, the use of the character object may seem like a complex concept, but will simplify a lot of things once you get the hang of the idea.
# The Libraries
## Animations (`ix.anim`)
Clockwork features many functions to set up animations for a specific model. Helix too has this functionality. Helix has one function instead that pairs a model to a specific "animation class" (grouping of animation types). So, all one needs to do is find the appropriate animation class to match the model with. Looking at the Clockwork function name should tell you.
```
-- before
Clockwork.animation:AddCivilProtectionModel("models/mymodel.mdl")
-- after
ix.anim.SetModelClass("models/mymodel.mdl", "metrocop")
```
## Attributes (`ix.attributes`)
Attributes allow the player to boost certain abilities over time. Both frameworks require one to register attributes, but they are done differently. In Clockwork, the `ATTRIBUTE` table needs to be defined and registered manually. In Helix, the `ATTRIBUTE` table is automatically defined and registered for you. All you need to do is have `ATTRIBUTE.value = "value"`. The basic parts of the attribute needed is `ATTRIBUTE.name` and `ATTRIBUTE.description`.
One extra feature for attributes in Helix is `ATTRIBUTE:OnSetup(client, value)` which is a function that gets called on spawn to apply any effects. For example, the stamina attribute changes the player's run speed by adding the amount of stamina points the player has.
You can find an example at [https://github.com/NebulousCloud/helix/blob/master/plugins/stamina/attributes/sh_stm.lua](https://github.com/NebulousCloud/helix/blob/master/plugins/stamina/attributes/sh_stm.lua)
## Classes (`ix.class`)
Classes are a part of the factions. They basically are a more specific form of a faction. Factions in Helix and Clockwork work similarly. For instance, all classes are placed in the `classes` folder under the schema folder and use `CLASS` as the main variable inside the file.
However:
- You do not need to use `local CLASS = Clockwork.class:New("My Class")`. Instead, `CLASS` is already defined for you and you set the name using `CLASS.name = "My Class"`
- `CLASS.factions` is *not* a table, so `CLASS.factions = {FACTION_MYFACTION}` becomes `CLASS.faction = FACTION_MYFACTION`
- You do not need to use `CLASS:Register()` as classes are registered for you after the file is done processing.
- Classes are *optional* for factions rather than being required.
## Commands (`ix.command`)
Commands no longer need to be in separate files. Instead, they are just placed into one large file. However, if you really wanted you can register multiple commands across multiple files or however you want. One thing you may notice is Clockwork uses a _COMMAND_ table while Helix does not always. It is simply a design preference. You can find examples at [https://github.com/NebulousCloud/helix/blob/master/gamemode/core/sh_commands.lua](https://github.com/NebulousCloud/helix/blob/master/gamemode/core/sh_commands.lua)
It should be noted that:
- `COMMAND.tip` is not used.
- `COMMAND.text` is not used.
- `COMMAND.flags` is not used.
- `COMMAND.arguments` does not need to be defined if no arguments are needed but is defined as a table of argument types when needed `arguments = {ix.type.character, ix.type.number}`. See `ix.command.CommandArgumentsStructure` for details.
- `COMMAND.access` for checking whether or not a person is a (super)admin can be replaced with `adminOnly = true` or `superAdminOnly = true` in the command table.
## Configurations (`ix.config`)
In Helix, the method of adding configurations that can be changed by server owners is heavily simplified. [See an example here](https://github.com/NebulousCloud/helix/blob/master/gamemode/config/sh_config.lua).
Adding a configuration is as follows:
```
-- before
Clockwork.config:Add("run_speed", 225)
-- after
ix.config.Add("runSpeed", 235, ...)
```
You'll notice that ellipses (...) were added at the end. This is because there are more arguments since adding configuration information has been placed into one function. Additionally:
- `Clockwork.config:ShareKey()` is not needed.
- The 3rd argument for `Clockwork.config:AddToSystem(name, key, description, min, max)` is also the 3rd argument for `ix.config.Add`
- The 4th argument for `ix.config.Add` is an optional function that is called when the configuration is changed.
- The 5th argument for `ix.config.Add` is a table. You can specify the category for the configuration to group it with other configurations. There is also a data table inside which can be used to determine the minimum value and maximum value for numbers. Check out [an example here](https://github.com/NebulousCloud/helix/blob/master/gamemode/config/sh_config.lua). See also `ix.config`.
## Currency (`ix.currency`)
Updating your currency code is simple:
```
-- before
Clockwork.config:SetKey("name_cash", "Tokens")
Clockwork.config:SetKey("name_cash", "Dollars") -- another example
-- after
ix.currency.Set("", "token", "tokens")
ix.currency.Set("$", "dollar", "dollars")
```
Note that you need to provide a symbol for that currency (€ for Euro, £ for Pound, ¥ for Yen, etc.) or just leave it as an empty string (`""`) and then provide the singular form of the name for the currency, then the plural form.
## Datastream
Helix uses the [net library](http://wiki.garrysmod.com/page/Net_Library_Usage) whereas Clockwork uses datastream ([netstream](https://github.com/alexgrist/NetStream/blob/master/netstream2.lua)).
If you're unfamiliar with the net library, you can include the netstream library to your schema by downloading [netstream](https://github.com/alexgrist/NetStream/blob/master/netstream2.lua) to `schema/libs/thirdparty/sh_netstream2.lua` and adding `ix.util.Include("libs/thirdparty/sh_netstream2.lua")` to your `sh_schema.lua` file.
Starting a datastream:
```
-- before
Clockwork.datastream:Start(receiver, "MessageName", {1, 2, 3});
-- after
netstream.Start(receiver, "MessageName", 1, 2, 3)
```
Receiving a datastream:
```
-- before
Clockwork.datastream:Hook("MessageName", function(player, data)
local a = data[1];
local b = data[2];
local c = data[3];
print(a, b, c);
end);
-- after
netstream.Hook("MessageName", function(client, a, b, c)
print(a, b, c)
end)
```
## Factions (`ix.faction`)
Factions, like classes, are pretty similar too. They share pretty much the same differences as classes in Clockwork and Helix do.
For instance:
- You do not need to use `local FACTION = Clockwork.faction:New("Name Here")`, instead `FACTION` is already defined for you and you set the name using `FACTION.name = "Name Here"`
- `FACTION.whitelist = true` is changed to `FACTION.isDefault = false`
- `FACTION.models` does not need a male and female part. Instead, all the models are combined into one big list.
- `function FACTION:GetName(name)` becomes `function FACTION:GetDefaultName(name)`
- `FACTION.description = "Describe me"` is added to the faction.
- `FACTION_MYFACTION = FACTION:Register()` becomes `FACTION_MYFACTION = FACTION.index`
## Flags (`ix.flag`)
Flags are functionally equivalent in Helix. To add a new flag:
```
-- before
Clockwork.flag:Add("x", "Name", "Description")
-- after
ix.flag.Add("x", "Description")
```
To check or manipulate a character's flag(s):
```
-- before
Clockwork.player:GiveFlags(player, flags)
Clockwork.player:TakeFlags(player, flags)
Clockwork.player:HasFlags(player, flags)
-- after
client:GetCharacter():GiveFlags(flags)
client:GetCharacter():TakeFlags(flags)
client:GetCharacter():HasFlags(flags)
```
## Inventories (`Inventory`)
Inventories have also had a change in the way they work that may seem very different than Clockwork. Similar to how characters are their own objects, inventories become their own objects as well. These inventory objects belong to character objects, which belongs to players. So, this creates a chain of objects which is neat. The use of inventories as objects makes it very simple to attach inventories to anything.
To access a player's inventory, you need to use `client:GetCharacter():GetInventory()` which returns the main inventory object for the player's character. You can also access all loaded inventories with `ix.item.inventories` but that is not important right now.
## Items (`Item`)
As discussed above, inventories contain items. Items are still used in inventories and world entities, use default class data, have callback functions, and can contain unique item data per instance.
### Setting up items
Every time needs to be registered, or have information about it (such as the name, model, what it does, etc.) defined. In Clockwork, you have your items defined in schemas/plugins under the items folder.
So let's start with the differences in structure in the item file.
- `local ITEM = Clockwork.item:New();` is removed
- `ITEM.uniqueID` is *completely* optional
- Replace `ITEM.cost` with `ITEM.price`
- `ITEM:Register()` is removed
### Item Sizes
Helix's inventory uses a grid and utilizes width and height instead of weight as a means of inventory capacity. This means you will have to change your item's weight (`ITEM.weight`) to something that might be analagous to the item's size using `ITEM.width` and `ITEM.height`. The item's size must be at least one by one grid cell. It's up to you to balance the sizes of items in your use case - taking into account how many items a character might have at once, the default inventory size set in the config, etc.
### Item Functions
Item functions are defined very differently than they are in Clockwork. For example:
```
-- before
function ITEM:OnUse(player, entity)
print("My name is: " .. player:Name(), entity)
end
-- after
ITEM.functions.Use = {
OnRun = function(item)
print("My name is: " .. item.player, item.entity)
end
}
```
All item functions are defined in the `ITEM.functions` table. This allows the drop-down menus when using the item a lot easier and cleaner to generate dynamically. There is also more control of the icons used for the options, whether or not the function should be displayed, etc.
You can see an example of a water item here: [https://github.com/NebulousCloud/helix-hl2rp/blob/master/schema/items/sh_water.lua](https://github.com/NebulousCloud/helix-hl2rp/blob/master/schema/items/sh_water.lua)
Here, we can define what happens when the function is run, what the icon is, and what sound it plays when used. It is basically put into one area rather than being scattered among hooks and stuff.
### Giving/Taking Items
So before we can give/take items, we need to understand what the *item instance* is. Using the analogy earlier about how the inventory system is like a forum, and inside the forum are posts (the items in this case), we can think of instancing an item as making a new post on a forum. So when we talk about an *item instance*, it is an item that has been created in the past. The reason we use an item instance (which is its own object too, neat!) is to make each item ever created unique. Each item instance can have its own data unique to itself.
Clockwork also uses an item instance system where you have to instance an item. So, to instance an item in Clockwork you would use:
```
item = Clockwork.item:CreateInstance("item")
```
And this would create a new instance of an item. Helix's instancing system is slightly different. Instead of having the function return the instance like it does in Clockwork, Helix relies on a callback to pass the instance. The reason for this is the item must be inserted into the database to get a unique number to represent that item. This is not done instantly, otherwise servers would freeze when new items are made. Clockwork uses the time and adds a number to get the numeric ID for an item, which allows the item to be returned which "solves" the issue, but I digress.
The Helix equivalent would be:
```
ix.item.Instance(0, "item", data, x, y, function(item) end)
```
Let's break down the differences:
- For Helix's item instance, the 1st argument (`0`) is the inventory that the item belongs to. You can specify 0 so it does not belong to any inventory.
- The data argument is *optional* and is just a table for the item data.
- *x* and *y* are the position of the items in inventory. You can find an available *x* and *y* with `inventory:FindEmptySlot()`.
- The function is an *optional* argument that passes the item instance. This is where you can directly access the new item.
Keep in mind that Helix will simplify the item system for you when it can. Normally, you would not need to instance an item yourself unless you were doing something advanced.
So you might be wondering, how do I spawn an item in the map, and how do I give a player an item? In Clockwork, you would do the following:
```
-- spawning an item in the map
Clockwork.entity:CreateItem(player, Clockwork.item:CreateInstance("item"), Vector(1, 2, 3));
-- giving a player an item
player:GiveItem(Clockwork.item:CreateInstance("item"));
```
The equivalent in Helix would be:
```
-- spawning an item in the map
ix.item.Spawn("item", Vector(1, 2, 3))
-- giving a player an item
client:GetCharacter():GetInventory():Add("test")
```
So in these two examples, the whole deal of instancing items is done for you in Helix!
# Hooks
You will need to modify the function name and arguments for your schema or plugin hooks.
```
-- before
function Schema:PlayerPlayPainSound(player, gender, damageInfo, hitGroup)
-- ...
end
-- after
function Schema:GetPlayerPainSound(client)
-- ...
end
```
You can see the documented hooks for the schema and plugins in the `Plugin` section.
# Conclusion
Overall, most of the conversion from Clockwork to Helix is simply renaming a certain function and/or switching the order of arguments around. Both are frameworks so they function similarly.
You may want to use our HL2 RP schema example for reference which can be found at [https://github.com/NebulousCloud/helix-hl2rp](https://github.com/NebulousCloud/helix-hl2rp)

View File

@@ -0,0 +1,75 @@
# Getting Started
It's pretty easy to get started with creating your own schema with Helix. It requires a bit of bootstrapping if you're starting from scratch, but you should quickly be on your way to developing your schema after following one of the below sections in this guide.
# Installing the framework
Before you start working on your schema, you'll need to install Helix onto your server. The exact instructions will vary based on your server provider, or if you're hosting the server yourself.
You'll need to download the framework from [GitHub](https://github.com/NebulousCloud/helix) into a folder called `helix`. This folder goes into your server's `gamemodes` folder at `garrysmod/gamemodes/helix`. That's it! The framework is now installed onto your server. Of course, you'll need to restart your server after installing the framework and a schema.
# MySQL usage
By default, Helix will use SQLite (which is built into Garry's Mod) to store player/character data. This requires no configuration and will work "out of the box" after installing and will be fine for most server owners. However, you might want to connect your database to your website or use multiple servers with one database - this will require the usage of an external database accessible elsewhere. This will require the use of a MySQL server. Some server providers will provide you with a MySQL database for free to use with your server.
## Installing
Helix uses the [MySQLOO](https://github.com/FredyH/MySQLOO) library to connect to MySQL databases. You'll need to follow the instructions for installing that library onto your server before continuing. In a nutshell, you need to make sure `gmsv_mysqloo_win32.dll` or `gmsv_mysqloo_linux.dll` (depending on your server's operating system) is in the `garrysmod/lua/bin` folder.
In older versions of MySQLOO, you previously required a .dll called `libmysql.dll` to place in your `root` server folder, where `srcds`/`srcds_linux` was stored. Newer versions of MySQLOO no longer require this.
## Configuring
Now that you've installed MySQLOO, you need to tell Helix that you want to connect to an external MySQL database instead of using SQLite. This requires creating a `helix.yml` configuration file in the `garrysmod/gamemodes/helix` folder. There is an example one already made for you called `helix.example.yml` that you can copy and rename to `helix.yml`.
The first thing you'll need to change is the `adapter` entry so that it says `mysqloo`. Next is to change the other entries to match your database's connection information. Here is an example of what your `helix.yml` should look like:
```
database:
adapter: "mysqloo"
hostname: "myexampledatabase.com"
username: "myusername"
password: "mypassword"
database: "helix"
port: 3306
```
The `hostname` field can either be a domain name (like `myexampledatabase.com`) or an IP address (`123.123.123.123`). If you don't know what the `port` field should be, simply leave it as the default `3306`; this is the default port for MySQL database connections. The `database` field is the name of the database that you've created for Helix. Note that it does not need to be `helix`, it can be whatever you'd like.
Another important thing to note about this configuration file is that you **must** indent with **two spaces only**. `database` should not have any spacing before it, and all other entries must have two spaces before them. Failing to ensure this will make the configuration file fail to load.
# Starting with the HL2 RP schema (Basic)
This section is for using the existing HL2 RP schema as a base for your own schema. It contains a good amount of example code if you need a stronger foundation than just a skeleton.
First, you'll need to download the schema from [GitHub](https://github.com/NebulousCloud/helix-hl2rp). Make sure that you download the contents of the repository into a folder called `ixhl2rp` and place it into your `garrysmod/gamemodes` folder. That's all you'll need to do to get the schema installed, other than setting your gamemode to `ixhl2rp` in the server's command line.
# Starting with the skeleton (Basic)
If you don't want excess code you might not use, or prefer to build from an almost-empty foundation that covers the basic bootstrapping, then the skeleton schema is for you. The skeleton schema contains a lot of comments explaining why code is laid out in a certain way, and some other helpful tips/explanations. Make sure you give it a read!
You'll need to download the schema from [GitHub](https://github.com/NebulousCloud/helix-skeleton) into the folder name of your choice - just make sure it's all lowercase with no spaces. Our example for the sake of brevity will be `myschema`. Place the folder into `garrysmod/gamemodes`.
Next up is to modify the gamemode info so that Garry's Mod will properly recognize it. Rename `skeleton.txt` in your schema folder to your folder's name. In our example we would rename `skeleton.txt` to `myschema.txt`. Next, you'll need to modify the contents of `myschema.txt` and replace the existing information with your own - making sure to replace the `"skeleton"` at the top of the file to your folder's name. In our case we would replace it with `"myschema"`. Once you've renamed the file, you're all good to go!
# Converting from Clockwork (Intermediate)
If you are looking to switch to Helix from Clockwork, you can follow the @{converting-from-clockwork|conversion guide}.
# Starting from scratch (Intermediate)
You can always create the gamemode files yourself if you'd like (although we suggest the skeleton schema in general). In general, a schema is a gamemode that is derived from `helix` and automatically loads `schema/sh_schema.lua`. You shouldn't have your schema files outside of the `schema` folder. The files you'll need are as follows:
`gamemode/init.lua`
```
AddCSLuaFile("cl_init.lua")
DeriveGamemode("helix")
```
`gamemode/cl_init.lua`
```
DeriveGamemode("helix")
```
`schema/sh_schema.lua`
```
Schema.name = "My Schema"
Schema.author = "me!"
Schema.description = "My awesome schema."
-- include your other schema files
ix.util.Include("cl_schema.lua")
ix.util.Include("sv_schema.lua")
-- etc.
```

View File

@@ -0,0 +1,19 @@
<div class="landing">
<h1>Helix Documentation</h1>
</div>
<div class="wrapper">
<p style="text-align: center;">Welcome to the documentation for Helix - the better gamemode framework.</p>
<h2>Developers</h2>
<p>The sidebar shows the entire contents of the documentation. Libraries, functions, etc are all searchable with the search box at the top of the sidebar. Migrating from Clockwork? Check out the <a href="{* ldoc.url('manual/converting-from-clockwork') *}">conversion guide</a> in the manual.</p>
<h2>Server owners</h2>
<p>If you're looking to get your Helix server up and running as soon as possible, check out the <a href="{* ldoc.url('manual/getting-started') *}">Getting Started</a> guide in the manual.</p>
<h2>Community</h2>
<p>Questions? Want to show off your work? Maybe drop a new plugin release? Come join our community <a href="https://discord.gg/2AutUcF" target="_blank">Discord server</a>.</p>
<h2>Contributing</h2>
<p>Helix is a large project and there are still a few things missing here and there. Contributions to the documentation - from function references, to simple typo fixes - are welcomed! Check out the <code>ix.storage</code> library's <a href="https://github.com/NebulousCloud/helix/blob/master/gamemode/core/libs/sh_storage.lua" target="_blank">source code</a> for a good example on how to write documentation. You'll need a basic understanding of <a href="https://guides.github.com/features/mastering-markdown/" target="_blank">Markdown</a>, since it's used extensively to generate the markup.</p>
<p>If you'd like to contribute code, you can visit the <a href="https://github.com/NebulousCloud/helix/" target="_blank">GitHub repository</a> and make a pull request.</p>
<h2>Learning</h2>
<p>Getting started on developing with the Helix framework requires an intermediate level of Garry's Mod Lua knowledge. You'll want to learn the basics before you get starting making a schema. The <a href="https://wiki.facepunch.com/gmod/" target="_blank">Garry's Mod Wiki</a> is a good place to start.</p>
</div>

90
gamemodes/helix/docs/templates/ldoc.ltp vendored Normal file
View File

@@ -0,0 +1,90 @@
{%
local baseUrl = ldoc.css:gsub("ldoc.css", "")
local repo = "https://github.com/nebulouscloud/helix/"
local pageTitle = mod and (ldoc.display_name(mod) .. " - " .. ldoc.title) or ldoc.title
local oldmarkup = ldoc.markup
function ldoc.markup(text, item)
return oldmarkup(text, item, ldoc.plain)
end
function ldoc.url(path)
return baseUrl .. path
end
function ldoc.realm_icon(realm)
return "<span class=\"realm " .. (realm or "") .. "\"></span>";
end
function ldoc.is_kind_classmethod(kind)
return kind ~= "libraries"
end
function ldoc.repo_reference(item)
return repo .. "tree/master" .. item.file.filename:gsub(item.file.base, "/gamemode") .. "#L" .. item.lineno
end
local function moduleDescription(mod)
if (mod.type == "topic") then
return mod.body:gsub(mod.display_name, ""):gsub("#", ""):sub(1, 256) .. "..."
end
return mod.summary
end
%}
<html>
<head>
<title>{{pageTitle}}</title>
<meta property="og:type" content="website" />
<meta property="og:title" content="{{pageTitle}}" />
<meta property="og:site_name" content="Helix Documentation" />
{% if (mod) then %}
<meta property="og:description" content="{{moduleDescription(mod)}}" />
{% else %}
<meta property="og:description" content="Documentation and function reference for the Helix framework." />
{% end %}
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Code+Pro" />
<link rel="stylesheet" href="{* ldoc.css *}" />
<link rel="stylesheet" href="{* ldoc.url('highlight.css') *}" />
</head>
<body>
<main>
{(docs/templates/sidebar.ltp)}
<article>
{% if (ldoc.root) then -- we're rendering the landing page (index.html) %}
{(docs/templates/landing.ltp)}
{% elseif (ldoc.body) then -- we're rendering non-code elements %}
<div class="wrapper">
{* ldoc.body *}
</div>
{% elseif (module) then -- we're rendering libary contents %}
<div class="wrapper">
{(docs/templates/module.ltp)}
</div>
{% end %}
</article>
</main>
<script type="text/javascript" src="{* ldoc.url('app.js') *}"></script>
<script type="text/javascript" src="{* ldoc.url('highlight.min.js') *}"></script>
<script type="text/javascript">
var elements = document.querySelectorAll("pre code")
hljs.configure({
languages: ["lua"]
});
for (var i = 0; i < elements.length; i++)
{
hljs.highlightBlock(elements[i]);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,123 @@
<header class="module">
<h1>{{mod.name}}</h1>
<h2>{* ldoc.markup(mod.summary) *}</h2>
</header>
<p>{* ldoc.markup(mod.description) *}</p>
{% for kind, items in mod.kinds() do %}
<h1 class="title">{{kind}}</h1>
{% for item in items() do %}
<section class="method">
<header>
<a class="anchor" id="{{item.name}}">
<h1>{* ldoc.realm_icon(item.tags.realm[1]) *}</span>{{ldoc.display_name(item)}}</h1>
</a>
{% if (item.tags.internal) then %}
<div class="notice error">
<div class="title">Internal</div>
<p>This is an internal function! You are able to use it, but you risk unintended side effects if used incorrectly.</p>
</div>
{% end %}
{% if (item.module and item.module.type ~= "hooks") then %}
<a class="reference" href="{* ldoc.repo_reference(item) *}">View source &raquo;</a>
{% end %}
{% if (ldoc.descript(item):len() == 0) then %}
<div class="notice warning">
<div class="title">Incomplete</div>
<p>Documentation for this section is incomplete and needs expanding.</p>
</div>
{% else %}
<p>{* ldoc.markup(ldoc.descript(item)) *}</p>
{% end %}
</header>
{# function arguments #}
{% if (item.params and #item.params > 0) then %}
{% local subnames = mod.kinds:type_of(item).subnames %}
{% if (subnames) then %}
<h3>{{subnames}}</h3>
{% end %}
{% for argument in ldoc.modules.iter(item.params) do %}
{% local argument, sublist = item:subparam(argument) %}
<ul>
{% for argumentName in ldoc.modules.iter(argument) do %}
{% local displayName = item:display_name_of(argumentName) %}
{% local type = ldoc.typename(item:type_of_param(argumentName)) %}
{% local default = item:default_of_param(argumentName) %}
<li>
<span class="tag parameter">{{displayName}}</span>
{% if (type ~= "") then %}
<span class="tag">{* type *}</span>
{% end %}
{% if (default and default ~= true) then %}
<span class="tag default">default: {{default}}</span>
{% elseif (default) then %}
<span class="tag default">optional</span>
{% end %}
<p>{* ldoc.markup(item.params.map[argumentName]) *}</p>
</li>
{% end %}
</ul>
{% end %}
{% end %}
{# function returns #}
{% if ((not ldoc.no_return_or_parms) and item.retgroups) then %}
{% local groups = item.retgroups %}
<h3>Returns</h3>
<ul>
{% for i, group in ldoc.ipairs(groups) do %}
{% for returnValue in group:iter() do %}
{% local type, ctypes = item:return_type(returnValue) %}
{% type = ldoc.typename(type) %}
<li>
{% if (type ~= "") then %}
{* type *}
{% else -- we'll assume that it will return a variable type if none is set %}
<span class="tag type">any</span>
{% end %}
<p>{* ldoc.markup(returnValue.text) *}</p>
</li>
{% end %}
{% if (i ~= #groups) then %}
<div class="or"><span>OR</span></div>
{% end %}
{% end %}
</ul>
{% end %}
{% if (item.usage) then -- function usage %}
<h3>Example Usage</h3>
{% for usage in ldoc.modules.iter(item.usage) do %}
<pre><code>{* usage *}</code></pre>
{% end %}
{% end %}
{% if (item.see) then %}
<h3>See Also</h3>
<ul>
{% for see in ldoc.modules.iter(item.see) do %}
<li><a href="{* ldoc.href(see) *}">{{see.label}}</a></li>
{% end %}
</ul>
{% end %}
</section>
{% end %}
{% end %}

View File

@@ -0,0 +1,69 @@
{%
local function isKindExpandable(kind)
return kind ~= "Manual"
end
%}
<nav>
<header>
{% if (not ldoc.root) then %}
<h1><a href="{* ldoc.url('') *}">Helix Documentation</a></h1>
{% end %}
<input id="search" type="search" autocomplete="off" placeholder="Search..." />
</header>
<section>
{% for kind, mods, type in ldoc.kinds() do %}
{% if (ldoc.allowed_in_contents(type, mod)) then %}
<details class="category" open>
<summary>
<h2>{{kind}}</h2>
</summary>
<ul>
{% for currentMod in mods() do %}
{% local name = ldoc.display_name(currentMod) %}
<li>
{% if (isKindExpandable(kind)) then %}
<details {{currentMod.name == (mod or {}).name and "open" or ""}}>
<summary><a href="{* ldoc.ref_to_module(currentMod) *}">{{name}}</a></summary>
<ul>
{% else %}
<a href="{* ldoc.ref_to_module(currentMod) *}">{{name}}</a>
{% end %}
{% if (isKindExpandable(kind)) then
currentMod.items:sort(function(a, b)
return a.name < b.name
end)
end %}
{% for k, v in pairs(currentMod.items) do %}
{% if (v.kind == "functions") then %}
<li>
{* ldoc.realm_icon(v.tags.realm[1]) *}
<a href="{* ldoc.ref_to_module(currentMod) *}#{{v.name}}">
{% if (ldoc.is_kind_classmethod(currentMod.kind)) then
echo((v.name:gsub(".+:", "")))
else
echo((v.name:gsub(currentMod.name .. ".", "")))
end %}
</a>
</li>
{% end %}
{% end %}
{% if (isKindExpandable(kind)) then %}
</ul>
</details>
{% end %}
</li>
{% end %}
</ul>
</details>
{% end %}
{% end %}
</section>
</nav>

View File

@@ -0,0 +1,345 @@
--[[
| 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 = "Item"
ENT.Category = "Helix"
ENT.Spawnable = false
ENT.ShowPlayerInteraction = true
ENT.RenderGroup = RENDERGROUP_BOTH
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("String", 0, "ItemID")
end
function ENT:GetProxyColors()
local itemTable = self.GetItemTable and self:GetItemTable()
return itemTable and itemTable.proxy or false
end
if (SERVER) then
local invalidBoundsMin = Vector(-8, -8, -8)
local invalidBoundsMax = Vector(8, 8, 8)
util.AddNetworkString("ixItemEntityAction")
function ENT:Initialize()
self:SetModel("models/props_junk/watermelon01.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:AddEFlags(EFL_FORCE_CHECK_TRANSMIT)
self.health = 50
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(true)
physObj:Wake()
end
end
function ENT:Use(activator, caller)
local itemTable = self:GetItemTable()
if (IsValid(caller) and caller:IsPlayer() and caller:GetCharacter() and itemTable) then
itemTable.player = caller
itemTable.entity = self
if (itemTable.functions.take.OnCanRun(itemTable)) then
caller:PerformInteraction(ix.config.Get("itemPickupTime", 0.5), self, function(client)
if (!ix.item.PerformInventoryAction(client, "take", self)) then
return false -- do not mark dirty if interaction fails
end
end)
end
itemTable.player = nil
itemTable.entity = nil
end
end
function ENT:SetItem(itemID)
local itemTable = ix.item.instances[itemID]
if (itemTable) then
local material = itemTable:GetMaterial(self)
self:SetSkin(itemTable:GetSkin())
self:SetModel(itemTable:GetModel())
self:SetBodyGroups(itemTable:GetModelBodygroups())
if (material) then
self:SetMaterial(material)
end
self:PhysicsInit(SOLID_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:SetItemID(itemTable.uniqueID)
self.ixItemID = itemID
if (!table.IsEmpty(itemTable.data)) then
self:SetNetVar("data", itemTable.data)
end
local physObj = self:GetPhysicsObject()
if (!IsValid(physObj)) then
self:PhysicsInitBox(invalidBoundsMin, invalidBoundsMax)
self:SetCollisionBounds(invalidBoundsMin, invalidBoundsMax)
end
if (IsValid(physObj)) then
physObj:EnableMotion(true)
physObj:Wake()
end
if (itemTable.OnEntityCreated) then
itemTable:OnEntityCreated(self)
end
end
end
function ENT:OnDuplicated(entTable)
local itemID = entTable.ixItemID
local itemTable = ix.item.instances[itemID]
ix.item.Instance(0, itemTable.uniqueID, itemTable.data, 1, 1, function(item)
self:SetItem(item:GetID())
end)
end
function ENT:OnTakeDamage(damageInfo)
local itemTable = ix.item.instances[self.ixItemID]
if (itemTable.OnEntityTakeDamage
and itemTable:OnEntityTakeDamage(self, damageInfo) == false) then
return
end
local damage = damageInfo:GetDamage()
self:SetHealth(self:Health() - damage)
if (self:Health() <= 0 and !self.ixIsDestroying) then
self.ixIsDestroying = true
self.ixDamageInfo = {damageInfo:GetAttacker(), damage, damageInfo:GetInflictor()}
self:Remove()
end
end
function ENT:OnRemove()
if (!ix.shuttingDown and !self.ixIsSafe and self.ixItemID) then
local itemTable = ix.item.instances[self.ixItemID]
if (itemTable) then
if (self.ixIsDestroying) then
self:EmitSound("physics/cardboard/cardboard_box_break"..math.random(1, 3)..".wav")
local position = self:LocalToWorld(self:OBBCenter())
local effect = EffectData()
effect:SetStart(position)
effect:SetOrigin(position)
effect:SetScale(3)
util.Effect("GlassImpact", effect)
if (itemTable.OnDestroyed) then
itemTable:OnDestroyed(self)
end
ix.log.Add(self.ixDamageInfo[1], "itemDestroy", itemTable:GetName(), itemTable:GetID())
end
if (itemTable.OnRemoved) then
itemTable:OnRemoved()
end
local query = mysql:Delete("ix_items")
query:Where("item_id", self.ixItemID)
query:Execute()
end
end
end
function ENT:Think()
local itemTable = self:GetItemTable()
if (!itemTable) then
--self:Remove()
return
end
if (itemTable.Think) then
itemTable:Think(self)
end
return true
end
function ENT:UpdateTransmitState()
return TRANSMIT_PVS
end
net.Receive("ixItemEntityAction", function(length, client)
ix.item.PerformInventoryAction(client, net.ReadString(), net.ReadEntity())
end)
else
ENT.PopulateEntityInfo = true
local shadeColor = Color(0, 0, 0, 200)
local blockSize = 4
local blockSpacing = 2
function ENT:OnPopulateEntityInfo(tooltip)
local item = self:GetItemTable()
if (!item) then
return
end
local oldData = item.data
item.data = self:GetNetVar("data", {})
item.entity = self
ix.hud.PopulateItemTooltip(tooltip, item)
local name = tooltip:GetRow("name")
local color = name and name:GetBackgroundColor() or ix.config.Get("color")
-- set the arrow to be the same colour as the title/name row
tooltip:SetArrowColor(color)
if ((item.width > 1 or item.height > 1) and
hook.Run("ShouldDrawItemSize", item) != false) then
local sizeHeight = item.height * blockSize + item.height * blockSpacing
local size = tooltip:Add("Panel")
size:SetWide(tooltip:GetWide())
if (tooltip:IsMinimal()) then
size:SetTall(sizeHeight)
size:Dock(TOP)
size:SetZPos(-999)
else
size:SetTall(sizeHeight + 8)
size:Dock(BOTTOM)
end
size.Paint = function(sizePanel, width, height)
if (!tooltip:IsMinimal()) then
surface.SetDrawColor(ColorAlpha(shadeColor, 60))
surface.DrawRect(0, 0, width, height)
end
local x, y = width * 0.5 - 1, height * 0.5 - 1
local itemWidth = item.width - 1
local itemHeight = item.height - 1
local heightDifference = ((itemHeight + 1) * blockSize + blockSpacing * itemHeight)
x = x - (itemWidth * blockSize + blockSpacing * itemWidth) * 0.5
y = y - heightDifference * 0.5
for i = 0, itemHeight do
for j = 0, itemWidth do
local blockX, blockY = x + j * blockSize + j * blockSpacing, y + i * blockSize + i * blockSpacing
surface.SetDrawColor(shadeColor)
surface.DrawRect(blockX + 1, blockY + 1, blockSize, blockSize)
surface.SetDrawColor(color)
surface.DrawRect(blockX, blockY, blockSize, blockSize)
end
end
end
tooltip:SizeToContents()
end
item.entity = nil
item.data = oldData
end
function ENT:DrawTranslucent()
local itemTable = self:GetItemTable()
if (itemTable and itemTable.DrawEntity) then
itemTable:DrawEntity(self)
end
end
function ENT:Draw()
self:DrawModel()
end
end
function ENT:GetEntityMenu(client)
local itemTable = self:GetItemTable()
local options = {}
if (!itemTable) then
return false
end
itemTable.player = client
itemTable.entity = self
for k, v in SortedPairs(itemTable.functions) do
if (k == "take" or k == "combine") then
continue
end
if (v.OnCanRun and v.OnCanRun(itemTable) == false) then
continue
end
-- we keep the localized phrase since we aren't using the callbacks - the name won't matter in this case
options[L(v.name or k)] = function()
local send = true
if (v.OnClick) then
send = v.OnClick(itemTable)
end
if (v.sound) then
surface.PlaySound(v.sound)
end
if (send != false) then
net.Start("ixItemEntityAction")
net.WriteString(k)
net.WriteEntity(self)
net.SendToServer()
end
-- don't run callbacks since we're handling it manually
return false
end
end
itemTable.player = nil
itemTable.entity = nil
return options
end
function ENT:GetItemTable()
return ix.item.list[self:GetItemID()]
end
function ENT:GetData(key, default)
local data = self:GetNetVar("data", {})
return data[key] or default
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/
--]]
AddCSLuaFile()
ENT.Type = "anim"
ENT.PrintName = "Money"
ENT.Category = "Helix"
ENT.Spawnable = false
ENT.ShowPlayerInteraction = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "Amount")
end
if (SERVER) then
local invalidBoundsMin = Vector(-8, -8, -8)
local invalidBoundsMax = Vector(8, 8, 8)
function ENT:Initialize()
self:SetModel(ix.currency.model)
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(true)
physObj:Wake()
else
self:PhysicsInitBox(invalidBoundsMin, invalidBoundsMax)
self:SetCollisionBounds(invalidBoundsMin, invalidBoundsMax)
end
end
function ENT:Use(activator)
if (self.ixSteamID and self.ixCharID) then
local char = activator:GetCharacter()
if (char and self.ixCharID != char:GetID() and self.ixSteamID == activator:SteamID()) then
activator:NotifyLocalized("itemOwned")
return false
end
end
activator:PerformInteraction(ix.config.Get("itemPickupTime", 0.5), self, function(client)
if (hook.Run("OnPickupMoney", client, self) != false) then
self:Remove()
end
end)
end
function ENT:UpdateTransmitState()
return TRANSMIT_PVS
end
else
ENT.PopulateEntityInfo = true
function ENT:OnPopulateEntityInfo(container)
local text = container:AddRow("name")
text:SetImportant()
text:SetText(ix.currency.Get(self:GetAmount()))
text:SizeToContents()
end
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()
ENT.Type = "anim"
ENT.PrintName = "Shipment"
ENT.Category = "Helix"
ENT.Spawnable = false
ENT.ShowPlayerInteraction = true
ENT.bNoPersist = true
function ENT:SetupDataTables()
self:NetworkVar("Int", 0, "DeliveryTime")
end
if (SERVER) then
function ENT:Initialize()
self:SetModel("models/Items/item_item_crate.mdl")
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetUseType(SIMPLE_USE)
self:PrecacheGibs()
local physObj = self:GetPhysicsObject()
if (IsValid(physObj)) then
physObj:EnableMotion(true)
physObj:Wake()
end
self:SetDeliveryTime(CurTime() + 120)
timer.Simple(120, function()
if (IsValid(self)) then
self:Remove()
end
end)
end
function ENT:Use(activator)
activator:PerformInteraction(ix.config.Get("itemPickupTime", 0.5), self, function(client)
if (client:GetCharacter() and client:GetCharacter():GetID() == self:GetNetVar("owner", 0)
and hook.Run("CanPlayerOpenShipment", client, self) != false) then
client.ixShipment = self
net.Start("ixShipmentOpen")
net.WriteEntity(self)
net.WriteTable(self.items)
net.Send(client)
end
-- don't mark dirty since the player could come back and use this shipment again later
return false
end)
end
function ENT:SetItems(items)
self.items = items
end
function ENT:GetItemCount()
local count = 0
for _, v in pairs(self.items) do
count = count + math.max(v, 0)
end
return count
end
function ENT:OnRemove()
self:EmitSound("physics/cardboard/cardboard_box_break"..math.random(1, 3)..".wav")
local position = self:LocalToWorld(self:OBBCenter())
local effect = EffectData()
effect:SetStart(position)
effect:SetOrigin(position)
effect:SetScale(3)
util.Effect("GlassImpact", effect)
end
function ENT:UpdateTransmitState()
return TRANSMIT_PVS
end
else
ENT.PopulateEntityInfo = true
local size = 150
local tempMat = Material("particle/warp1_warp", "alphatest")
function ENT:Draw()
local pos, ang = self:GetPos(), self:GetAngles()
self:DrawModel()
pos = pos + self:GetUp() * 25
pos = pos + self:GetForward() * 1
pos = pos + self:GetRight() * 3
local delTime = math.max(math.ceil(self:GetDeliveryTime() - CurTime()), 0)
local func = function()
surface.SetMaterial(tempMat)
surface.SetDrawColor(0, 0, 0, 200)
surface.DrawTexturedRect(-size / 2, -size / 2 - 10, size, size)
ix.util.DrawText("k", 0, 0, color_white, 1, 4, "ixIconsBig")
ix.util.DrawText(delTime, 0, -10, color_white, 1, 5, "ixBigFont")
end
cam.Start3D2D(pos, ang, .15)
func()
cam.End3D2D()
ang:RotateAroundAxis(ang:Right(), 180)
pos = pos - self:GetUp() * 26
cam.Start3D2D(pos, ang, .15)
func()
cam.End3D2D()
end
function ENT:OnPopulateEntityInfo(container)
local owner = ix.char.loaded[self:GetNetVar("owner", 0)]
local name = container:AddRow("name")
name:SetImportant()
name:SetText(L("shipment"))
name:SizeToContents()
if (owner) then
local description = container:AddRow("description")
description:SetText(L("shipmentDesc", owner:GetName()))
description:SizeToContents()
end
end
end

View File

@@ -0,0 +1,649 @@
--[[
| 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 = "Hands"
SWEP.Slot = 0
SWEP.SlotPos = 1
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = true
end
SWEP.Author = "Chessnut"
SWEP.Instructions = [[Primary Fire: Throw/Punch
Secondary Fire: Knock/Pickup
Secondary Fire + Mouse: Rotate Object
Reload: Drop]]
SWEP.Purpose = "Hitting things and knocking on doors."
SWEP.Drop = false
SWEP.ViewModelFOV = 45
SWEP.ViewModelFlip = false
SWEP.AnimPrefix = "rpg"
SWEP.ViewTranslation = 4
if CLIENT then
SWEP.NextAllowedPlayRateChange = 0
end
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Primary.Damage = 5
SWEP.Primary.Delay = 0.75
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
SWEP.Secondary.Delay = 0.5
SWEP.ViewModel = Model("models/weapons/c_arms.mdl")
SWEP.WorldModel = ""
SWEP.UseHands = true
SWEP.LowerAngles = Angle(0, 5, -14)
SWEP.LowerAngles2 = Angle(0, 5, -19)
SWEP.KnockViewPunchAngle = Angle(-1.3, 1.8, 0)
SWEP.FireWhenLowered = true
SWEP.HoldType = "fist"
SWEP.holdDistance = 64
SWEP.maxHoldDistance = 96 -- how far away the held object is allowed to travel before forcefully dropping
SWEP.maxHoldStress = 4000 -- how much stress the held object can undergo before forcefully dropping
-- luacheck: globals ACT_VM_FISTS_DRAW ACT_VM_FISTS_HOLSTER
ACT_VM_FISTS_DRAW = 2
ACT_VM_FISTS_HOLSTER = 1
function SWEP:Initialize()
self:SetHoldType(self.HoldType)
self.lastHand = 0
self.maxHoldDistanceSquared = self.maxHoldDistance ^ 2
self.heldObjectAngle = Angle(angle_zero)
end
if (CLIENT) then
function SWEP:PreDrawViewModel(viewModel, weapon, client)
local hands = player_manager.TranslatePlayerHands(player_manager.TranslateToPlayerModelName(client:GetModel()))
if client:GetModel() == "models/willardnetworks/vortigaunt.mdl" then
self.ViewModelFOV = 60
end
if (hands and hands.model) then
viewModel:SetModel(hands.model)
if hands.skin and isnumber(hands.skin) then
viewModel:SetSkin(hands.skin)
end
viewModel:SetBodyGroups(hands.body)
end
end
function SWEP:DoDrawCrosshair(x, y)
surface.SetDrawColor(255, 255, 255, 66)
surface.DrawRect(x - 2, y - 2, 4, 4)
end
-- Adjust these variables to move the viewmodel's position
SWEP.IronSightsPos = Vector(0, 0, 0)
SWEP.IronSightsAng = Vector(0, 0, 0)
function SWEP:GetViewModelPosition(EyePos, EyeAng)
if self.Owner:GetModel() == "models/willardnetworks/vortigaunt.mdl" then
self.IronSightsPos = Vector(0, -3, -5)
local Mul = 1.0
local Offset = self.IronSightsPos
if (self.IronSightsAng) then
EyeAng = EyeAng * 1
EyeAng:RotateAroundAxis(EyeAng:Right(), self.IronSightsAng.x * Mul)
EyeAng:RotateAroundAxis(EyeAng:Up(), self.IronSightsAng.y * Mul)
EyeAng:RotateAroundAxis(EyeAng:Forward(), self.IronSightsAng.z * Mul)
end
local Right = EyeAng:Right()
local Up = EyeAng:Up()
local Forward = EyeAng:Forward()
EyePos = EyePos + Offset.x * Right * Mul
EyePos = EyePos + Offset.y * Forward * Mul
EyePos = EyePos + Offset.z * Up * Mul
return EyePos, EyeAng
end
end
hook.Add("CreateMove", "ixHandsCreateMove", function(cmd)
if (LocalPlayer():GetLocalVar("bIsHoldingObject", false) and cmd:KeyDown(IN_ATTACK2)) then
cmd:ClearMovement()
local angle = RenderAngles()
angle.z = 0
cmd:SetViewAngles(angle)
end
end)
end
function SWEP:Deploy()
if (!IsValid(self:GetOwner())) then
return
end
local viewModel = self:GetOwner():GetViewModel()
if (IsValid(viewModel)) then
viewModel:SetPlaybackRate(1)
viewModel:ResetSequence(ACT_VM_FISTS_DRAW)
if CLIENT then
self.NextAllowedPlayRateChange = CurTime() + viewModel:SequenceDuration()
end
end
self:DropObject()
return true
end
function SWEP:Precache()
util.PrecacheSound("npc/vort/claw_swing1.wav")
util.PrecacheSound("npc/vort/claw_swing2.wav")
util.PrecacheSound("physics/plastic/plastic_box_impact_hard1.wav")
util.PrecacheSound("physics/plastic/plastic_box_impact_hard2.wav")
util.PrecacheSound("physics/plastic/plastic_box_impact_hard3.wav")
util.PrecacheSound("physics/plastic/plastic_box_impact_hard4.wav")
util.PrecacheSound("physics/wood/wood_crate_impact_hard2.wav")
util.PrecacheSound("physics/wood/wood_crate_impact_hard3.wav")
end
function SWEP:OnReloaded()
self.maxHoldDistanceSquared = self.maxHoldDistance ^ 2
self:DropObject()
end
function SWEP:Holster()
if (!IsValid(self:GetOwner())) then
return
end
local viewModel = self:GetOwner():GetViewModel()
if (IsValid(viewModel)) then
viewModel:SetPlaybackRate(1)
viewModel:ResetSequence(ACT_VM_FISTS_HOLSTER)
if CLIENT then
self.NextAllowedPlayRateChange = CurTime() + viewModel:SequenceDuration()
end
end
return true
end
function SWEP:Think()
if (!IsValid(self:GetOwner())) then
return
end
if (CLIENT) then
local viewModel = self:GetOwner():GetViewModel()
if (IsValid(viewModel) and self.NextAllowedPlayRateChange < CurTime()) then
viewModel:SetPlaybackRate(1)
end
else
if (self:IsHoldingObject()) then
local physics = self:GetHeldPhysicsObject()
local bIsRagdoll = self.heldEntity:IsRagdoll()
local holdDistance = bIsRagdoll and self.holdDistance * 0.5 or self.holdDistance
local targetLocation = self:GetOwner():GetShootPos() + self:GetOwner():GetForward() * holdDistance
if (bIsRagdoll) then
targetLocation.z = math.min(targetLocation.z, self:GetOwner():GetShootPos().z - 32)
end
if (!IsValid(physics)) then
self:DropObject()
return
end
if (physics:GetPos():DistToSqr(targetLocation) > self.maxHoldDistanceSquared) then
self:DropObject()
else
local physicsObject = self.holdEntity:GetPhysicsObject()
local currentPlayerAngles = self:GetOwner():EyeAngles()
local client = self:GetOwner()
if (client:KeyDown(IN_ATTACK2)) then
local cmd = client:GetCurrentCommand()
self.heldObjectAngle:RotateAroundAxis(currentPlayerAngles:Forward(), cmd:GetMouseX() / 15)
self.heldObjectAngle:RotateAroundAxis(currentPlayerAngles:Right(), cmd:GetMouseY() / 15)
end
self.lastPlayerAngles = self.lastPlayerAngles or currentPlayerAngles
self.heldObjectAngle.y = self.heldObjectAngle.y - math.AngleDifference(self.lastPlayerAngles.y, currentPlayerAngles.y)
self.lastPlayerAngles = currentPlayerAngles
physicsObject:Wake()
physicsObject:ComputeShadowControl({
secondstoarrive = 0.01,
pos = targetLocation,
angle = self.heldObjectAngle,
maxangular = 256,
maxangulardamp = 10000,
maxspeed = 256,
maxspeeddamp = 10000,
dampfactor = 0.8,
teleportdistance = self.maxHoldDistance * 0.75,
deltatime = FrameTime()
})
if (physics:GetStress() > self.maxHoldStress) then
self:DropObject()
end
local pos = physics:GetPos()
local clientPos = client:GetPos()
if (clientPos.z > pos.z and math.Distance(clientPos.x, clientPos.y, pos.x, pos.y) <= 50) then
self:DropObject()
end
end
end
-- Prevents the camera from getting stuck when the object that the client is holding gets deleted.
if(!IsValid(self.heldEntity) and self:GetOwner():GetLocalVar("bIsHoldingObject", true)) then
self:GetOwner():SetLocalVar("bIsHoldingObject", false)
end
end
end
function SWEP:GetHeldPhysicsObject()
return IsValid(self.heldEntity) and self.heldEntity:GetPhysicsObject() or nil
end
function SWEP:CanHoldObject(entity)
if !entity or entity and !IsValid(entity) then return false end
local physics = entity.GetPhysicsObject and entity:GetPhysicsObject()
local client = self:GetOwner()
local clientPos = client:GetPos()
local pos = physics and IsValid(physics) and physics:GetPos()
return IsValid(physics) and
(physics:GetMass() <= ix.config.Get("maxHoldWeight", 100) and physics:IsMoveable()) and
!self:IsHoldingObject() and
!IsValid(entity.ixHeldOwner) and
hook.Run("CanPlayerHoldObject", client, entity) and
!(clientPos.z > entity:GetPos().z and math.Distance(clientPos.x, clientPos.y, pos.x, pos.y) < 50)
end
function SWEP:IsHoldingObject()
return IsValid(self.heldEntity) and
IsValid(self.heldEntity.ixHeldOwner) and
self.heldEntity.ixHeldOwner == self:GetOwner()
end
function SWEP:PickupObject(entity)
if (self:IsHoldingObject() or
!IsValid(entity) or
!IsValid(entity:GetPhysicsObject())) then
return
end
local physics = entity:GetPhysicsObject()
physics:EnableGravity(false)
physics:AddGameFlag(FVPHYSICS_PLAYER_HELD)
entity.ixHeldOwner = self:GetOwner()
entity.ixCollisionGroup = entity:GetCollisionGroup()
entity:StartMotionController()
entity:SetCollisionGroup(COLLISION_GROUP_WEAPON)
self.heldObjectAngle = entity:GetAngles()
self.heldEntity = entity
self.holdEntity = ents.Create("prop_physics")
self.holdEntity:SetPos(self.heldEntity:LocalToWorld(self.heldEntity:OBBCenter()))
self.holdEntity:SetAngles(self.heldEntity:GetAngles())
self.holdEntity:SetModel("models/weapons/w_bugbait.mdl")
self.holdEntity:SetOwner(self:GetOwner())
self.holdEntity:SetNoDraw(true)
self.holdEntity:SetNotSolid(true)
self.holdEntity:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
self.holdEntity:DrawShadow(false)
self.holdEntity:Spawn()
local trace = self:GetOwner():GetEyeTrace()
local physicsObject = self.holdEntity:GetPhysicsObject()
if (IsValid(physicsObject)) then
physicsObject:SetMass(2048)
physicsObject:SetDamping(0, 1000)
physicsObject:EnableGravity(false)
physicsObject:EnableCollisions(false)
physicsObject:EnableMotion(false)
end
if (trace.Entity:IsRagdoll()) then
local tracedEnt = trace.Entity
self.holdEntity:SetPos(tracedEnt:GetBonePosition(tracedEnt:TranslatePhysBoneToBone(trace.PhysicsBone)))
end
self.constraint = constraint.Weld(self.holdEntity, self.heldEntity, 0,
trace.Entity:IsRagdoll() and trace.PhysicsBone or 0, 0, true, true)
end
function SWEP:DropObject(bThrow)
if (!IsValid(self.heldEntity) or self.heldEntity.ixHeldOwner != self:GetOwner()) then
return
end
self.lastPlayerAngles = nil
self:GetOwner():SetLocalVar("bIsHoldingObject", false)
self.constraint:Remove()
self.holdEntity:Remove()
self.heldEntity:StopMotionController()
self.heldEntity:SetCollisionGroup(self.heldEntity.ixCollisionGroup or COLLISION_GROUP_NONE)
local physics = self:GetHeldPhysicsObject()
physics:EnableGravity(true)
physics:Wake()
physics:ClearGameFlag(FVPHYSICS_PLAYER_HELD)
if (bThrow) then
timer.Simple(0, function()
if (IsValid(physics) and IsValid(self:GetOwner())) then
physics:AddGameFlag(FVPHYSICS_WAS_THROWN)
physics:ApplyForceCenter(self:GetOwner():GetAimVector() * ix.config.Get("throwForce", 732))
end
end)
end
self.heldEntity.ixHeldOwner = nil
self.heldEntity.ixCollisionGroup = nil
self.heldEntity = nil
end
function SWEP:PlayPickupSound(surfaceProperty)
local result = "Flesh.ImpactSoft"
if (surfaceProperty != nil) then
local surfaceName = util.GetSurfacePropName(surfaceProperty)
local soundName = surfaceName:gsub("^metal$", "SolidMetal") .. ".ImpactSoft"
if (sound.GetProperties(soundName)) then
result = soundName
end
end
self:GetOwner():EmitSound(result, 75, 100, 40)
end
function SWEP:Holster()
if (!IsFirstTimePredicted() or CLIENT) then
return
end
self:DropObject()
return true
end
function SWEP:OnRemove()
if (SERVER) then
self:DropObject()
end
end
function SWEP:OwnerChanged()
if (SERVER) then
self:DropObject()
end
end
function SWEP:DoPunchAnimation()
self.lastHand = math.abs(1 - self.lastHand)
local sequence = 3 + self.lastHand
local viewModel = self:GetOwner():GetViewModel()
if (IsValid(viewModel)) then
viewModel:SetPlaybackRate(0.5)
viewModel:SetSequence(sequence)
if CLIENT then
self.NextAllowedPlayRateChange = CurTime() + viewModel:SequenceDuration() * 2
end
end
end
function SWEP:PrimaryAttack()
if (!IsFirstTimePredicted()) then
return
end
if (SERVER and self:IsHoldingObject()) then
self:DropObject(true)
return
end
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
if (hook.Run("CanPlayerThrowPunch", self:GetOwner()) == false) then
return
end
if (ix.plugin.Get("stamina")) then
local staminaUse = ix.config.Get("punchStamina")
if (staminaUse > 0) then
local value = self:GetOwner():GetLocalVar("stm", 0) - staminaUse
if (value < 0) then
return
elseif (SERVER) then
self:GetOwner():ConsumeStamina(staminaUse)
end
end
end
if (SERVER) then
self:GetOwner():EmitSound("npc/vort/claw_swing"..math.random(1, 2)..".wav")
end
self:DoPunchAnimation()
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:GetOwner():ViewPunch(Angle(self.lastHand + 2, self.lastHand + 5, 0.125))
if ix.plugin.Get("vortigaunts") then
if (ix.config.Get("pushOnly")) and !self:GetOwner():IsVortigaunt() then
local data = {}
data.start = self.Owner:GetShootPos()
data.endpos = data.start + self.Owner:GetAimVector() * 84
data.filter = {self, self.Owner}
local trace = util.TraceLine(data)
local entity = trace.Entity
if (entity:IsPlayer() and ix.config.Get("allowPush", true)) then
self:PushEntity(entity)
end
return
end
else
if (ix.config.Get("pushOnly")) then
local data = {}
data.start = self.Owner:GetShootPos()
data.endpos = data.start + self.Owner:GetAimVector() * 84
data.filter = {self, self.Owner}
local trace = util.TraceLine(data)
local entity = trace.Entity
if (entity:IsPlayer() and ix.config.Get("allowPush", true)) then
self:PushEntity(entity)
end
return
end
end
timer.Simple(0.055, function()
if (IsValid(self) and IsValid(self:GetOwner())) then
local damage = self.Primary.Damage
if ix.plugin.Get("vortigaunts") then
if self:GetOwner():IsVortigaunt() then
damage = damage + self:GetOwner():GetCharacter():GetSkillLevel("melee")
end
if (SERVER and self:GetOwner():IsPlayer() and self:GetOwner().GetCharacter and self:GetOwner():GetCharacter() and self:GetOwner():IsVortigaunt()) then
self:GetOwner():GetCharacter():DoAction("melee_slash")
end
end
local context = {damage = damage}
local result = hook.Run("GetPlayerPunchDamage", self:GetOwner(), damage, context)
if (result != nil) then
damage = result
else
damage = context.damage
end
damage = damage * 1.7 --For some reason, punching only does 60% of the damage. 60% * 1.7 = 102%
if self:GetOwner():IsVortigaunt() and damage > 25 then
damage = 30
end
self:GetOwner():LagCompensation(true)
local data = {}
data.start = self:GetOwner():GetShootPos()
data.endpos = data.start + self:GetOwner():GetAimVector() * 96
data.filter = self:GetOwner()
local trace = util.TraceLine(data)
if (SERVER and trace.Hit) then
local entity = trace.Entity
if (IsValid(entity)) then
if ix.plugin.Get("vortigaunts") then
if (self:GetOwner():IsPlayer() and self:GetOwner().GetCharacter and self:GetOwner():GetCharacter() and self:GetOwner():IsVortigaunt()) then
self:GetOwner():GetCharacter():DoAction("melee_hit")
end
end
local damageInfo = DamageInfo()
damageInfo:SetAttacker(self:GetOwner())
damageInfo:SetInflictor(self)
damageInfo:SetDamage(damage)
damageInfo:SetDamageType(DMG_GENERIC)
damageInfo:SetDamagePosition(trace.HitPos)
damageInfo:SetDamageForce(self:GetOwner():GetAimVector() * 1024)
entity:DispatchTraceAttack(damageInfo, data.start, data.endpos)
if (entity:IsPlayer()) then
ix.log.AddRaw(self:GetOwner():Name() .." has damaged " .. entity:Name() .. ", dealing " .. damage .. " with ix_hands")
end
if (entity:IsNPC()) then
ix.log.AddRaw(self:GetOwner():Name() .." has damaged " .. entity:GetClass() .. ", dealing " .. damage .. " with ix_hands")
end
self:GetOwner():EmitSound("physics/body/body_medium_impact_hard"..math.random(1, 6)..".wav", 80)
end
end
hook.Run("PlayerThrowPunch", self:GetOwner(), trace)
self:GetOwner():LagCompensation(false)
if (CLIENT and trace.Hit) then
local entity = trace.Entity
--This is kind of redundant
--if (entity:IsPlayer() and IsValid(entity)) then
-- chat.AddText(Color(217, 83, 83), "You have damaged " .. entity:Name() .. ", dealing " .. damage .. " points of damage.")
--end
--if (entity:IsNPC()) then
-- chat.AddText(Color(217, 83, 83), "You have damaged " .. entity:GetClass() .. ", dealing " .. damage .. " points of damage.")
--end
end
end
end)
end
function SWEP:SecondaryAttack()
if (!IsFirstTimePredicted()) then
return
end
local data = {}
data.start = self:GetOwner():GetShootPos()
data.endpos = data.start + self:GetOwner():GetAimVector() * 84
data.filter = {self, self:GetOwner()}
local trace = util.TraceLine(data)
local entity = trace.Entity
if CLIENT then
local viewModel = self:GetOwner():GetViewModel()
if (IsValid(viewModel)) then
viewModel:SetPlaybackRate(0.5)
if CLIENT then
self.NextAllowedPlayRateChange = CurTime() + viewModel:SequenceDuration() * 2
end
end
end
if (SERVER and IsValid(entity)) then
if (entity:IsDoor()) then
if (hook.Run("CanPlayerKnock", self:GetOwner(), entity) == false) then
return
end
self:GetOwner():ViewPunch(self.KnockViewPunchAngle)
self:GetOwner():EmitSound("physics/wood/wood_crate_impact_hard"..math.random(2, 3)..".wav")
self:GetOwner():SetAnimation(PLAYER_ATTACK1)
self:DoPunchAnimation()
self:SetNextSecondaryFire(CurTime() + 0.4)
self:SetNextPrimaryFire(CurTime() + 1)
elseif (entity:IsPlayer() and ix.config.Get("allowPush", true)) then
self:PushEntity(entity)
elseif (!entity:IsNPC() and self:CanHoldObject(entity)) then
self:GetOwner():SetLocalVar("bIsHoldingObject", true)
self:PickupObject(entity)
self:PlayPickupSound(trace.SurfaceProps)
self:SetNextSecondaryFire(CurTime() + self.Secondary.Delay)
end
end
end
function SWEP:PushEntity(entity)
local curTime = CurTime()
local direction = self.Owner:GetAimVector() * (300 + (self.Owner:GetCharacter():GetAttribute("str", 0) * 3))
direction.z = 0
entity:SetVelocity(direction)
self.Owner:EmitSound("physics/flesh/flesh_impact_hard"..math.random(1, 6)..".wav")
self:SetNextSecondaryFire(curTime + 1.5)
self:SetNextPrimaryFire(curTime + 1.5)
end
function SWEP:Reload()
if (!IsFirstTimePredicted()) then
return
end
if (SERVER and IsValid(self.heldEntity)) then
self:DropObject()
end
end

View File

@@ -0,0 +1,60 @@
--[[
| 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/
--]]
-- unix systems are case-sensitive, are missing fonts, or use different naming conventions
if (!system.IsWindows()) then
local fontOverrides = {
["Roboto"] = "Roboto Regular",
["Roboto Th"] = "Roboto Thin",
["Roboto Lt"] = "Roboto Light",
["Roboto Bk"] = "Roboto Black",
["coolvetica"] = "Coolvetica",
["tahoma"] = "Tahoma",
["Harmonia Sans Pro Cyr"] = "Roboto Regular",
["Harmonia Sans Pro Cyr Light"] = "Roboto Light",
["Century Gothic"] = "Roboto Regular"
}
if (system.IsOSX()) then
fontOverrides["Consolas"] = "Monaco"
else
fontOverrides["Consolas"] = "Courier New"
end
local ixCreateFont = surface.CreateFont
function surface.CreateFont(name, info) -- luacheck: globals surface
local font = info.font
if (font and fontOverrides[font]) then
info.font = fontOverrides[font]
end
ixCreateFont(name, info)
end
end
DeriveGamemode("sandbox")
ix = ix or {util = {}, gui = {}, meta = {}}
-- Include core files.
include("core/sh_util.lua")
include("core/sh_data.lua")
include("shared.lua")
-- Sandbox stuff
CreateConVar("cl_weaponcolor", "0.30 1.80 2.10", {
FCVAR_ARCHIVE, FCVAR_USERINFO, FCVAR_DONTRECORD
}, "The value is a Vector - so between 0-1 - not between 0-255")
timer.Remove("HintSystem_OpeningMenu")
timer.Remove("HintSystem_Annoy1")
timer.Remove("HintSystem_Annoy2")

View File

@@ -0,0 +1,244 @@
--[[
| 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/
--]]
-- You can change the default language by setting this in your schema.
ix.config.language = "english"
--[[
DO NOT CHANGE ANYTHING BELOW THIS.
This is the Helix main configuration file.
This file DOES NOT set any configurations, instead it just prepares them.
To set the configuration, there is a "Config" tab in the F1 menu for super admins and above.
Use the menu to change the variables, not this file.
--]]
ix.config.Add("maxCharacters", 5, "The maximum number of characters a player can have.", nil, {
data = {min = 1, max = 50},
category = "characters"
})
ix.config.Add("color", Color(75, 119, 190, 255), "The main color theme for the framework.", function(oldValue, newValue)
if (newValue.a != 255) then
ix.config.Set("color", ColorAlpha(newValue, 255))
return
end
if (CLIENT) then
hook.Run("ColorSchemeChanged", newValue)
end
end, {category = "appearance"})
ix.config.Add("font", "Roboto Th", "The font used to display titles.", function(oldValue, newValue)
if (CLIENT) then
hook.Run("LoadFonts", newValue, ix.config.Get("genericFont"))
end
end, {category = "appearance"})
ix.config.Add("genericFont", "Roboto", "The font used to display generic texts.", function(oldValue, newValue)
if (CLIENT) then
hook.Run("LoadFonts", ix.config.Get("font"), newValue)
end
end, {category = "appearance"})
ix.config.Add("maxAttributes", 100, "The maximum amount each attribute can be.", nil, {
data = {min = 0, max = 100},
category = "characters"
})
ix.config.Add("chatAutoFormat", true, "Whether or not to automatically capitalize and punctuate in-character text.", nil, {
category = "Chat"
})
ix.config.Add("chatRange", 280, "The maximum distance a person's IC chat message goes to.", nil, {
data = {min = 10, max = 5000, decimals = 1},
category = "chat"
})
ix.config.Add("chatMax", 256, "The maximum amount of characters that can be sent in chat.", nil, {
data = {min = 32, max = 1024},
category = "chat"
})
ix.config.Add("chatColor", Color(255, 255, 150), "The default color for IC chat.", nil, {category = "chat"})
ix.config.Add("chatListenColor", Color(175, 255, 150), "The color for IC chat if you are looking at the speaker.", nil, {
category = "chat"
})
ix.config.Add("oocDelay", 10, "The delay before a player can use OOC chat again in seconds.", nil, {
data = {min = 0, max = 10000},
category = "chat"
})
ix.config.Add("allowGlobalOOC", true, "Whether or not Global OOC is enabled.", nil, {
category = "chat"
})
ix.config.Add("loocDelay", 0, "The delay before a player can use LOOC chat again in seconds.", nil, {
data = {min = 0, max = 10000},
category = "chat"
})
ix.config.Add("spawnTime", 5, "The time it takes to respawn.", nil, {
data = {min = 0, max = 10000},
category = "characters"
})
ix.config.Add("inventoryWidth", 6, "How many slots in a row there is in a default inventory.", nil, {
data = {min = 0, max = 20},
category = "characters"
})
ix.config.Add("inventoryHeight", 4, "How many slots in a column there is in a default inventory.", nil, {
data = {min = 0, max = 20},
category = "characters"
})
ix.config.Add("minNameLength", 4, "The minimum number of characters in a name.", nil, {
data = {min = 4, max = 64},
category = "characters"
})
ix.config.Add("maxNameLength", 32, "The maximum number of characters in a name.", nil, {
data = {min = 16, max = 128},
category = "characters"
})
ix.config.Add("minDescriptionLength", 16, "The minimum number of characters in a description.", nil, {
data = {min = 0, max = 300},
category = "characters"
})
ix.config.Add("descriptionDisplayLength", 256,
"The amount of characters of a description that will be displayed when someone look at the player.", nil, {
data = {min = 64, max = 2048},
category = "characters"
})
ix.config.Add("saveInterval", 300, "How often characters save in seconds.", nil, {
data = {min = 60, max = 3600},
category = "characters"
})
ix.config.Add("walkSpeed", 130, "How fast a player normally walks.", function(oldValue, newValue)
for _, v in ipairs(player.GetAll()) do
v:SetWalkSpeed(newValue)
end
end, {
data = {min = 75, max = 500},
category = "characters"
})
ix.config.Add("runSpeed", 235, "How fast a player normally runs.", function(oldValue, newValue)
for _, v in ipairs(player.GetAll()) do
v:SetRunSpeed(newValue)
end
end, {
data = {min = 75, max = 500},
category = "characters"
})
ix.config.Add("walkRatio", 0.5, "How fast one goes when holding ALT.", nil, {
data = {min = 0, max = 1, decimals = 1},
category = "characters"
})
ix.config.Add("jumpPower", 200, "How much force is behind ones jump.", function(oldValue, newValue)
for _, v in ipairs(player.GetAll()) do
v:SetJumpPower(newValue)
end
end, {
data = {min = 100, max = 400},
category = "characters"
})
ix.config.Add("intro", true, "Whether or not the Helix intro is enabled for new players.", nil, {
category = "appearance"
})
ix.config.Add("music", "music/hl2_song2.mp3", "The default music played in the character menu.", nil, {
category = "appearance"
})
ix.config.Add("communityURL",
"https://willard.network/forums/",
"The URL to navigate to when the community button is clicked.", nil, {
category = "appearance"
})
ix.config.Add("communityText", "@community",
"The text to display on the community button. You can use language phrases by prefixing with @", nil, {
category = "appearance"
})
ix.config.Add("vignette", true, "Whether or not the vignette is shown.", nil, {
category = "appearance"
})
ix.config.Add("scoreboardRecognition", false, "Whether or not recognition is used in the scoreboard.", nil, {
category = "characters"
})
ix.config.Add("defaultMoney", 0, "The amount of money that players start with.", nil, {
category = "characters",
data = {min = 0, max = 1000}
})
ix.config.Add("allowVoice", false, "Whether or not voice chat is allowed.", function(oldValue, newValue)
if (SERVER) then
hook.Run("VoiceToggled", newValue)
end
end, {
category = "server"
})
ix.config.Add("voiceDistance", 600.0, "How far can the voice be heard.", function(oldValue, newValue)
if (SERVER) then
hook.Run("VoiceDistanceChanged", newValue)
end
end, {
category = "server",
data = {min = 0, max = 5000, decimals = 1}
})
ix.config.Add("weaponAlwaysRaised", false, "Whether or not weapons are always raised.", nil, {
category = "server"
})
ix.config.Add("weaponRaiseTime", 1, "The time it takes for a weapon to raise.", nil, {
data = {min = 0.1, max = 60, decimals = 1},
category = "server"
})
ix.config.Add("maxHoldWeight", 100, "The maximum weight that a player can carry in their hands.", nil, {
data = {min = 1, max = 500},
category = "interaction"
})
ix.config.Add("throwForce", 732, "How hard a player can throw the item that they're holding.", nil, {
data = {min = 0, max = 8192},
category = "interaction"
})
ix.config.Add("allowPush", true, "Whether or not pushing with hands is allowed.", nil, {
category = "interaction"
})
ix.config.Add("pushOnly", false, "Whether or not punch damage is enabled.", nil, {
category = "interaction"
})
ix.config.Add("itemPickupTime", 0.5, "How long it takes to pick up and put an item in your inventory.", nil, {
data = {min = 0, max = 5, decimals = 1},
category = "interaction"
})
ix.config.Add("year", 2015, "The current in-game year.", function(oldValue, newValue)
if (SERVER and !ix.date.bSaving) then
ix.date.ResolveOffset()
ix.date.current:setyear(newValue)
ix.date.Send()
end
end, {
data = {min = 1, max = 9999},
category = "date"
})
ix.config.Add("month", 1, "The current in-game month.", function(oldValue, newValue)
if (SERVER and !ix.date.bSaving) then
ix.date.ResolveOffset()
ix.date.current:setmonth(newValue)
ix.date.Send()
end
end, {
data = {min = 1, max = 12},
category = "date"
})
ix.config.Add("day", 1, "The current in-game day.", function(oldValue, newValue)
if (SERVER and !ix.date.bSaving) then
ix.date.ResolveOffset()
ix.date.current:setday(newValue)
ix.date.Send()
end
end, {
data = {min = 1, max = 31},
category = "date"
})
ix.config.Add("secondsPerMinute", 60, "How many seconds it takes for a minute to pass in-game.", function(oldValue, newValue)
if (SERVER and !ix.date.bSaving) then
ix.date.UpdateTimescale(newValue)
ix.date.Send()
end
end, {
data = {min = 0.01, max = 120},
category = "date"
})

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/
--]]
if (CLIENT) then
ix.option.Add("animationScale", ix.type.number, 1, {
category = "appearance", min = 0.3, max = 2, decimals = 1
})
ix.option.Add("24hourTime", ix.type.bool, false, {
category = "appearance"
})
ix.option.Add("altLower", ix.type.bool, true, {
category = "general"
})
ix.option.Add("alwaysShowBars", ix.type.bool, false, {
category = "appearance"
})
ix.option.Add("noticeDuration", ix.type.number, 8, {
category = "appearance", min = 0.1, max = 20, decimals = 1
})
ix.option.Add("noticeMax", ix.type.number, 4, {
category = "appearance", min = 1, max = 20
})
ix.option.Add("cheapBlur", ix.type.bool, false, {
category = "performance"
})
ix.option.Add("disableAnimations", ix.type.bool, false, {
category = "performance"
})
ix.option.Add("openBags", ix.type.bool, true, {
category = "general"
})
ix.option.Add("showIntro", ix.type.bool, true, {
category = "general"
})
end
ix.option.Add("language", ix.type.array, ix.config.language or "english", {
category = "general",
bNetworked = true,
populate = function()
local entries = {}
for k, _ in SortedPairs(ix.lang.stored) do
local name = ix.lang.names[k]
local name2 = k:utf8sub(1, 1):utf8upper() .. k:utf8sub(2)
if (name) then
name = name .. " (" .. name2 .. ")"
else
name = name2
end
entries[k] = name
end
return entries
end
})

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