How do I make a projectile entity function like the HL2 Crossbow Bolt?

Hello everyone, I need help with my projectile weapon.

I’m currently working on a Fallout SWEPs Pack (it’s nothing too glamorous) and I’m stumped on my iteration of the Railway Rifle.

I would like to make it shoot a railway spike and send a person flying and optionally lodge itself in the corpse if it’s possible.

I opened up another SWEP to see how a custom projectile functions and I don’t understand how to make my projectile act like the crossbow bolt.

I shall leave my projectile code down below. Thank you in advance.

(I copied and repurposed the code from the dart_gun weapon available on garrysmod.org, which explains why it may be familiar to some of you gentlemen)

[lua]
AddCSLuaFile( “cl_init.lua” )
AddCSLuaFile( “shared.lua” )
include( ‘shared.lua’ )

function ENT:SpawnFunction( ply, tr )

if ( !tr.Hit ) then return end

local SpawnPos = tr.HitPos + tr.HitNormal * 16

local ent = ents.Create( "ent_railspike" )
	ent:SetPos( SpawnPos )
ent:Spawn()
ent:Activate()

return ent

end

/---------------------------------------------------------
Name: Initialize
---------------------------------------------------------
/
function ENT:Initialize()
self.Entity:SetModel( “models/Items/AR2_Grenade.mdl” )
self.Entity:SetSolid(SOLID_VPHYSICS)
self.Entity:PhysicsInit(MOVETYPE_VPHYSICS)
self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
self.Angles = self.Entity:GetAngles()
self.Entity:Fire(“kill”,"",10)
end

/---------------------------------------------------------
Name: PhysicsCollide
---------------------------------------------------------
/
function ENT:PhysicsCollide( data, physobj )
local target = data.HitEntity
local BadNpc = 0
if target:IsNPC() and (SERVER)then

	local ragdoll = ents.Create( "prop_ragdoll" )
	ragdoll:SetPos( target:GetPos())
	ragdoll:SetModel( target:GetModel() )
	ragdoll:SetAngles(Angle((target:GetAngles().p), (target:GetAngles().y), target:GetAngles().r))
	ragdoll:Spawn()
    target:Remove()
	ragdoll.ConvertToRagdoll = true
	ragdoll.Isnpc = true
	self:Remove()		

elseif target:IsPlayer()then
		
	target.PlyHp = target:Health()
    self:Remove()
else
self.Entity:GetPhysicsObject():EnableMotion( false )
self.Entity:SetAngles(self.Angles)
inactive = true

end
end

/---------------------------------------------------------
Name: OnTakeDamage
---------------------------------------------------------
/
function ENT:OnTakeDamage( dmginfo )
end

/---------------------------------------------------------
Name: Use
---------------------------------------------------------
/
function ENT:Use( activator, caller )
end

[/lua]

Here’s how I did it in my Lua crossbow. I probably didn’t write this code, but it should help. It also almost definitely has prediction errors.

In the SWEP:
[lua]
function SWEP:FireBolt()
if not self:CanPrimaryAttack() then return end
local ply = self.Owner

if not ply then return end

if SERVER then
	local pBolt = ents.Create("cbow_bolt_z")
	pBolt:SetPos(ply:GetShootPos())
	pBolt:SetAngles(ply:GetAimVector():Angle())
	pBolt.DamageDealt = self.Damage
	pBolt:SetOwner(ply)
	pBolt:Spawn()
end

ply:ViewPunch(Angle(-2, 0, 0))

self:EmitSound(self.ShootSoundSingle, nil, nil, nil, CHAN_WEAPON)

self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)

self.NextReload = CurTime() + self.Owner:GetViewModel():SequenceDuration() + 0.3

self:TakePrimaryAmmo(1)

end
[/lua]

entities/cbow_bolt_z.lua
[lua]
– Most code from mad cow, some from me
– .phy of the crossbow_bolt made by Silver Spirit

AddCSLuaFile()

ENT.Type = “anim”
ENT.Base = “base_anim”

ENT.PrintName = “CrossbowBolt”
ENT.Author = “Worshipper/Zerf”

ENT.RenderGroup = RENDERGROUP_TRANSLUCENT

ENT.Damage = 100
ENT.LifeTime = 4
ENT.Model = “models/crossbow_bolt.mdl”

function ENT:OnRemove()
end

function ENT:PhysicsUpdate()
end

if SERVER then
function ENT:Initialize()
self:SetModel(self.Model)
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
self:DrawShadow(false)

	-- Wake the physics object up. It's time to have fun!
	local phys = self:GetPhysicsObject()
	if IsValid(phys) then
		phys:EnableGravity(false)
		phys:EnableDrag(true)
		phys:SetMass(2)
		phys:Wake()
		phys:AddGameFlag(FVPHYSICS_NO_IMPACT_DMG)
		phys:AddGameFlag(FVPHYSICS_NO_NPC_IMPACT_DMG)
		phys:AddGameFlag(FVPHYSICS_PENETRATING)
	end

– local trail = util.SpriteTrail(self, 0, Color(255, 255, 255, 30), true, 2, 0, 3, 1 / (5.38) * 0.5, “trails/smoke.vmt”)
self.Moving = true
end
–[[
function ENT:PhysicsUpdate(phys)
local vel = Vector(0, 0, ((-9.81 * phys:GetMass()) * 0.65))
phys:ApplyForceCenter(vel)
end
–]]
function ENT:Impact(ent, normal, pos)
if not IsValid(self) then return end

	local info

	local tr = {}
	tr.start = self:GetPos()
	tr.filter = {self, self.Owner}
	tr.endpos = pos
	tr = util.TraceLine(tr)

	if tr.HitSky then self:Remove() return end

	if not ent:IsPlayer() and not ent:IsNPC() then
		local effectdata = EffectData()
		effectdata:SetOrigin(pos - normal * 10)
		effectdata:SetEntity(self)
		effectdata:SetStart(pos)
		effectdata:SetNormal(normal)
		util.Effect("Impact", effectdata)
	end

	if IsValid(ent) then
		ent:TakeDamage(self.DamageDealt, self.Owner)

		self:EmitSound("Weapon_Crossbow.BoltHitBody")
		self:Remove()
		return
	end

	self:EmitSound("Weapon_Crossbow.BoltHitWorld")

	-- We've hit a prop, so let's weld to it. Also embed this in the object for looks

	self:SetPos(pos - normal * 10)

– self:SetAngles(normal:Angle())

	if not IsValid(ent) then
		self:GetPhysicsObject():EnableMotion(false)
	end

	timer.Simple(self.LifeTime, function()
		if IsValid(self) then self:Remove() end
	end)
end

function ENT:PhysicsCollide(data, phys, dmg)
	if self.Moving then
		self.Moving = false
		phys:Sleep()
		self:Impact(data.HitEntity, data.HitNormal, data.HitPos)
	end
end

function ENT:Think()
	local phys	= self:GetPhysicsObject()
	local ang	= self:GetForward() * 100000
	local up	= self:GetUp() * -800

	local force = ang + up

	phys:ApplyForceCenter(force)

	if (self.HitWeld) then
		self.HitWeld = false
		constraint.Weld(self.HitEnt, self, 0, 0, 0, true)
	end
end

end

if CLIENT then
function ENT:Initialize()
self:DrawShadow(false)
end

function ENT:IsTranslucent()
	return true
end

function ENT:Draw()
	self:DrawModel()
end

end
[/lua]