mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-18 06:03:47 +03:00
Upload
This commit is contained in:
354
lua/pac3/core/client/parts/projectile.lua
Normal file
354
lua/pac3/core/client/parts/projectile.lua
Normal file
@@ -0,0 +1,354 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
language.Add("pac_projectile", "Projectile")
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.ClassName = "projectile"
|
||||
PART.Group = 'advanced'
|
||||
PART.Icon = 'icon16/bomb.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Speed", 1)
|
||||
BUILDER:GetSet("AddOwnerSpeed", false)
|
||||
BUILDER:GetSet("Damping", 0)
|
||||
BUILDER:GetSet("Gravity", true)
|
||||
BUILDER:GetSet("Collisions", true)
|
||||
BUILDER:GetSet("Sphere", false)
|
||||
BUILDER:GetSet("Radius", 1)
|
||||
BUILDER:GetSet("DamageRadius", 50)
|
||||
BUILDER:GetSet("LifeTime", 5)
|
||||
BUILDER:GetSet("AimDir", false)
|
||||
BUILDER:GetSet("Sticky", false)
|
||||
BUILDER:GetSet("Bounce", 0)
|
||||
BUILDER:GetSet("BulletImpact", false)
|
||||
BUILDER:GetSet("Damage", 0)
|
||||
BUILDER:GetSet("DamageType", "generic", {enums = {
|
||||
generic = 0, --generic damage
|
||||
crush = 1, --caused by physics interaction
|
||||
bullet = 2, --bullet damage
|
||||
slash = 4, --sharp objects, such as manhacks or other npcs attacks
|
||||
burn = 8, --damage from fire
|
||||
vehicle = 16, --hit by a vehicle
|
||||
fall = 32, --fall damage
|
||||
blast = 64, --explosion damage
|
||||
club = 128, --crowbar damage
|
||||
shock = 256, --electrical damage, shows smoke at the damage position
|
||||
sonic = 512, --sonic damage,used by the gargantua and houndeye npcs
|
||||
energybeam = 1024, --laser
|
||||
nevergib = 4096, --don't create gibs
|
||||
alwaysgib = 8192, --always create gibs
|
||||
drown = 16384, --drown damage
|
||||
paralyze = 32768, --same as dmg_poison
|
||||
nervegas = 65536, --neurotoxin damage
|
||||
poison = 131072, --poison damage
|
||||
acid = 1048576, --
|
||||
airboat = 33554432, --airboat gun damage
|
||||
blast_surface = 134217728, --this won't hurt the player underwater
|
||||
buckshot = 536870912, --the pellets fired from a shotgun
|
||||
direct = 268435456, --
|
||||
dissolve = 67108864, --forces the entity to dissolve on death
|
||||
drownrecover = 524288, --damage applied to the player to restore health after drowning
|
||||
physgun = 8388608, --damage done by the gravity gun
|
||||
plasma = 16777216, --
|
||||
prevent_physics_force = 2048, --
|
||||
radiation = 262144, --radiation
|
||||
removenoragdoll = 4194304, --don't create a ragdoll on death
|
||||
slowburn = 2097152, --
|
||||
|
||||
explosion = -1, -- util.BlastDamage
|
||||
fire = -1, -- ent:Ignite(5)
|
||||
|
||||
-- env_entity_dissolver
|
||||
dissolve_energy = 0,
|
||||
dissolve_heavy_electrical = 1,
|
||||
dissolve_light_electrical = 2,
|
||||
dissolve_core_effect = 3,
|
||||
|
||||
heal = -1,
|
||||
armor = -1,
|
||||
}
|
||||
})
|
||||
BUILDER:GetSet("Spread", 0)
|
||||
BUILDER:GetSet("Delay", 0)
|
||||
BUILDER:GetSet("Maximum", 0)
|
||||
BUILDER:GetSet("Mass", 100)
|
||||
BUILDER:GetSet("Attract", 0)
|
||||
BUILDER:GetSet("AttractMode", "projectile_nearest", {enums = {
|
||||
hitpos = "hitpos",
|
||||
hitpos_radius = "hitpos_radius",
|
||||
closest_to_projectile = "closest_to_projectile",
|
||||
closest_to_hitpos = "closest_to_hitpos",
|
||||
}})
|
||||
BUILDER:GetSet("AttractRadius", 200)
|
||||
BUILDER:GetSetPart("OutfitPart")
|
||||
BUILDER:GetSet("Physical", false)
|
||||
BUILDER:GetSet("CollideWithOwner", false)
|
||||
BUILDER:GetSet("CollideWithSelf", false)
|
||||
BUILDER:GetSet("RemoveOnCollide", false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
PART.Translucent = false
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
-- TODO:
|
||||
-- this makes sure all the parents of this movable have an up-to-date draw position
|
||||
-- GetBonePosition implicitly uses ent:GetPos() as the parent origin which is really bad,
|
||||
-- it should instead be using what pac considers to be the position
|
||||
--self:GetRootPart():CallRecursive("Draw", "opaque")
|
||||
local parents = self:GetParentList()
|
||||
-- call draw from root to the current part only on direct parents to update the position hiearchy
|
||||
for i = #parents, 1, -1 do
|
||||
local part = parents[i]
|
||||
if part.Draw then
|
||||
part:Draw("opaque")
|
||||
end
|
||||
end
|
||||
self:Shoot(self:GetDrawPosition())
|
||||
end
|
||||
end
|
||||
|
||||
function PART:AttachToEntity(ent)
|
||||
if not self.OutfitPart:IsValid() then return false end
|
||||
|
||||
ent.pac_draw_distance = 0
|
||||
|
||||
local tbl = self.OutfitPart:ToTable()
|
||||
|
||||
local group = pac.CreatePart("group", self:GetPlayerOwner())
|
||||
group:SetShowInEditor(false)
|
||||
|
||||
local part = pac.CreatePart(tbl.self.ClassName, self:GetPlayerOwner(), tbl, tostring(tbl))
|
||||
group:AddChild(part)
|
||||
|
||||
group:SetOwner(ent)
|
||||
group.SetOwner = function(s) s.Owner = ent end
|
||||
part:SetHide(false)
|
||||
|
||||
local id = group.Id
|
||||
local owner_id = self:GetPlayerOwnerId()
|
||||
if owner_id then
|
||||
id = id .. owner_id
|
||||
end
|
||||
|
||||
ent:CallOnRemove("pac_projectile_" .. id, function() group:Remove() end)
|
||||
group:CallRecursive("Think")
|
||||
|
||||
ent.RenderOverride = ent.RenderOverride or function()
|
||||
if self.AimDir then
|
||||
ent:SetRenderAngles(ent:GetVelocity():Angle())
|
||||
end
|
||||
end
|
||||
|
||||
ent.pac_projectile_part = group
|
||||
ent.pac_projectile = self
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local enable = CreateClientConVar("pac_sv_projectiles", 0, true)
|
||||
|
||||
function PART:Shoot(pos, ang)
|
||||
local physics = self.Physical
|
||||
|
||||
if physics then
|
||||
if pac.LocalPlayer ~= self:GetPlayerOwner() then return end
|
||||
|
||||
local tbl = {}
|
||||
for key in pairs(self:GetStorableVars()) do
|
||||
tbl[key] = self[key]
|
||||
end
|
||||
|
||||
net.Start("pac_projectile")
|
||||
net.WriteVector(pos)
|
||||
net.WriteAngle(ang)
|
||||
net.WriteTable(tbl)
|
||||
net.SendToServer()
|
||||
else
|
||||
self.projectiles = self.projectiles or {}
|
||||
|
||||
local count = 0
|
||||
|
||||
for key, ent in pairs(self.projectiles) do
|
||||
if not ent:IsValid() then
|
||||
self.projectiles[key] = nil
|
||||
else
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
local max = math.min(self.Maximum, 100)
|
||||
|
||||
if max == 0 then
|
||||
max = 100
|
||||
end
|
||||
|
||||
if count > max then
|
||||
return
|
||||
end
|
||||
|
||||
local function spawn()
|
||||
|
||||
if not self:IsValid() then return end
|
||||
|
||||
local ent = pac.CreateEntity("models/props_junk/popcan01a.mdl")
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
local idx = table.insert(self.projectiles, ent)
|
||||
|
||||
ent:AddCallback("PhysicsCollide", function(ent, data)
|
||||
local phys = ent:GetPhysicsObject()
|
||||
if self.Bounce > 0 then
|
||||
timer.Simple(0, function()
|
||||
if phys:IsValid() then
|
||||
phys:SetVelocity(data.OurOldVelocity - 2 * (data.HitNormal:Dot(data.OurOldVelocity) * data.HitNormal) * self.Bounce)
|
||||
end
|
||||
end)
|
||||
elseif self.Sticky then
|
||||
phys:SetVelocity(Vector(0,0,0))
|
||||
phys:EnableMotion(false)
|
||||
ent.pac_stuck = data.OurOldVelocity
|
||||
end
|
||||
|
||||
if self.BulletImpact then
|
||||
ent:FireBullets{
|
||||
Attacker = ent:GetOwner(),
|
||||
Damage = 0,
|
||||
Force = 0,
|
||||
Num = 1,
|
||||
Src = data.HitPos - data.HitNormal,
|
||||
Dir = data.HitNormal,
|
||||
Distance = 10,
|
||||
}
|
||||
end
|
||||
|
||||
if self.RemoveOnCollide then
|
||||
timer.Simple(0.01, function() SafeRemoveEntity(ent) end)
|
||||
end
|
||||
end)
|
||||
|
||||
ent:SetOwner(self:GetPlayerOwner(true))
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
|
||||
if self.Sphere then
|
||||
ent:PhysicsInitSphere(math.Clamp(self.Radius, 1, 30))
|
||||
else
|
||||
ent:PhysicsInitBox(Vector(1,1,1) * - math.Clamp(self.Radius, 1, 30), Vector(1,1,1) * math.Clamp(self.Radius, 1, 30))
|
||||
end
|
||||
|
||||
ent.RenderOverride = function()
|
||||
if not self:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
if not self:GetRootPart():GetOwner():IsValid() then
|
||||
timer.Simple(0, function() SafeRemoveEntity(ent) end)
|
||||
end
|
||||
|
||||
if self.AimDir then
|
||||
if ent.pac_stuck then
|
||||
ent:SetRenderAngles(ent.pac_stuck:Angle())
|
||||
else
|
||||
local angle = ent:GetVelocity():Angle()
|
||||
ent:SetRenderAngles(angle)
|
||||
ent.last_angle = angle
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
phys:EnableGravity(self.Gravity)
|
||||
phys:AddVelocity((ang:Forward() + (VectorRand():Angle():Forward() * self.Spread)) * self.Speed * 1000)
|
||||
if self.AddOwnerSpeed and ent:GetOwner():IsValid() then
|
||||
phys:AddVelocity(ent:GetOwner():GetVelocity())
|
||||
end
|
||||
phys:EnableCollisions(self.Collisions)
|
||||
phys:SetDamping(self.Damping, 0)
|
||||
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
|
||||
if self:AttachToEntity(ent) then
|
||||
timer.Simple(math.Clamp(self.LifeTime, 0, 10), function()
|
||||
if ent:IsValid() then
|
||||
if ent.pac_projectile_part and ent.pac_projectile_part:IsValid() then
|
||||
ent.pac_projectile_part:Remove()
|
||||
end
|
||||
|
||||
timer.Simple(0.5, function()
|
||||
SafeRemoveEntity(ent)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Delay == 0 then
|
||||
spawn()
|
||||
else
|
||||
timer.Simple(self.Delay, spawn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if not self.Physical and self.projectiles then
|
||||
for key, ent in pairs(self.projectiles) do
|
||||
SafeRemoveEntity(ent)
|
||||
end
|
||||
|
||||
self.projectiles = {}
|
||||
end
|
||||
end
|
||||
--[[
|
||||
function PART:OnHide()
|
||||
if self.RemoveOnHide then
|
||||
self:OnRemove()
|
||||
end
|
||||
end
|
||||
]]
|
||||
do -- physical
|
||||
local Entity = Entity
|
||||
local projectiles = {}
|
||||
pac.AddHook("Think", "pac_projectile", function()
|
||||
for key, data in pairs(projectiles) do
|
||||
if not data.ply:IsValid() then
|
||||
projectiles[key] = nil
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
local ent = Entity(data.ent_id)
|
||||
|
||||
if ent:IsValid() and ent:GetClass() == "pac_projectile" then
|
||||
local part = pac.GetPartFromUniqueID(pac.Hash(data.ply), data.partuid)
|
||||
if part:IsValid() and part:GetPlayerOwner() == data.ply then
|
||||
part:AttachToEntity(ent)
|
||||
end
|
||||
projectiles[key] = nil
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("pac_projectile_attach", function()
|
||||
local ply = net.ReadEntity()
|
||||
local ent_id = net.ReadInt(16)
|
||||
local partuid = net.ReadString()
|
||||
|
||||
if ply:IsValid() then
|
||||
table.insert(projectiles, {ply = ply, ent_id = ent_id, partuid = partuid})
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
Reference in New Issue
Block a user