mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
64
lua/entities/apchl2_hull/cl_init.lua
Normal file
64
lua/entities/apchl2_hull/cl_init.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
|
||||
include('shared.lua')
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
--[[
|
||||
if( SinglePlayer() ) then
|
||||
|
||||
function ENT:RenderOverride()
|
||||
|
||||
-- if( self:GetVelocity():Length() < 50 ) then self:DrawModel() return end
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
local speed = 1
|
||||
|
||||
if( phys:IsValid() ) then
|
||||
|
||||
print( "yay got phys" )
|
||||
speed = phys:GetAngleVelocity().y
|
||||
|
||||
end
|
||||
|
||||
local itr, max_iterations = 1, 8
|
||||
|
||||
for i=itr, max_iterations do
|
||||
|
||||
-- self:SetLocalAngles( 0,0,0 )
|
||||
local a = self:GetAngles()
|
||||
a:RotateAroundAxis( self:GetUp(), i * 3)
|
||||
|
||||
render.SetBlend( i / max_iterations )
|
||||
self:SetupBones()
|
||||
self:SetRenderAngles( a )
|
||||
self:DrawModel()
|
||||
--self:SetRenderAngles( nil )
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
]]--
|
||||
|
||||
function ENT:Draw()
|
||||
|
||||
-- self:SetupBones()
|
||||
self:DrawModel()
|
||||
|
||||
end
|
||||
|
||||
function ENT:CustomOnRemove()
|
||||
end
|
||||
37
lua/entities/apchl2_hull/init.lua
Normal file
37
lua/entities/apchl2_hull/init.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
--[[
|
||||
| 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' )
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
self:SetModel( "models/combine_apc2.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
//self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
self.PhysObj = self:GetPhysicsObject()
|
||||
|
||||
if ( self.PhysObj:IsValid() ) then
|
||||
|
||||
self.PhysObj:EnableDrag( true )
|
||||
self.PhysObj:Wake()
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
17
lua/entities/apchl2_hull/shared.lua
Normal file
17
lua/entities/apchl2_hull/shared.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
--[[
|
||||
| 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.Type = "anim"
|
||||
ENT.Author = "Hoffa"
|
||||
ENT.Category = "NeuroTec Helicopters";
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
331
lua/entities/arccw_ammo.lua
Normal file
331
lua/entities/arccw_ammo.lua
Normal file
@@ -0,0 +1,331 @@
|
||||
--[[
|
||||
| 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.Base = "base_entity"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Base Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
ENT.ArcCW_Ammo = true
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.Model = "models/items/sniper_round_box.mdl"
|
||||
ENT.MaxHealth = 40
|
||||
ENT.Scale = 1
|
||||
|
||||
ENT.AmmoType = "SniperPenetratedRound"
|
||||
ENT.AmmoCount = 5
|
||||
ENT.DetonationDamage = 10 -- Per-round damage
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/arccw/glock18/glock18-1.wav" -- string or table
|
||||
|
||||
ENT.ShellModel = "models/shells/shell_9mm.mdl"
|
||||
ENT.ShellScale = 1.5
|
||||
|
||||
ENT.ResistanceMult = {
|
||||
[DMG_BURN] = 3,
|
||||
[DMG_DIRECT] = 3, -- This is also fire
|
||||
[DMG_BLAST] = 2,
|
||||
[DMG_BULLET] = 0.5,
|
||||
[DMG_BUCKSHOT] = 0.5,
|
||||
[DMG_CLUB] = 0.25,
|
||||
[DMG_SLASH] = 0.25,
|
||||
[DMG_CRUSH] = 0.25,
|
||||
[DMG_NERVEGAS] = 0,
|
||||
[DMG_POISON] = 0
|
||||
}
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel(self.Model)
|
||||
self:SetHealth(math.max(math.ceil(self.MaxHealth * ArcCW.ConVars["mult_ammohealth"]:GetFloat()), 1))
|
||||
self.AmmoCount = math.max(math.ceil(self.AmmoCount * ArcCW.ConVars["mult_ammoamount"]:GetFloat(), 1))
|
||||
self.MaxAmmoCount = self.AmmoCount
|
||||
|
||||
if engine.ActiveGamemode() == "terrortown" and ArcCW.TTTReplaceTable then
|
||||
self.AmmoType = ArcCW.TTTReplaceTable[self.AmmoType] or self.AmmoType
|
||||
end
|
||||
|
||||
if self.Scale != 1 then
|
||||
self:SetModelScale(self.Scale)
|
||||
end
|
||||
|
||||
if self:SkinCount() > 1 and math.random() <= ArcCW.ConVars["ammo_rareskin"]:GetFloat() then
|
||||
self:SetSkin(math.random(1, self:SkinCount() - 1))
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
self:PhysWake()
|
||||
|
||||
self:SetTrigger(true) -- Enables Touch() to be called even when not colliding
|
||||
if ArcCW.ConVars["ammo_largetrigger"]:GetBool() then
|
||||
self:UseTriggerBounds(true, 24)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Adapted from TTT's ammo - we don't use it otherwise
|
||||
function ENT:TTT_PlayerCanPickup(ply)
|
||||
if ply == self:GetOwner() then return false end
|
||||
|
||||
local result = hook.Call("TTTCanPickupAmmo", nil, ply, self)
|
||||
if result then
|
||||
return result
|
||||
end
|
||||
|
||||
local ent = self
|
||||
local phys = ent:GetPhysicsObject()
|
||||
local spos = phys:IsValid() and phys:GetPos() or ent:OBBCenter()
|
||||
local epos = ply:GetShootPos()
|
||||
|
||||
local tr = util.TraceLine({start = spos, endpos = epos, filter = {ply, ent}, mask = MASK_SOLID})
|
||||
|
||||
-- can pickup if trace was not stopped
|
||||
return tr.Fraction == 1.0
|
||||
end
|
||||
|
||||
-- Ditto - unused outside of TTT
|
||||
function ENT:TTT_CheckForWeapon(ply)
|
||||
--[[]
|
||||
if !self.CachedWeapons then
|
||||
local tbl = {}
|
||||
for k,v in pairs(weapons.GetList()) do
|
||||
if v and v.Primary.Ammo == self.AmmoType then
|
||||
tbl[v.ClassName] = true -- WEPS.GetClass(v)
|
||||
end
|
||||
end
|
||||
self.CachedWeapons = tbl
|
||||
end
|
||||
]]
|
||||
|
||||
-- Why does TTT not iterate over the player's weapons? This is obviously faster
|
||||
for _, wep in ipairs(ply:GetWeapons()) do
|
||||
--if self.CachedWeapons[wep:GetClass()] then return true end
|
||||
-- Perform check for overwritten ammo types (attachments) and UBGLs
|
||||
if wep.ArcCW and
|
||||
(wep:GetBuff_Override("UBGL_Ammo") == self.AmmoType
|
||||
or wep:GetBuff_Override("Override_Ammo", wep.Primary.Ammo) == self.AmmoType
|
||||
or wep:GetBuff_Override("Akimbo_Ammo") == self.AmmoType) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:ApplyAmmo(ply)
|
||||
if self.USED then return end
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
-- Stupid checks mate... but we'll play along unless an override exists
|
||||
if !self.IgnoreTTTChecks and !self:TTT_PlayerCanPickup(ply) or !self:TTT_CheckForWeapon(ply) then return end
|
||||
|
||||
local giveCount = math.min(self.AmmoCount, ArcCW.TTTAmmoToClipMax[string.lower(self.AmmoType)] - ply:GetAmmoCount(self.AmmoType))
|
||||
if giveCount <= 0 then return end
|
||||
|
||||
self.AmmoCount = self.AmmoCount - giveCount
|
||||
ply:GiveAmmo(giveCount, self.AmmoType)
|
||||
|
||||
-- Ugly hack to let client update ammo count
|
||||
-- Why not just use NWInts or NetworkVars to begin with? Good question!
|
||||
self:SetNWInt("truecount", self.AmmoCount)
|
||||
|
||||
if self.AmmoCount <= 0 then
|
||||
self.USED = true
|
||||
self:Remove()
|
||||
end
|
||||
else
|
||||
self.USED = true -- Prevent multiple uses
|
||||
ply:GiveAmmo(self.AmmoCount, self.AmmoType)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DetonateRound()
|
||||
local count = math.Clamp(math.random(1, self.MaxAmmoCount / 5), 1, self.AmmoCount)
|
||||
-- Default function
|
||||
self:FireBullets({
|
||||
Attacker = self.Burner,
|
||||
Damage = self.DetonationDamage,
|
||||
Force = self.DetonationDamage / 5,
|
||||
Num = count,
|
||||
AmmoType = self.AmmoType,
|
||||
Src = self:WorldSpaceCenter(),
|
||||
Dir = self:GetUp(),
|
||||
Spread = Vector(math.pi * 2, math.pi * 2, 0),
|
||||
IgnoreEntity = self
|
||||
})
|
||||
self.AmmoCount = self.AmmoCount - count
|
||||
|
||||
self:GetPhysicsObject():AddVelocity(VectorRand() * math.random(30, 50) * self:GetPhysicsObject():GetMass())
|
||||
self:GetPhysicsObject():AddAngleVelocity(VectorRand() * math.random(60, 300))
|
||||
|
||||
if self.DetonationSound then
|
||||
self:EmitSound(istable(self.DetonationSound) and table.Random(self.DetonationSound) or self.DetonationSound)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Detonate(wet, attacker)
|
||||
if wet then
|
||||
self:FireBullets({
|
||||
Attacker = attacker,
|
||||
Damage = self.DetonationDamage,
|
||||
Force = self.DetonationDamage / 5,
|
||||
Num = math.max(self.AmmoCount, 50),
|
||||
AmmoType = self.AmmoType,
|
||||
Src = self:WorldSpaceCenter(),
|
||||
Dir = self:GetUp(),
|
||||
Spread = Vector(math.pi * 2, math.pi * 2, 0),
|
||||
IgnoreEntity = self
|
||||
})
|
||||
end
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(self:GetPos())
|
||||
util.Effect("Explosion", e)
|
||||
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.DetonationRadius, self.DetonationDamage * (wet and 0.5 or 1))
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
function ENT:Use(ply)
|
||||
if !ply:IsPlayer() then return end
|
||||
self:ApplyAmmo(ply)
|
||||
end
|
||||
|
||||
|
||||
function ENT:Touch(ply)
|
||||
if !ply:IsPlayer() or !ArcCW.ConVars["ammo_autopickup"]:GetBool() then return end
|
||||
self:ApplyAmmo(ply)
|
||||
end
|
||||
|
||||
function ENT:Burn(attacker)
|
||||
self.Burning = true
|
||||
self.Burner = attacker
|
||||
self:Ignite(30)
|
||||
self:SetHealth(-1)
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmginfo)
|
||||
|
||||
if self:Health() <= 0 or self.USED then return end
|
||||
|
||||
--self:TakePhysicsDamage(dmginfo)
|
||||
self:SetHealth(self:Health() - dmginfo:GetDamage())
|
||||
|
||||
if self:Health() <= 0 then
|
||||
|
||||
self.USED = true
|
||||
|
||||
local cvar = ArcCW.ConVars["ammo_detonationmode"]:GetInt()
|
||||
|
||||
if cvar == -1 or (!ArcCW.ConVars["ammo_chaindet"]:GetBool() and dmginfo:GetInflictor().ArcCW_Ammo) or self.DetonationDamage <= 0 then
|
||||
-- Go quietly
|
||||
local e = EffectData()
|
||||
e:SetOrigin(self:GetPos())
|
||||
e:SetMagnitude(8)
|
||||
e:SetScale(2)
|
||||
util.Effect("Sparks", e)
|
||||
self:EmitSound("physics/cardboard/cardboard_box_break2.wav", 80, 120)
|
||||
self:Remove()
|
||||
elseif cvar == 2 and (math.random() <= 0.25 or dmginfo:IsDamageType(DMG_BURN)) then
|
||||
-- Fancy ammobox burning
|
||||
self:Burn(dmginfo:GetAttacker())
|
||||
else
|
||||
-- Plain old explosion
|
||||
self:Detonate(cvar >= 1, dmginfo:GetAttacker())
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if self.Burning then
|
||||
|
||||
if self.AmmoCount <= 0 then
|
||||
self:Detonate(false, IsValid(self.Burner) and self.Burner or self)
|
||||
else
|
||||
self:DetonateRound()
|
||||
end
|
||||
|
||||
self:NextThink(CurTime() + math.random() * 0.3 + 0.2)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Do it during the hook so that hit damage numbers show up properly (yes, I am _that_ pedantic)
|
||||
hook.Add("EntityTakeDamage", "ArcCW_Ammo", function(ent, dmginfo)
|
||||
if ent.ArcCW_Ammo then
|
||||
if ArcCW.ConVars["mult_ammohealth"]:GetFloat() < 0 then
|
||||
dmginfo:ScaleDamage(0)
|
||||
elseif ent.ResistanceMult then
|
||||
-- Only apply one multiplier, and prioritize larger ones
|
||||
for k, v in SortedPairsByValue(ent.ResistanceMult, true) do if dmginfo:IsDamageType(k) then dmginfo:ScaleDamage(v) break end end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
elseif CLIENT then
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
self:Draw()
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local cvar2d3d = ArcCW.ConVars["2d3d"]:GetInt()
|
||||
if cvar2d3d == 0 or (cvar2d3d == 1 and LocalPlayer():GetEyeTrace().Entity != self) then return end
|
||||
|
||||
if (EyePos() - self:GetPos()):LengthSqr() <= 262144 then -- 512^2
|
||||
local ang = LocalPlayer():EyeAngles()
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), 180)
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
cam.Start3D2D(self:WorldSpaceCenter() + Vector(0, 0, (self:OBBMaxs().z - self:OBBMins().z) * 0.5 + 8) , ang, 0.1)
|
||||
surface.SetFont("ArcCW_32_Unscaled")
|
||||
|
||||
local w = surface.GetTextSize(self.PrintName)
|
||||
|
||||
surface.SetTextPos(-w / 2 + 2, 2)
|
||||
surface.SetTextColor(0, 0, 0, 150)
|
||||
surface.DrawText(self.PrintName)
|
||||
|
||||
surface.SetTextPos(-w / 2, 0)
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
surface.DrawText(self.PrintName)
|
||||
|
||||
local ammo = self:GetNWInt("truecount", -1) != -1 and self:GetNWInt("truecount", -1) or self.AmmoCount
|
||||
if ammo then
|
||||
w = surface.GetTextSize("×" .. ammo)
|
||||
|
||||
surface.SetTextColor(0, 0, 0, 150)
|
||||
surface.SetTextPos(-w / 2 + 2, 27)
|
||||
surface.DrawText("×" .. ammo)
|
||||
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
surface.SetTextPos(-w / 2, 25)
|
||||
surface.DrawText("×" .. ammo)
|
||||
end
|
||||
cam.End3D2D()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
32
lua/entities/arccw_ammo_357.lua
Normal file
32
lua/entities/arccw_ammo_357.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Magnum Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/magnum_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "357"
|
||||
ENT.AmmoCount = 12
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
ENT.AmmoType = "AlyxGun"
|
||||
ENT.AmmoCount = 18
|
||||
end
|
||||
|
||||
|
||||
ENT.DetonationDamage = 50
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "weapons/357_fire2.wav"
|
||||
28
lua/entities/arccw_ammo_357_large.lua
Normal file
28
lua/entities/arccw_ammo_357_large.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Magnum Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/magnum_ammo_closed.mdl"
|
||||
|
||||
ENT.AmmoType = "357"
|
||||
ENT.AmmoCount = 60
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.DetonationDamage = 50
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "weapons/357_fire2.wav"
|
||||
27
lua/entities/arccw_ammo_ar2.lua
Normal file
27
lua/entities/arccw_ammo_ar2.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Rifle Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/rifle_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "ar2"
|
||||
ENT.AmmoCount = 30
|
||||
|
||||
ENT.DetonationDamage = 50
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/ar1/ar1_dist2.wav"
|
||||
28
lua/entities/arccw_ammo_ar2_large.lua
Normal file
28
lua/entities/arccw_ammo_ar2_large.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Rifle Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/rifle_ammo.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "ar2"
|
||||
ENT.AmmoCount = 150
|
||||
|
||||
ENT.DetonationDamage = 50
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/ar1/ar1_dist2.wav"
|
||||
29
lua/entities/arccw_ammo_buckshot.lua
Normal file
29
lua/entities/arccw_ammo_buckshot.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Shotgun Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/shotgun_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "buckshot"
|
||||
ENT.AmmoCount = 20
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
ENT.AmmoCount = 12
|
||||
end
|
||||
|
||||
ENT.DetonationDamage = 80
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "weapons/shotgun/shotgun_fire6.wav"
|
||||
27
lua/entities/arccw_ammo_buckshot_large.lua
Normal file
27
lua/entities/arccw_ammo_buckshot_large.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Shotgun Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/shotgun_ammo_closed.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "buckshot"
|
||||
ENT.AmmoCount = 100
|
||||
|
||||
ENT.DetonationDamage = 80
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "weapons/shotgun/shotgun_fire6.wav"
|
||||
26
lua/entities/arccw_ammo_pistol.lua
Normal file
26
lua/entities/arccw_ammo_pistol.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Pistol Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/pistol_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "pistol"
|
||||
ENT.AmmoCount = 40
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/pistol/pistol_fire3.wav"
|
||||
27
lua/entities/arccw_ammo_pistol_large.lua
Normal file
27
lua/entities/arccw_ammo_pistol_large.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Pistol Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/pistol_ammo.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "pistol"
|
||||
ENT.AmmoCount = 200
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/pistol/pistol_fire3.wav"
|
||||
33
lua/entities/arccw_ammo_plinking.lua
Normal file
33
lua/entities/arccw_ammo_plinking.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Plinking Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/plinking_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "plinking"
|
||||
ENT.AmmoCount = 100
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = nil
|
||||
|
||||
DEFINE_BASECLASS(ENT.Base)
|
||||
function ENT:DetonateRound()
|
||||
BaseClass.DetonateRound(self)
|
||||
self:EmitSound("weapons/pistol/pistol_fire2.wav", 70, 175, 0.8)
|
||||
end
|
||||
34
lua/entities/arccw_ammo_plinking_large.lua
Normal file
34
lua/entities/arccw_ammo_plinking_large.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_ammo"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Plinking Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/plinking_ammo.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "plinking"
|
||||
ENT.AmmoCount = 500
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = nil
|
||||
|
||||
DEFINE_BASECLASS(ENT.Base)
|
||||
function ENT:DetonateRound()
|
||||
BaseClass.DetonateRound(self)
|
||||
self:EmitSound("weapons/pistol/pistol_fire2.wav", 70, 175, 0.8)
|
||||
end
|
||||
29
lua/entities/arccw_ammo_smg1.lua
Normal file
29
lua/entities/arccw_ammo_smg1.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Carbine Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/smg_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "smg1"
|
||||
ENT.AmmoCount = 60
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
ENT.AmmoCount = 30
|
||||
end
|
||||
|
||||
ENT.DetonationDamage = 30
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/smg1/npc_smg1_fire1.wav"
|
||||
49
lua/entities/arccw_ammo_smg1_grenade.lua
Normal file
49
lua/entities/arccw_ammo_smg1_grenade.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Rifle Grenade"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/Items/AR2_Grenade.mdl"
|
||||
ENT.Health = 15
|
||||
|
||||
ENT.AmmoType = "smg1_grenade"
|
||||
ENT.AmmoCount = 1
|
||||
|
||||
ENT.DetonationDamage = 50 -- Per-round damage
|
||||
ENT.DetonationRadius = 300
|
||||
|
||||
function ENT:DetonateRound(attacker)
|
||||
local nade = ents.Create("arccw_gl_ammodet")
|
||||
nade:SetPos(self:GetPos())
|
||||
nade:SetAngles(self:GetAngles() + AngleRand(-10, 10))
|
||||
nade:Spawn()
|
||||
nade:GetPhysicsObject():AddVelocity(self:GetVelocity() + self:GetForward() * math.random(500, 2000))
|
||||
nade:SetOwner(attacker or self.Burner)
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function ENT:Detonate(wet, attacker)
|
||||
if wet then
|
||||
self:DetonateRound(attacker)
|
||||
else
|
||||
local e = EffectData()
|
||||
e:SetOrigin(self:GetPos())
|
||||
util.Effect("Explosion", e)
|
||||
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.DetonationRadius, self.DetonationDamage)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
58
lua/entities/arccw_ammo_smg1_grenade_large.lua
Normal file
58
lua/entities/arccw_ammo_smg1_grenade_large.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Rifle Grenade Box"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/riflegrenade_ammo.mdl"
|
||||
ENT.Health = 70
|
||||
|
||||
ENT.AmmoType = "smg1_grenade"
|
||||
ENT.AmmoCount = 5
|
||||
|
||||
ENT.DetonationDamage = 100 -- Per-round damage
|
||||
ENT.DetonationRadius = 300
|
||||
|
||||
function ENT:DetonateRound(attacker)
|
||||
local nade = ents.Create("arccw_gl_ammodet")
|
||||
nade:SetPos(self:GetPos())
|
||||
local v = self:GetUp():Angle() + AngleRand(-60, 60)
|
||||
nade:SetAngles(v)
|
||||
nade:Spawn()
|
||||
nade:GetPhysicsObject():AddVelocity(self:GetVelocity() + self:GetForward() * math.random(2000, 3000))
|
||||
nade:SetOwner(attacker or self.Burner)
|
||||
|
||||
self.AmmoCount = self.AmmoCount - 1
|
||||
|
||||
self:GetPhysicsObject():AddVelocity(VectorRand() * math.random(5, 10) * self:GetPhysicsObject():GetMass())
|
||||
self:GetPhysicsObject():AddAngleVelocity(VectorRand() * math.random(60, 300))
|
||||
|
||||
self:EmitSound("weapons/ar2/ar2_altfire.wav", 80, 150)
|
||||
end
|
||||
|
||||
function ENT:Detonate(wet, attacker)
|
||||
if wet then
|
||||
for i = 1, math.random(1, 3) do
|
||||
self:DetonateRound(attacker)
|
||||
end
|
||||
end
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(self:GetPos())
|
||||
util.Effect("Explosion", e)
|
||||
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.DetonationRadius, self.DetonationDamage * (wet and 1 or 2))
|
||||
self:Remove()
|
||||
end
|
||||
27
lua/entities/arccw_ammo_smg1_large.lua
Normal file
27
lua/entities/arccw_ammo_smg1_large.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Carbine Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/smg_ammo.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "smg1"
|
||||
ENT.AmmoCount = 300
|
||||
|
||||
ENT.DetonationDamage = 30
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/smg1/npc_smg1_fire1.wav"
|
||||
30
lua/entities/arccw_ammo_sniper.lua
Normal file
30
lua/entities/arccw_ammo_sniper.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Sniper Ammo"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/sniper_ammo.mdl"
|
||||
|
||||
ENT.AmmoType = "SniperPenetratedRound"
|
||||
ENT.AmmoCount = 10
|
||||
ENT.MaxHealth = 20
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
ENT.AmmoType = "357"
|
||||
end
|
||||
|
||||
ENT.DetonationDamage = 80
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "npc/sniper/echo1.wav"
|
||||
28
lua/entities/arccw_ammo_sniper_large.lua
Normal file
28
lua/entities/arccw_ammo_sniper_large.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "Sniper Ammo (Large)"
|
||||
ENT.Category = "ArcCW - Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/items/arccw/sniper_ammo.mdl"
|
||||
ENT.Scale = 1.5
|
||||
|
||||
ENT.AmmoType = "SniperPenetratedRound"
|
||||
ENT.AmmoCount = 50
|
||||
ENT.MaxHealth = 20
|
||||
|
||||
ENT.DetonationDamage = 80
|
||||
ENT.DetonationRadius = 128
|
||||
ENT.DetonationSound = "npc/sniper/echo1.wav"
|
||||
142
lua/entities/arccw_att_base/shared.lua
Normal file
142
lua/entities/arccw_att_base/shared.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.PrintName = "Base Dropped Attachment"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
|
||||
ENT.Spawnable = false
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.Category = "ArcCW - Attachments"
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.GiveAttachments = nil -- table of all the attachments to give, and in what quantity. {{["id"] = int quantity}}
|
||||
|
||||
ENT.SoundImpact = "weapon.ImpactSoft"
|
||||
ENT.Model = ""
|
||||
|
||||
if SERVER then
|
||||
|
||||
function ENT:Initialize()
|
||||
if !self.Model then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self:SetModel(self.Model)
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self:SetTrigger( true )
|
||||
self:SetPos(self:GetPos() + Vector(0, 0, 4))
|
||||
local phys = self:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
phys:SetBuoyancyRatio(0)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, collider)
|
||||
if colData.DeltaTime < 0.25 then return end
|
||||
|
||||
self:EmitSound(self.SoundImpact)
|
||||
end
|
||||
|
||||
function ENT:Use(activator, caller)
|
||||
if !caller:IsPlayer() then return end
|
||||
|
||||
if ArcCW.ConVars["attinv_free"]:GetBool() then return end
|
||||
|
||||
local take = false
|
||||
|
||||
for i, k in pairs(self.GiveAttachments) do
|
||||
if i == "BaseClass" then continue end
|
||||
|
||||
if ArcCW.ConVars["attinv_lockmode"]:GetBool() then
|
||||
if ArcCW:PlayerGetAtts(caller, i) > 0 then
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
if hook.Run("ArcCW_PickupAttEnt", caller, i, k) then continue end
|
||||
|
||||
ArcCW:PlayerGiveAtt(caller, i, k)
|
||||
|
||||
take = true
|
||||
end
|
||||
|
||||
if take then
|
||||
ArcCW:PlayerSendAttInv(caller)
|
||||
|
||||
self:EmitSound("weapons/arccw/useatt.wav")
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local defaulticon = Material("arccw/hud/atts/default.png")
|
||||
local iw = 64
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
self:Draw()
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local cvar2d3d = ArcCW.ConVars["2d3d"]:GetInt()
|
||||
if cvar2d3d == 0 or (cvar2d3d == 1 and LocalPlayer():GetEyeTrace().Entity != self) then return end
|
||||
|
||||
if self.PrintName == "Base Dropped Attachment" and self:GetNWInt("attid", -1) != -1 then
|
||||
local att = ArcCW.AttachmentIDTable[self:GetNWInt("attid", -1)]
|
||||
|
||||
if !att then return end
|
||||
|
||||
local atttbl = ArcCW.AttachmentTable[att]
|
||||
|
||||
if !atttbl then return end
|
||||
|
||||
self.PrintName = atttbl.PrintName or att
|
||||
self.Icon = atttbl.Icon or defaulticon
|
||||
end
|
||||
|
||||
if (EyePos() - self:WorldSpaceCenter()):LengthSqr() <= 262144 then -- 512^2
|
||||
local ang = LocalPlayer():EyeAngles()
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), 180)
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
cam.Start3D2D(self:WorldSpaceCenter() + Vector(0, 0, 16), ang, 0.1)
|
||||
surface.SetFont("ArcCW_32_Unscaled")
|
||||
|
||||
local w = surface.GetTextSize(self.PrintName)
|
||||
surface.SetTextPos(-w / 2 + 2, 2)
|
||||
surface.SetTextColor(0, 0, 0, 150)
|
||||
surface.DrawText(self.PrintName)
|
||||
surface.SetTextPos(-w / 2, 0)
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
surface.DrawText(self.PrintName)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255)
|
||||
surface.SetMaterial(self.Icon or defaulticon)
|
||||
surface.DrawTexturedRect(-iw / 2, iw / 2, iw, iw)
|
||||
cam.End3D2D()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
59
lua/entities/arccw_att_dropped.lua
Normal file
59
lua/entities/arccw_att_dropped.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| 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 = "arccw_att_base"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
ENT.Category = "ArcCW - Attachments"
|
||||
ENT.PrintName = "Attachment Box"
|
||||
ENT.Spawnable = false
|
||||
|
||||
ENT.Model = "models/Items/BoxMRounds.mdl"
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local cvar2d3d = ArcCW.ConVars["2d3d"]:GetInt()
|
||||
if cvar2d3d == 0 or (cvar2d3d == 1 and LocalPlayer():GetEyeTrace().Entity != self) then return end
|
||||
|
||||
if (EyePos() - self:WorldSpaceCenter()):LengthSqr() <= 262144 then -- 512^2
|
||||
local ang = LocalPlayer():EyeAngles()
|
||||
local name = self:GetNWString("boxname", nil) or self.PrintName
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), 180)
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
cam.Start3D2D(self:WorldSpaceCenter() + Vector(0, 0, 14), ang, 0.1)
|
||||
surface.SetFont("ArcCW_32_Unscaled")
|
||||
local w = surface.GetTextSize(name)
|
||||
|
||||
surface.SetTextPos(-w / 2 + 2, 2)
|
||||
surface.SetTextColor(0, 0, 0, 150)
|
||||
surface.DrawText(name)
|
||||
|
||||
surface.SetTextPos(-w / 2, 0)
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
surface.DrawText(name)
|
||||
|
||||
local count = self:GetNWInt("boxcount", 0)
|
||||
local str = count .. " Attachment" .. (count != 1 and "s" or "")
|
||||
local w2 = surface.GetTextSize(str)
|
||||
|
||||
surface.SetTextPos(-w2 / 2 + 2, 26)
|
||||
surface.SetTextColor(0, 0, 0, 150)
|
||||
surface.DrawText(str)
|
||||
surface.SetTextPos(-w2 / 2, 24)
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
surface.DrawText(str)
|
||||
cam.End3D2D()
|
||||
end
|
||||
end
|
||||
126
lua/entities/arccw_gl_ammodet.lua
Normal file
126
lua/entities/arccw_gl_ammodet.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
--[[
|
||||
| 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.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.PrintName = "HE Round"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
|
||||
ENT.Spawnable = false
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Model = "models/items/ar2_grenade.mdl"
|
||||
ENT.Ticks = 0
|
||||
ENT.FuseTime = 10
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
|
||||
ENT.Ticks = 0
|
||||
|
||||
function ENT:Detonate()
|
||||
if !self:IsValid() then return end
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self:GetPos() )
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect( "WaterSurfaceExplosion", effectdata )
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
util.Effect( "Explosion", effectdata)
|
||||
self:EmitSound("phx/kaboom.wav", 125, 100, 1, CHAN_AUTO)
|
||||
end
|
||||
|
||||
local attacker = self
|
||||
|
||||
if self:GetOwner():IsValid() then
|
||||
attacker = self:GetOwner()
|
||||
end
|
||||
|
||||
util.BlastDamage(self, attacker, self:GetPos(), 300, 50)
|
||||
|
||||
self:FireBullets({
|
||||
Attacker = attacker,
|
||||
Damage = 0,
|
||||
Tracer = 0,
|
||||
Distance = 20000,
|
||||
Dir = self:GetVelocity(),
|
||||
Src = self:GetPos(),
|
||||
Callback = function(att, tr, dmg)
|
||||
util.Decal("Scorch", tr.StartPos, tr.HitPos - (tr.HitNormal * 16), self)
|
||||
end
|
||||
})
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function ENT:Think()
|
||||
if self.Ticks % 2 == 0 then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
|
||||
if !self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if !IsValid(emitter) then return end
|
||||
|
||||
local smoke = emitter:Add("particle/particle_smokegrenade", self:GetPos())
|
||||
smoke:SetVelocity( VectorRand() * 25 )
|
||||
smoke:SetGravity( Vector(math.Rand(-5, 5), math.Rand(-5, 5), math.Rand(-20, -25)) )
|
||||
smoke:SetDieTime( math.Rand(1.5, 2.0) )
|
||||
smoke:SetStartAlpha( 255 )
|
||||
smoke:SetEndAlpha( 0 )
|
||||
smoke:SetStartSize( 0 )
|
||||
smoke:SetEndSize( 100 )
|
||||
smoke:SetRoll( math.Rand(-180, 180) )
|
||||
smoke:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
smoke:SetColor( 20, 20, 20 )
|
||||
smoke:SetAirResistance( 5 )
|
||||
smoke:SetPos( self:GetPos() )
|
||||
smoke:SetLighting( false )
|
||||
emitter:Finish()
|
||||
end
|
||||
|
||||
self.Ticks = self.Ticks + 1
|
||||
end
|
||||
else
|
||||
|
||||
function ENT:Initialize()
|
||||
local pb_vert = 1
|
||||
local pb_hor = 1
|
||||
self:SetModel(self.Model)
|
||||
self:PhysicsInitBox( Vector(-pb_vert,-pb_hor,-pb_hor), Vector(pb_vert,pb_hor,pb_hor) )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self.SpawnTime = CurTime()
|
||||
|
||||
timer.Simple(0.1, function()
|
||||
if !IsValid(self) then return end
|
||||
self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if SERVER and CurTime() - self.SpawnTime >= self.FuseTime then
|
||||
self:Detonate()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, collider)
|
||||
self:Detonate()
|
||||
end
|
||||
|
||||
end
|
||||
131
lua/entities/arccw_smoke/shared.lua
Normal file
131
lua/entities/arccw_smoke/shared.lua
Normal file
@@ -0,0 +1,131 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.PrintName = "Smoke Cloud"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
local smokeimages = {"particle/smokesprites_0002", "particle/smokesprites_0003", "particle/smokesprites_0004", "particle/smokesprites_0005", "particle/smokesprites_0006", "particle/smokesprites_0007", "particle/smokesprites_0008", "particle/smokesprites_0009", "particle/smokesprites_0010", "particle/smokesprites_0011", "particle/smokesprites_0012", "particle/smokesprites_0013", "particle/smokesprites_0014", "particle/smokesprites_0015", "particle/smokesprites_0016"}
|
||||
|
||||
local function GetSmokeImage()
|
||||
return smokeimages[math.random(#smokeimages)]
|
||||
end
|
||||
|
||||
ENT.Particles = nil
|
||||
ENT.SmokeRadius = 256
|
||||
ENT.SmokeColor = Color(150, 150, 150)
|
||||
ENT.BillowTime = 1
|
||||
ENT.Life = 15
|
||||
|
||||
ENT.ArcCWSmoke = true
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
function ENT:Initialize()
|
||||
if SERVER then
|
||||
self:SetModel( "models/weapons/w_eq_smokegrenade_thrown.mdl" )
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_NONE )
|
||||
self:DrawShadow( false )
|
||||
else
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
|
||||
self.Particles = {}
|
||||
|
||||
local amt = 20
|
||||
|
||||
for i = 1, amt do
|
||||
local smoke = emitter:Add(GetSmokeImage(), self:GetPos())
|
||||
smoke:SetVelocity( VectorRand() * 8 + (Angle(0, i * (360 / amt), 0):Forward() * 400) )
|
||||
smoke:SetStartAlpha( 0 )
|
||||
smoke:SetEndAlpha( 255 )
|
||||
smoke:SetStartSize( 0 )
|
||||
smoke:SetEndSize( self.SmokeRadius )
|
||||
smoke:SetRoll( math.Rand(-180, 180) )
|
||||
smoke:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
smoke:SetColor( self.SmokeColor.r, self.SmokeColor.g, self.SmokeColor.b )
|
||||
smoke:SetAirResistance( 75 )
|
||||
smoke:SetPos( self:GetPos() )
|
||||
smoke:SetCollide( true )
|
||||
smoke:SetBounce( 0.2 )
|
||||
smoke:SetLighting( false )
|
||||
smoke:SetNextThink( CurTime() + FrameTime() )
|
||||
smoke.bt = CurTime() + self.BillowTime
|
||||
smoke.dt = CurTime() + self.BillowTime + self.Life
|
||||
smoke.ft = CurTime() + self.BillowTime + self.Life + math.Rand(2.5, 5)
|
||||
smoke:SetDieTime(smoke.ft)
|
||||
smoke.life = self.Life
|
||||
smoke.billowed = false
|
||||
smoke.radius = self.SmokeRadius
|
||||
smoke:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
|
||||
local prog = 1
|
||||
local alph = 0
|
||||
|
||||
if pa.ft < CurTime() then
|
||||
return
|
||||
elseif pa.dt < CurTime() then
|
||||
local d = (CurTime() - pa.dt) / (pa.ft - pa.dt)
|
||||
|
||||
alph = 1 - d
|
||||
elseif pa.bt < CurTime() then
|
||||
alph = 1
|
||||
else
|
||||
local d = math.Clamp(pa:GetLifeTime() / (pa.bt - CurTime()), 0, 1)
|
||||
|
||||
prog = (-d ^ 2) + (2 * d)
|
||||
|
||||
alph = d
|
||||
end
|
||||
|
||||
pa:SetEndSize( pa.radius * prog )
|
||||
pa:SetStartSize( pa.radius * prog )
|
||||
|
||||
pa:SetStartAlpha(255 * alph)
|
||||
pa:SetEndAlpha(255 * alph)
|
||||
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
|
||||
table.insert(self.Particles, smoke)
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
end
|
||||
|
||||
self.dt = CurTime() + self.Life + self.BillowTime
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
|
||||
if SERVER then
|
||||
local targets = ents.FindInSphere(self:GetPos(), 256)
|
||||
for _, k in pairs(targets) do
|
||||
if k:IsNPC() then
|
||||
k:SetSchedule(SCHED_STANDOFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.dt < CurTime() then
|
||||
if SERVER then
|
||||
SafeRemoveEntity(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
return false
|
||||
end
|
||||
143
lua/entities/arccw_uc_40mm_airburst.lua
Normal file
143
lua/entities/arccw_uc_40mm_airburst.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
--[[
|
||||
| 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Airburst"
|
||||
|
||||
ENT.GrenadeDamage = 75
|
||||
ENT.GrenadeRadius = 300
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = false
|
||||
ENT.DragCoefficient = 0.75
|
||||
ENT.DetonateOnImpact = false
|
||||
|
||||
ENT.NextTraceTime = 0
|
||||
|
||||
if SERVER then
|
||||
function ENT:Think()
|
||||
if SERVER and CurTime() - self.SpawnTime >= self.FuseTime then
|
||||
self:Detonate()
|
||||
end
|
||||
|
||||
if self.SpawnTime + 0.2 < CurTime() and self.NextTraceTime < CurTime() then
|
||||
self.NextTraceTime = CurTime() + 0.1
|
||||
|
||||
local dir = self:GetVelocity():GetNormalized()
|
||||
local deg = math.Clamp(1.5 - dir:Cross(Vector(0, 0, -1)):Length(), 0.5, 1)
|
||||
|
||||
local tr = util.TraceHull({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + dir * (1024 * deg),
|
||||
filter = self,
|
||||
mins = Vector(-16, -16, -8),
|
||||
maxs = Vector(16, 16, 8)
|
||||
})
|
||||
if tr.Hit then
|
||||
self:Detonate()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoDetonation()
|
||||
local attacker = IsValid(self:GetOwner()) and self:GetOwner() or self
|
||||
local dir = self:GetVelocity():GetNormalized()
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
effectdata:SetMagnitude(4)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(4)
|
||||
effectdata:SetNormal(dir)
|
||||
util.Effect("Sparks", effectdata)
|
||||
self:EmitSound("physics/metal/metal_box_break1.wav", 100, 200)
|
||||
end
|
||||
|
||||
-- The steeper the vertical angle, the higher the damage
|
||||
local deg = math.Clamp(1.5 - dir:Cross(Vector(0, 0, -1)):Length(), 0.5, 1)
|
||||
|
||||
self:FireBullets({
|
||||
Attacker = attacker,
|
||||
Damage = 25,
|
||||
Force = 5,
|
||||
Distance = 2048,
|
||||
HullSize = 16,
|
||||
Num = 64,
|
||||
Tracer = 1,
|
||||
Src = self:GetPos(),
|
||||
Dir = dir,
|
||||
Spread = Vector(1, 1, 0),
|
||||
IgnoreEntity = self,
|
||||
})
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetAttacker(IsValid(self:GetOwner()) and self:GetOwner() or self)
|
||||
dmg:SetDamageType(DMG_BULLET)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamageForce(self:GetVelocity() * 100)
|
||||
for _, ent in pairs(ents.FindInCone(self:GetPos(), dir, 1024, 0.707)) do
|
||||
local tr = util.QuickTrace(self:GetPos(), ent:WorldSpaceCenter() - self:GetPos(), self)
|
||||
if tr.Entity == ent then
|
||||
dmg:SetDamage(math.Rand(75, 150) * deg * math.Clamp(tr.Fraction, 0.5, 1))
|
||||
ent:TakeDamageInfo(dmg)
|
||||
end
|
||||
end
|
||||
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.GrenadeRadius, self.GrenadeDamage or self.Damage or 0)
|
||||
end
|
||||
|
||||
--[[]
|
||||
function ENT:BurstEffect()
|
||||
local dir = self:GetVelocity():GetNormalized()
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
if !self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if !IsValid(emitter) then return end
|
||||
for i = 1, 64 do
|
||||
local fire = emitter:Add("particles/smokey", self:GetPos())
|
||||
fire:SetVelocity( VectorRand() * 500 + dir * 1000 )
|
||||
fire:SetGravity( Vector(0, 0, -90) )
|
||||
fire:SetDieTime( math.Rand(0.25, 0.5) )
|
||||
fire:SetStartAlpha( 200 )
|
||||
fire:SetEndAlpha( 0 )
|
||||
fire:SetStartSize( 10 )
|
||||
fire:SetEndSize( 128 )
|
||||
fire:SetRoll( math.Rand(-180, 180) )
|
||||
fire:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
fire:SetColor( 255, 255, 255 )
|
||||
fire:SetAirResistance( 150 )
|
||||
fire:SetPos( self:GetPos() )
|
||||
fire:SetLighting( false )
|
||||
fire:SetCollide(true)
|
||||
fire:SetBounce(0.75)
|
||||
fire:SetNextThink( CurTime() + FrameTime() )
|
||||
fire:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
local col1 = Color(150, 150, 150)
|
||||
local col2 = Color(200, 200, 200)
|
||||
|
||||
local col3 = col1
|
||||
local d = pa:GetLifeTime() / pa:GetDieTime()
|
||||
col3.r = Lerp(d, col1.r, col2.r)
|
||||
col3.g = Lerp(d, col1.g, col2.g)
|
||||
col3.b = Lerp(d, col1.b, col2.b)
|
||||
|
||||
pa:SetColor(col3.r, col3.g, col3.b)
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
end
|
||||
emitter:Finish()
|
||||
end
|
||||
]]
|
||||
85
lua/entities/arccw_uc_40mm_dp.lua
Normal file
85
lua/entities/arccw_uc_40mm_dp.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
--[[
|
||||
| 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm HE Dual Purpose Grenade"
|
||||
|
||||
ENT.GrenadeDamage = false
|
||||
ENT.GrenadeRadius = 300
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = false
|
||||
|
||||
function ENT:DoDetonation()
|
||||
local dir = self.GrenadeDir or self:GetVelocity():GetNormalized()
|
||||
local attacker = IsValid(self:GetOwner()) and self:GetOwner() or self
|
||||
local damage = self.GrenadeDamage or self.Damage or 0
|
||||
local blastpos = self:GetPos()
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + dir * 64,
|
||||
filter = self
|
||||
})
|
||||
if IsValid(tr.Entity) then
|
||||
-- do impact damage
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetAttacker(attacker)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamage(damage * 10)
|
||||
dmg:SetDamageForce(dir * 3000)
|
||||
dmg:SetDamagePosition(tr.HitPos)
|
||||
tr.Entity:TakeDamageInfo(dmg)
|
||||
end
|
||||
-- attempt to penetrate entity/world and place explosion behind
|
||||
local tr2 = util.TraceLine({
|
||||
start = tr.HitPos + dir * 69,
|
||||
endpos = tr.HitPos,
|
||||
filter = self,
|
||||
})
|
||||
|
||||
if tr2.Hit and !tr2.StartSolid then
|
||||
-- Produce a weaker blast on the pre-penetration side
|
||||
util.BlastDamage(self, attacker, blastpos, self.GrenadeRadius, damage * 0.5)
|
||||
|
||||
blastpos = tr2.HitPos + dir * 16
|
||||
self:EmitSound("physics/concrete/concrete_break2.wav", 100, 110)
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
effectdata:SetMagnitude(2)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(2)
|
||||
effectdata:SetNormal(-dir)
|
||||
util.Effect("Sparks", effectdata)
|
||||
effectdata:SetOrigin(blastpos)
|
||||
effectdata:SetNormal(dir)
|
||||
util.Effect("Sparks", effectdata)
|
||||
end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(blastpos)
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
self:EmitSound(self.ExplosionSounds[math.random(1,#self.ExplosionSounds)], 125, 100, 1, CHAN_AUTO)
|
||||
ParticleEffect("explosion_grenade_fas2", self:GetPos(), tr.HitNormal:Angle())
|
||||
if tr2.Hit and !tr2.StartSolid then
|
||||
ParticleEffect("explosion_he_m79_fas2", tr2.StartPos, tr.HitNormal:Angle() * -1)
|
||||
end
|
||||
if self.DebrisSounds then
|
||||
self:EmitSound(self.DebrisSounds[math.random(1,#self.DebrisSounds)], 85, 100, 1, CHAN_AUTO)
|
||||
end
|
||||
end
|
||||
|
||||
util.ScreenShake(self:GetPos(),25,4,.75,self.GrenadeRadius * 4)
|
||||
util.BlastDamage(self, attacker, blastpos, self.GrenadeRadius, damage)
|
||||
end
|
||||
87
lua/entities/arccw_uc_40mm_dummy.lua
Normal file
87
lua/entities/arccw_uc_40mm_dummy.lua
Normal 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()
|
||||
|
||||
ENT.Base = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Dummy Grenade"
|
||||
|
||||
ENT.GrenadeDamage = 50
|
||||
ENT.GrenadeRadius = 150
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = "PaintSplatBlue"
|
||||
|
||||
function ENT:DoDetonation()
|
||||
--[[]
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
effectdata:SetMagnitude(4)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(4)
|
||||
effectdata:SetNormal(self:GetVelocity():GetNormalized())
|
||||
util.Effect("Sparks", effectdata)
|
||||
]]
|
||||
self:EmitSound("physics/cardboard/cardboard_box_break2.wav", 80, 110)
|
||||
end
|
||||
|
||||
function ENT:DoImpact(ent)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function ENT:Think()
|
||||
self.NextSmoke = self.NextSmoke or CurTime()
|
||||
if self.SmokeTrail and self.NextSmoke < CurTime() then
|
||||
self.NextSmoke = CurTime() + 0.025 / math.Clamp(self:GetVelocity():Length() / 1000, 1, 5)
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
if not self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if not IsValid(emitter) then return end
|
||||
local smoke = emitter:Add("particle/smokestack", self:GetPos())
|
||||
smoke:SetVelocity(VectorRand() * 2)
|
||||
smoke:SetGravity(Vector(0, 0, -3))
|
||||
smoke:SetDieTime(math.Rand(2, 3))
|
||||
smoke:SetStartAlpha(150)
|
||||
smoke:SetEndAlpha(0)
|
||||
smoke:SetStartSize(math.Rand(3, 5))
|
||||
smoke:SetEndSize(20)
|
||||
smoke:SetRoll(math.Rand(-180, 180))
|
||||
smoke:SetRollDelta(math.Rand(-0.1, 0.1))
|
||||
smoke:SetColor(150, 150, math.Rand(220, 255))
|
||||
smoke:SetAirResistance(5)
|
||||
smoke:SetPos(self:GetPos())
|
||||
smoke:SetLighting(false)
|
||||
emitter:Finish()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
if not self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if not IsValid(emitter) then return end
|
||||
for i = 1, 10 do
|
||||
local smoke = emitter:Add("particle/smokestack", self:GetPos())
|
||||
smoke:SetVelocity(VectorRand() * 100)
|
||||
smoke:SetGravity(Vector(math.Rand(-5, 5), math.Rand(-5, 5), -25))
|
||||
smoke:SetDieTime(math.Rand(5, 7))
|
||||
smoke:SetStartAlpha(100)
|
||||
smoke:SetEndAlpha(0)
|
||||
smoke:SetStartSize(math.Rand(10, 15))
|
||||
smoke:SetEndSize(75)
|
||||
smoke:SetRoll(math.Rand(-180, 180))
|
||||
smoke:SetRollDelta(math.Rand(-0.5, 0.5))
|
||||
smoke:SetColor(150, 150, math.Rand(220, 255))
|
||||
smoke:SetAirResistance(150)
|
||||
smoke:SetPos(self:GetPos())
|
||||
smoke:SetLighting(false)
|
||||
smoke:SetBounce(0.5)
|
||||
smoke:SetCollide(true)
|
||||
end
|
||||
emitter:Finish()
|
||||
end
|
||||
end
|
||||
80
lua/entities/arccw_uc_40mm_flash.lua
Normal file
80
lua/entities/arccw_uc_40mm_flash.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--[[
|
||||
| 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Flash Grenade"
|
||||
|
||||
ENT.GrenadeDamage = 50
|
||||
ENT.GrenadeRadius = 150
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = false
|
||||
|
||||
function ENT:DoDetonation()
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
effectdata:SetMagnitude(4)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(4)
|
||||
effectdata:SetNormal(self:GetVelocity():GetNormalized())
|
||||
util.Effect("Sparks", effectdata)
|
||||
self:EmitSound("physics/metal/metal_box_break1.wav", 100, 200, 0.5)
|
||||
end
|
||||
|
||||
-- TODO: these sounds need to be replaced (dependency)!
|
||||
self:EmitSound("weapons/arccw/flashbang/flashbang_explode1.wav", 100, 100, 1, CHAN_AUTO)
|
||||
self:EmitSound("weapons/arccw/flashbang/flashbang_explode1_distant.wav", 140, 100, 1, CHAN_AUTO)
|
||||
|
||||
util.Effect( "arccw_flashexplosion", effectdata)
|
||||
|
||||
local flashorigin = self:GetPos()
|
||||
|
||||
local flashpower = 512
|
||||
local targets = ents.FindInSphere(flashorigin, flashpower)
|
||||
|
||||
for _, k in pairs(targets) do
|
||||
if k:IsPlayer() then
|
||||
local dist = k:EyePos():Distance(flashorigin)
|
||||
local dp = (k:EyePos() - flashorigin):Dot(k:EyeAngles():Forward())
|
||||
|
||||
local time = Lerp( dp, 2.5, 0.25 )
|
||||
|
||||
time = Lerp( dist / flashpower, time, 0 )
|
||||
|
||||
if k:VisibleVec( flashorigin ) then
|
||||
k:ScreenFade( SCREENFADE.IN, Color( 255, 255, 255, 255 ), 2.5, time )
|
||||
end
|
||||
|
||||
k:SetDSP(37, false)
|
||||
|
||||
elseif k:IsNPC() then
|
||||
|
||||
k:SetNPCState(NPC_STATE_PLAYDEAD)
|
||||
|
||||
if timer.Exists( k:EntIndex() .. "_arccw_flashtimer" ) then
|
||||
timer.Remove( k:EntIndex() .. "_arccw_flashtimer" )
|
||||
end
|
||||
|
||||
timer.Create( k:EntIndex() .. "_arccw_flashtimer", 10, 1, function()
|
||||
if !k:IsValid() then return end
|
||||
k:SetNPCState(NPC_STATE_ALERT)
|
||||
end)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
20
lua/entities/arccw_uc_40mm_he.lua
Normal file
20
lua/entities/arccw_uc_40mm_he.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_uc_riflegrenade"
|
||||
ENT.PrintName = "40mm HE"
|
||||
|
||||
ENT.GrenadeDamage = false
|
||||
ENT.GrenadeRadius = 300
|
||||
ENT.DragCoefficient = 0.25
|
||||
|
||||
ENT.Model = "models/items/ar2_grenade.mdl"
|
||||
47
lua/entities/arccw_uc_40mm_hv.lua
Normal file
47
lua/entities/arccw_uc_40mm_hv.lua
Normal file
@@ -0,0 +1,47 @@
|
||||
--[[
|
||||
| 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm High Velocity"
|
||||
|
||||
ENT.GrenadeDamage = false
|
||||
ENT.GrenadeRadius = 200
|
||||
ENT.DragCoefficient = 0
|
||||
|
||||
ENT.Model = "models/weapons/shell.mdl"
|
||||
|
||||
if CLIENT then
|
||||
function ENT:Think()
|
||||
if self.Ticks % 3 == 0 then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
if not self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if not IsValid(emitter) then return end
|
||||
|
||||
local smoke = emitter:Add("particle/particle_smokegrenade", self:GetPos())
|
||||
smoke:SetVelocity(VectorRand() * 25)
|
||||
smoke:SetGravity(Vector(math.Rand(-5, 5), math.Rand(-5, 5), math.Rand(-20, -25)))
|
||||
smoke:SetDieTime(math.Rand(1.5, 2.0))
|
||||
smoke:SetStartAlpha(255)
|
||||
smoke:SetEndAlpha(0)
|
||||
smoke:SetStartSize(0)
|
||||
smoke:SetEndSize(60)
|
||||
smoke:SetRoll(math.Rand(-180, 180))
|
||||
smoke:SetRollDelta(math.Rand(-0.2, 0.2))
|
||||
smoke:SetColor(100, 100, 100)
|
||||
smoke:SetAirResistance(5)
|
||||
smoke:SetPos(self:GetPos())
|
||||
smoke:SetLighting(false)
|
||||
emitter:Finish()
|
||||
end
|
||||
self.Ticks = self.Ticks + 1
|
||||
end
|
||||
end
|
||||
42
lua/entities/arccw_uc_40mm_incendiary.lua
Normal file
42
lua/entities/arccw_uc_40mm_incendiary.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Incendiary"
|
||||
|
||||
ENT.GrenadeDamage = 50
|
||||
ENT.GrenadeRadius = 150
|
||||
|
||||
function ENT:DoDetonation()
|
||||
local attacker = IsValid(self:GetOwner()) and self:GetOwner() or self
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.GrenadeRadius, self.GrenadeDamage)
|
||||
self:EmitSound("ambient/fire/gascan_ignite1.wav", 100, 100, 1)
|
||||
|
||||
for i = 1, 5 do
|
||||
local cloud = ents.Create("arccw_uc_fire")
|
||||
cloud.FireTime = 20
|
||||
|
||||
if !IsValid(cloud) then return end
|
||||
|
||||
local vel = Vector(math.Rand(-1, 1), math.Rand(-1, 1), math.Rand(-1, 1)) * 1500
|
||||
|
||||
cloud.Order = i
|
||||
cloud:SetPos(self:GetPos() - (self:GetVelocity() * FrameTime()) * 3 + VectorRand())
|
||||
cloud:SetAbsVelocity(vel + self:GetVelocity())
|
||||
cloud:SetOwner(self:GetOwner())
|
||||
cloud:Spawn()
|
||||
end
|
||||
end
|
||||
|
||||
--[[att.Hook_FireBullets = function(wep, data) this thing doesn't actually call firebullets lol
|
||||
wep:EmitSound("DB_ADD") -- lua/arccw/shared/sh_0_uc.lua
|
||||
end]]
|
||||
82
lua/entities/arccw_uc_40mm_napalm.lua
Normal file
82
lua/entities/arccw_uc_40mm_napalm.lua
Normal 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Napalm"
|
||||
|
||||
ENT.GrenadeDamage = 50
|
||||
ENT.GrenadeRadius = 150
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = false
|
||||
ENT.DragCoefficient = 0.75
|
||||
ENT.DetonateOnImpact = false
|
||||
|
||||
ENT.NextTraceTime = 0
|
||||
|
||||
if SERVER then
|
||||
function ENT:Think()
|
||||
if SERVER and CurTime() - self.SpawnTime >= self.FuseTime then
|
||||
self:Detonate()
|
||||
end
|
||||
|
||||
if self.SpawnTime + 0.2 < CurTime() and self.NextTraceTime < CurTime() then
|
||||
self.NextTraceTime = CurTime() + 0.1
|
||||
local dir = self:GetVelocity():GetNormalized()
|
||||
local tr = util.TraceHull({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + dir * 512,
|
||||
filter = self,
|
||||
mins = Vector(-16, -16, -8),
|
||||
maxs = Vector(16, 16, 8)
|
||||
})
|
||||
if tr.Hit then
|
||||
self:Detonate()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoDetonation()
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
effectdata:SetMagnitude(4)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(4)
|
||||
effectdata:SetNormal(self:GetVelocity():GetNormalized())
|
||||
util.Effect("Sparks", effectdata)
|
||||
self:EmitSound("physics/metal/metal_box_break1.wav", 100, 200)
|
||||
self:EmitSound("ambient/fire/gascan_ignite1.wav", 100, 100, 0.75)
|
||||
end
|
||||
|
||||
for i = 1, math.random(5, 7) do
|
||||
local cloud = ents.Create("arccw_uc_napalm")
|
||||
cloud.FireTime = math.Rand(20, 40)
|
||||
|
||||
if !IsValid(cloud) then return end
|
||||
|
||||
local vel = VectorRand() * 500
|
||||
|
||||
cloud.Order = i
|
||||
cloud:SetPos(self:GetPos() - (self:GetVelocity() * FrameTime()) + VectorRand())
|
||||
--cloud:SetAbsVelocity(vel + self:GetVelocity())
|
||||
cloud:SetOwner(self:GetOwner())
|
||||
cloud:Spawn()
|
||||
cloud:GetPhysicsObject():SetVelocityInstantaneous(self:GetVelocity() + vel)
|
||||
|
||||
end
|
||||
end
|
||||
48
lua/entities/arccw_uc_40mm_smoke.lua
Normal file
48
lua/entities/arccw_uc_40mm_smoke.lua
Normal file
@@ -0,0 +1,48 @@
|
||||
--[[
|
||||
| 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 = "arccw_uc_40mm_he"
|
||||
ENT.PrintName = "40mm Smoke Grenade"
|
||||
|
||||
ENT.GrenadeDamage = 50
|
||||
ENT.GrenadeRadius = 150
|
||||
ENT.ExplosionEffect = false
|
||||
ENT.Scorch = false
|
||||
|
||||
function ENT:DoDetonation()
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
effectdata:SetMagnitude(4)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(4)
|
||||
effectdata:SetNormal(self:GetVelocity():GetNormalized())
|
||||
util.Effect("Sparks", effectdata)
|
||||
self:EmitSound("physics/metal/metal_box_break1.wav", 100, 200, 0.5)
|
||||
end
|
||||
|
||||
-- TODO: these sounds need to be replaced (dependency)!
|
||||
self:EmitSound("weapons/arccw/smokegrenade/smoke_emit.wav", 90, 100, 1, CHAN_AUTO)
|
||||
|
||||
local cloud = ents.Create( "arccw_smoke" )
|
||||
|
||||
if !IsValid(cloud) then return end
|
||||
|
||||
cloud:SetPos(self:GetPos())
|
||||
cloud:Spawn()
|
||||
|
||||
end
|
||||
205
lua/entities/arccw_uc_fire.lua
Normal file
205
lua/entities/arccw_uc_fire.lua
Normal file
@@ -0,0 +1,205 @@
|
||||
--[[
|
||||
| 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.Base = "base_entity"
|
||||
ENT.PrintName = "Fire Particle"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.Model = "models/Items/AR2_Grenade.mdl"
|
||||
|
||||
ENT.FireTime = 20
|
||||
|
||||
ENT.Armed = false
|
||||
|
||||
ENT.NextDamageTick = 0
|
||||
|
||||
ENT.Ticks = 0
|
||||
|
||||
ENT.ArcCW_Killable = false
|
||||
|
||||
function ENT:Initialize()
|
||||
if SERVER then
|
||||
self:SetModel( self.Model )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
local maxs = Vector(1, 1, 1)
|
||||
local mins = -maxs
|
||||
self:PhysicsInitBox(mins, maxs)
|
||||
self:DrawShadow( false )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
phys:SetBuoyancyRatio(0)
|
||||
end
|
||||
|
||||
self.SpawnTime = CurTime()
|
||||
self:Detonate()
|
||||
|
||||
self.FireTime = math.Rand(self.FireTime - 1, self.FireTime + 1)
|
||||
end
|
||||
end
|
||||
|
||||
local fired = {
|
||||
"sprites/flamelet1",
|
||||
"sprites/flamelet2",
|
||||
"sprites/flamelet3",
|
||||
"sprites/flamelet4",
|
||||
"sprites/flamelet5",
|
||||
}
|
||||
local function GetFireParticle()
|
||||
return fired[math.random(#fired)]
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if !self.SpawnTime then self.SpawnTime = CurTime() end
|
||||
|
||||
if CLIENT then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
|
||||
if !self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if !IsValid(emitter) then return end
|
||||
|
||||
if math.random(1, 100) < 10 then
|
||||
local fire = emitter:Add(GetFireParticle(), self:GetPos() + (VectorRand() * 16))
|
||||
fire:SetVelocity( VectorRand() * 500 * VectorRand() )
|
||||
fire:SetGravity( Vector(0, 0, 100) )
|
||||
fire:SetDieTime( math.Rand(0.5, 0.75) )
|
||||
fire:SetStartAlpha( 255 )
|
||||
fire:SetEndAlpha( 0 )
|
||||
fire:SetStartSize( 25 )
|
||||
fire:SetEndSize( 100 )
|
||||
fire:SetRoll( math.Rand(-180, 180) )
|
||||
fire:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
fire:SetColor( 255, 255, 255 )
|
||||
fire:SetAirResistance( 150 )
|
||||
fire:SetPos( self:GetPos() )
|
||||
fire:SetLighting( false )
|
||||
fire:SetCollide(true)
|
||||
fire:SetBounce(0.75)
|
||||
fire:SetNextThink( CurTime() + FrameTime() )
|
||||
fire:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
local col1 = Color(255, 255, 255)
|
||||
local col2 = Color(0, 0, 0)
|
||||
|
||||
local col3 = col1
|
||||
local d = pa:GetLifeTime() / pa:GetDieTime()
|
||||
col3.r = Lerp(d, col1.r, col2.r)
|
||||
col3.g = Lerp(d, col1.g, col2.g)
|
||||
col3.b = Lerp(d, col1.b, col2.b)
|
||||
|
||||
pa:SetColor(col3.r, col3.g, col3.b)
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
end
|
||||
|
||||
if math.random(1, 100) < 5 then
|
||||
local fire = emitter:Add("particles/smokey", self:GetPos())
|
||||
fire:SetVelocity( VectorRand() * 25 )
|
||||
fire:SetGravity( Vector(0, 0, 1500) )
|
||||
fire:SetDieTime( math.Rand(0.25, 1) )
|
||||
fire:SetStartAlpha( 255 )
|
||||
fire:SetEndAlpha( 0 )
|
||||
fire:SetStartSize( 10 )
|
||||
fire:SetEndSize( 150 )
|
||||
fire:SetRoll( math.Rand(-180, 180) )
|
||||
fire:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
fire:SetColor( 255, 255, 255 )
|
||||
fire:SetAirResistance( 150 )
|
||||
fire:SetPos( self:GetPos() )
|
||||
fire:SetLighting( false )
|
||||
fire:SetCollide(true)
|
||||
fire:SetBounce(0.75)
|
||||
fire:SetNextThink( CurTime() + FrameTime() )
|
||||
fire:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
local col1 = Color(255, 135, 0)
|
||||
local col2 = Color(150, 150, 150)
|
||||
|
||||
local col3 = col1
|
||||
local d = pa:GetLifeTime() / pa:GetDieTime()
|
||||
col3.r = Lerp(d, col1.r, col2.r)
|
||||
col3.g = Lerp(d, col1.g, col2.g)
|
||||
col3.b = Lerp(d, col1.b, col2.b)
|
||||
|
||||
pa:SetColor(col3.r, col3.g, col3.b)
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
|
||||
self.Ticks = self.Ticks + 1
|
||||
else
|
||||
|
||||
if self:GetVelocity():LengthSqr() <= 32 then
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
end
|
||||
|
||||
if self.NextDamageTick > CurTime() then return end
|
||||
|
||||
if self:WaterLevel() > 2 then self:Remove() return end
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamageType(DMG_BURN)
|
||||
dmg:SetDamage(math.Round(math.random() * 2 + 3))
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetAttacker(self:GetOwner())
|
||||
util.BlastDamageInfo(dmg, self:GetPos(), 200)
|
||||
|
||||
self.NextDamageTick = CurTime() + 0.15
|
||||
|
||||
if self.SpawnTime + self.FireTime <= CurTime() then self:Remove() return end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if !self.FireSound then return end
|
||||
self.FireSound:Stop()
|
||||
end
|
||||
|
||||
function ENT:Detonate()
|
||||
if !self:IsValid() then return end
|
||||
|
||||
self.Armed = true
|
||||
|
||||
if self.Order and self.Order != 1 then return end
|
||||
|
||||
self.FireSound = CreateSound(self, "arccw_go/molotov/fire_loop_1.wav")
|
||||
self.FireSound:Play()
|
||||
|
||||
self.FireSound:ChangePitch(80, self.FireTime)
|
||||
|
||||
timer.Simple(self.FireTime - 1, function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
self.FireSound:ChangeVolume(0, 1)
|
||||
end)
|
||||
|
||||
timer.Simple(self.FireTime, function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
self:Remove()
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
-- cam.Start3D() -- Start the 3D function so we can draw onto the screen.
|
||||
-- render.SetMaterial( GetFireParticle() ) -- Tell render what material we want, in this case the flash from the gravgun
|
||||
-- render.DrawSprite( self:GetPos(), math.random(200, 250), math.random(200, 250), Color(255, 255, 255) ) -- Draw the sprite in the middle of the map, at 16x16 in it's original colour with full alpha.
|
||||
-- cam.End3D()
|
||||
end
|
||||
263
lua/entities/arccw_uc_napalm.lua
Normal file
263
lua/entities/arccw_uc_napalm.lua
Normal file
@@ -0,0 +1,263 @@
|
||||
--[[
|
||||
| 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.Base = "base_entity"
|
||||
ENT.PrintName = "Fire Particle"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.Model = "models/Items/AR2_Grenade.mdl"
|
||||
|
||||
ENT.FireTime = 30
|
||||
ENT.CollisionGroup = COLLISION_GROUP_PROJECTILE
|
||||
ENT.Armed = false
|
||||
|
||||
ENT.NextDamageTick = 0
|
||||
ENT.NextStickTick = 0
|
||||
|
||||
ENT.Ticks = 0
|
||||
|
||||
ENT.ArcCW_Killable = false
|
||||
|
||||
function ENT:Initialize()
|
||||
if SERVER then
|
||||
self:SetModel( self.Model )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
local maxs = Vector(1, 1, 1)
|
||||
local mins = -maxs
|
||||
self:PhysicsInitBox(mins, maxs)
|
||||
self:DrawShadow( false )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
phys:SetBuoyancyRatio(0)
|
||||
end
|
||||
|
||||
self.SpawnTime = CurTime()
|
||||
self:Detonate()
|
||||
|
||||
self.FireTime = math.Rand(self.FireTime - 1, self.FireTime + 1)
|
||||
end
|
||||
end
|
||||
|
||||
local fired = {
|
||||
"sprites/flamelet1",
|
||||
"sprites/flamelet2",
|
||||
"sprites/flamelet3",
|
||||
"sprites/flamelet4",
|
||||
"sprites/flamelet5",
|
||||
}
|
||||
local function GetFireParticle()
|
||||
return fired[math.random(#fired)]
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if !self.SpawnTime then self.SpawnTime = CurTime() end
|
||||
|
||||
if CLIENT then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
|
||||
if !self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if !IsValid(emitter) then return end
|
||||
|
||||
if math.random(1, 100) < 10 then
|
||||
local fire = emitter:Add(GetFireParticle(), self:GetPos() + (VectorRand() * 16))
|
||||
fire:SetVelocity( VectorRand() * 500 * VectorRand() )
|
||||
fire:SetGravity( Vector(0, 0, 100) )
|
||||
fire:SetDieTime( math.Rand(0.5, 0.75) )
|
||||
fire:SetStartAlpha( 255 )
|
||||
fire:SetEndAlpha( 0 )
|
||||
fire:SetStartSize( 15 )
|
||||
fire:SetEndSize( 100 )
|
||||
fire:SetRoll( math.Rand(-180, 180) )
|
||||
fire:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
fire:SetColor( 255, 255, 255 )
|
||||
fire:SetAirResistance( 150 )
|
||||
fire:SetPos( self:GetPos() )
|
||||
fire:SetLighting( false )
|
||||
fire:SetCollide(true)
|
||||
fire:SetBounce(0.75)
|
||||
fire:SetNextThink( CurTime() + FrameTime() )
|
||||
fire:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
local col1 = Color(255, 255, 175)
|
||||
local col2 = Color(0, 0, 0)
|
||||
|
||||
local col3 = col1
|
||||
local d = pa:GetLifeTime() / pa:GetDieTime()
|
||||
col3.r = Lerp(d, col1.r, col2.r)
|
||||
col3.g = Lerp(d, col1.g, col2.g)
|
||||
col3.b = Lerp(d, col1.b, col2.b)
|
||||
|
||||
pa:SetColor(col3.r, col3.g, col3.b)
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
end
|
||||
|
||||
if math.random(1, 100) < 15 then
|
||||
local fire = emitter:Add("particles/smokey", self:GetPos())
|
||||
fire:SetVelocity( VectorRand() * 100 )
|
||||
fire:SetGravity( Vector(0, 0, 1000) )
|
||||
fire:SetDieTime( math.Rand(0.5, 2) )
|
||||
fire:SetStartAlpha( 200 )
|
||||
fire:SetEndAlpha( 0 )
|
||||
fire:SetStartSize( 10 )
|
||||
fire:SetEndSize( 128 )
|
||||
fire:SetRoll( math.Rand(-180, 180) )
|
||||
fire:SetRollDelta( math.Rand(-0.2,0.2) )
|
||||
fire:SetColor( 255, 255, 255 )
|
||||
fire:SetAirResistance( 150 )
|
||||
fire:SetPos( self:GetPos() )
|
||||
fire:SetLighting( false )
|
||||
fire:SetCollide(true)
|
||||
fire:SetBounce(0.75)
|
||||
fire:SetNextThink( CurTime() + FrameTime() )
|
||||
fire:SetThinkFunction( function(pa)
|
||||
if !pa then return end
|
||||
local col1 = Color(150, 75, 0)
|
||||
local col2 = Color(50, 50, 50)
|
||||
|
||||
local col3 = col1
|
||||
local d = pa:GetLifeTime() / pa:GetDieTime()
|
||||
col3.r = Lerp(d, col1.r, col2.r)
|
||||
col3.g = Lerp(d, col1.g, col2.g)
|
||||
col3.b = Lerp(d, col1.b, col2.b)
|
||||
|
||||
pa:SetColor(col3.r, col3.g, col3.b)
|
||||
pa:SetNextThink( CurTime() + FrameTime() )
|
||||
end )
|
||||
end
|
||||
|
||||
emitter:Finish()
|
||||
|
||||
self.Ticks = self.Ticks + 1
|
||||
else
|
||||
|
||||
if self.NextDamageTick > CurTime() then return end
|
||||
|
||||
if self.Stuck and (!IsValid(self:GetParent()) or (self:GetParent():IsPlayer() and !self:GetParent():Alive())) then
|
||||
self:SetParent(NULL)
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self.Stuck = false
|
||||
local maxs = Vector(1, 1, 1)
|
||||
local mins = -maxs
|
||||
self:PhysicsInitBox(mins, maxs)
|
||||
local phys = self:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamageType(DMG_BURN)
|
||||
dmg:SetDamage(math.random() * 2 + 1)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetAttacker(self:GetOwner())
|
||||
|
||||
if self:WaterLevel() > 2 then
|
||||
if math.random() <= 0.075 then self:Remove() return end
|
||||
dmg:SetDamage(1)
|
||||
end
|
||||
|
||||
util.BlastDamageInfo(dmg, self:GetPos(), 150)
|
||||
|
||||
self.NextDamageTick = CurTime() + 0.15
|
||||
if !self.Stuck and self.NextStickTick < CurTime() then
|
||||
self.NextStickTick = CurTime() + 0.5
|
||||
if math.random() <= 0.25 then
|
||||
for _, e in pairs(ents.FindInSphere(self:GetPos(), 96)) do
|
||||
if e:IsNPC() or e:IsNextBot() or e:IsVehicle() or (e:IsPlayer() and e:Alive()) or (simfphys and simfphys.IsCar(e)) then
|
||||
self.Stuck = true
|
||||
timer.Simple(0, function()
|
||||
-- we commit a mild amount of war crimes
|
||||
self:SetSolid(SOLID_NONE)
|
||||
self:SetMoveType(MOVETYPE_NONE)
|
||||
self:SetParent(e)
|
||||
local min, max = e:WorldSpaceAABB()
|
||||
self:SetPos(min + (max - min) * math.random())
|
||||
end)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if self.SpawnTime + self.FireTime <= CurTime() then self:Remove() return end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if !self.FireSound then return end
|
||||
self.FireSound:Stop()
|
||||
end
|
||||
|
||||
function ENT:Detonate()
|
||||
if !self:IsValid() then return end
|
||||
|
||||
self.Armed = true
|
||||
|
||||
if self.Order and self.Order != 1 then return end
|
||||
|
||||
self.FireSound = CreateSound(self, "arccw_go/molotov/fire_loop_1.wav")
|
||||
self.FireSound:Play()
|
||||
|
||||
self.FireSound:ChangePitch(80, self.FireTime)
|
||||
|
||||
timer.Simple(self.FireTime - 1, function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
self.FireSound:ChangeVolume(0, 1)
|
||||
end)
|
||||
|
||||
timer.Simple(self.FireTime, function()
|
||||
if !IsValid(self) then return end
|
||||
|
||||
self:Remove()
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
function ENT:PhysicsCollide(data, physobj)
|
||||
if self.Stuck then return end
|
||||
|
||||
local tgt = data.HitEntity
|
||||
if !tgt:IsWorld() then
|
||||
timer.Simple(0, function()
|
||||
-- we commit a mild amount of war crimes
|
||||
self:SetSolid(SOLID_NONE)
|
||||
self:SetMoveType(MOVETYPE_NONE)
|
||||
self:SetParent(tgt)
|
||||
end)
|
||||
self.Stuck = true
|
||||
else
|
||||
timer.Simple(0, function()
|
||||
-- we commit a mild amount of war crimes
|
||||
self:SetSolid(SOLID_NONE)
|
||||
self:SetMoveType(MOVETYPE_NONE)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
-- cam.Start3D() -- Start the 3D function so we can draw onto the screen.
|
||||
-- render.SetMaterial( GetFireParticle() ) -- Tell render what material we want, in this case the flash from the gravgun
|
||||
-- render.DrawSprite( self:GetPos(), math.random(200, 250), math.random(200, 250), Color(255, 255, 255) ) -- Draw the sprite in the middle of the map, at 16x16 in it's original colour with full alpha.
|
||||
-- cam.End3D()
|
||||
end
|
||||
188
lua/entities/arccw_uc_riflegrenade.lua
Normal file
188
lua/entities/arccw_uc_riflegrenade.lua
Normal 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()
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.PrintName = "Base Rifle Grenade"
|
||||
ENT.Author = ""
|
||||
ENT.Information = ""
|
||||
ENT.Spawnable = false
|
||||
|
||||
ENT.Ticks = 0
|
||||
ENT.CollisionGroup = COLLISION_GROUP_PROJECTILE
|
||||
|
||||
|
||||
-- Intentionally not ENT.Damage since ArcCW base overwrites it with weapon damage (for some reason)
|
||||
ENT.GrenadeDamage = false
|
||||
ENT.GrenadeRadius = 0
|
||||
ENT.FuseTime = 10
|
||||
ENT.DragCoefficient = 1
|
||||
ENT.DetonateOnImpact = true
|
||||
|
||||
ENT.Model = "models/items/ar2_grenade.mdl"
|
||||
ENT.ExplosionEffect = true
|
||||
ENT.Scorch = "Scorch"
|
||||
ENT.SmokeTrail = true
|
||||
|
||||
local path = "arccw_uc/common/"
|
||||
local path1 = "arccw_uc/common/"
|
||||
ENT.ExplosionSounds = {path .. "explosion-close-01.ogg", path .. "explosion-close-02.ogg"}
|
||||
ENT.DebrisSounds = {path1 .. "debris-01.ogg", path1 .. "debris-02.ogg", path1 .. "debris-03.ogg", path1 .. "debris-04.ogg", path1 .. "debris-05.ogg"}
|
||||
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
local pb_vert = 1
|
||||
local pb_hor = 1
|
||||
self:SetModel(self.Model)
|
||||
self:PhysicsInitBox(Vector(-pb_vert, -pb_hor, -pb_hor), Vector(pb_vert, pb_hor, pb_hor))
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
phys:SetDragCoefficient(self.DragCoefficient)
|
||||
phys:SetBuoyancyRatio(0.1)
|
||||
end
|
||||
|
||||
self.SpawnTime = CurTime()
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if SERVER and CurTime() - self.SpawnTime >= self.FuseTime then
|
||||
self:Detonate()
|
||||
end
|
||||
end
|
||||
else
|
||||
function ENT:Think()
|
||||
if self.SmokeTrail then
|
||||
if self.Ticks % 5 == 0 then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
if not self:IsValid() or self:WaterLevel() > 2 then return end
|
||||
if not IsValid(emitter) then return end
|
||||
local smoke = emitter:Add("particle/particle_smokegrenade", self:GetPos())
|
||||
smoke:SetVelocity(VectorRand() * 25)
|
||||
smoke:SetGravity(Vector(math.Rand(-5, 5), math.Rand(-5, 5), math.Rand(-20, -25)))
|
||||
smoke:SetDieTime(math.Rand(1.5, 2.0))
|
||||
smoke:SetStartAlpha(255)
|
||||
smoke:SetEndAlpha(0)
|
||||
smoke:SetStartSize(0)
|
||||
smoke:SetEndSize(100)
|
||||
smoke:SetRoll(math.Rand(-180, 180))
|
||||
smoke:SetRollDelta(math.Rand(-0.2, 0.2))
|
||||
smoke:SetColor(20, 20, 20)
|
||||
smoke:SetAirResistance(5)
|
||||
smoke:SetPos(self:GetPos())
|
||||
smoke:SetLighting(false)
|
||||
emitter:Finish()
|
||||
end
|
||||
self.Ticks = self.Ticks + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- overwrite to do special explosion things
|
||||
function ENT:DoDetonation()
|
||||
local attacker = IsValid(self:GetOwner()) and self:GetOwner() or self
|
||||
util.BlastDamage(self, attacker, self:GetPos(), self.GrenadeRadius, self.GrenadeDamage or self.Damage or 0)
|
||||
end
|
||||
|
||||
function ENT:DoImpact(ent)
|
||||
local attacker = IsValid(self:GetOwner()) and self:GetOwner() or self
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetAttacker(attacker)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamage(100)
|
||||
dmg:SetDamageType(DMG_CRUSH)
|
||||
dmg:SetDamageForce(self.GrenadeDir * 5000)
|
||||
dmg:SetDamagePosition(self:GetPos())
|
||||
ent:TakeDamageInfo(dmg)
|
||||
end
|
||||
|
||||
function ENT:Detonate()
|
||||
if not self:IsValid() or self.BOOM then return end
|
||||
self.BOOM = true
|
||||
|
||||
if self.ExplosionEffect then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
|
||||
if self:WaterLevel() >= 1 then
|
||||
util.Effect("WaterSurfaceExplosion", effectdata)
|
||||
self:EmitSound("weapons/underwater_explode3.wav", 125, 100, 1, CHAN_AUTO)
|
||||
else
|
||||
-- util.Effect("Explosion", effectdata)
|
||||
|
||||
-- explosion_HE_m79_fas2
|
||||
-- explosion_he_grenade_fas2
|
||||
-- explosion_HE_claymore_fas2
|
||||
-- explosion_grenade_fas2
|
||||
|
||||
self:EmitSound(self.ExplosionSounds[math.random(1,#self.ExplosionSounds)], 125, 100, 1, CHAN_AUTO)
|
||||
ParticleEffect("explosion_HE_m79_fas2", self:GetPos(), Angle(-90, 0, 0))
|
||||
|
||||
--self:EmitSound("phx/kaboom.wav", 125, 100, 1, CHAN_AUTO)
|
||||
|
||||
-- Where is the sound zenith ? ???
|
||||
end
|
||||
|
||||
util.ScreenShake(self:GetPos(), 25, 4, 0.75, self.GrenadeRadius * 4)
|
||||
|
||||
if self.GrenadePos == nil then
|
||||
self.GrenadePos = self:GetPos()
|
||||
end
|
||||
if self.GrenadeDir == nil then
|
||||
self.GrenadeDir = self:GetVelocity():GetNormalized()
|
||||
end
|
||||
|
||||
local trace = util.TraceLine({
|
||||
start = self.GrenadePos,
|
||||
endpos = self.GrenadePos + self.GrenadeDir * 4,
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
if trace.Hit then
|
||||
self:EmitSound(self.DebrisSounds[math.random(1,#self.DebrisSounds)], 85, 100, 1, CHAN_AUTO)
|
||||
end
|
||||
end
|
||||
|
||||
self:DoDetonation()
|
||||
|
||||
if self.Scorch then
|
||||
util.Decal(self.Scorch, self.GrenadePos, self.GrenadePos + self.GrenadeDir * 4, self)
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, collider)
|
||||
self.GrenadeDir = colData.OurOldVelocity:GetNormalized()
|
||||
self.GrenadePos = colData.HitPos
|
||||
|
||||
self:DoImpact(colData.HitEntity)
|
||||
|
||||
if self.DetonateOnImpact then
|
||||
self:Detonate()
|
||||
else
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin(self:GetPos())
|
||||
effectdata:SetMagnitude(2)
|
||||
effectdata:SetScale(1)
|
||||
effectdata:SetRadius(2)
|
||||
effectdata:SetNormal(self.GrenadeDir)
|
||||
util.Effect("Sparks", effectdata)
|
||||
self:EmitSound("weapons/rpg/shotdown.wav", 100, 150)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
611
lua/entities/aw2_dropship.lua
Normal file
611
lua/entities/aw2_dropship.lua
Normal file
@@ -0,0 +1,611 @@
|
||||
--[[
|
||||
| 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.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Combine Dropship"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.useGunner = false
|
||||
|
||||
ENT.firstPersonOffset = Vector(110, 50, 40)
|
||||
ENT.thirdPersonOffset = Vector(-800, 0, 100)
|
||||
|
||||
ENT.baseAttach = 1
|
||||
ENT.barrelAttach = 2
|
||||
|
||||
ENT.pitchIndex = 0
|
||||
ENT.yawIndex = 1
|
||||
|
||||
ENT.accuracy = 0.02
|
||||
ENT.damage = 15
|
||||
ENT.delay = 0.1
|
||||
|
||||
util.PrecacheSound("NPC_CombineDropship.NearRotorLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
util.PrecacheSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 120
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "GunOperator")
|
||||
self:NetworkVar("Entity", 1, "Pod")
|
||||
|
||||
self:NetworkVar("Int", 0, "SpeedMult")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:aimGun()
|
||||
self:weaponThink()
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() or GetConVar("aw2_alwayson"):GetBool() then
|
||||
if not self.isActive then
|
||||
self:enableEffects()
|
||||
self.isActive = true
|
||||
end
|
||||
else
|
||||
if self.isActive then
|
||||
self:disableEffects()
|
||||
self.isActive = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:hasLOS()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local hitpos = self:getHitpos(ply)
|
||||
|
||||
local barrel = self:GetPod():GetAttachment(self.barrelAttach)
|
||||
|
||||
local dot = barrel.Ang:Forward():Dot((hitpos - barrel.Pos):GetNormalized())
|
||||
|
||||
if dot >= 0.95 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local thirdperson = ply:GetVehicle():GetThirdPersonMode()
|
||||
|
||||
local pos, ang
|
||||
|
||||
if thirdperson then
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self, self:GetPod()},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
pos = trace.HitPos + trace.HitNormal * 5
|
||||
ang = eyeAng
|
||||
else
|
||||
local entAng = self:GetAngles()
|
||||
|
||||
entAng.p = 0
|
||||
entAng.r = 0
|
||||
|
||||
local offset = self.firstPersonOffset
|
||||
|
||||
pos = self:LocalToWorld(offset)
|
||||
ang = eyeAng
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:getHitpos(ply)
|
||||
local pos, ang = self:getViewData(ply)
|
||||
|
||||
return util.QuickTrace(pos, ang:Forward() * 10000, {self, self:GetPod()}).HitPos
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/Combine_dropship.mdl")
|
||||
self:ResetSequence("cargo_hover")
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(500000)
|
||||
end
|
||||
|
||||
local pod = ents.Create("prop_dynamic")
|
||||
pod:SetModel("models/combine_dropship_container.mdl")
|
||||
pod:SetPos(self:GetPos())
|
||||
pod:SetAngles(self:GetAngles())
|
||||
pod:SetParent(self)
|
||||
pod:Spawn()
|
||||
pod:Activate()
|
||||
|
||||
self:DeleteOnRemove(pod)
|
||||
|
||||
self:SetPod(pod)
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
if self.useGunner then
|
||||
self.seatGunner = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatGunner:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatGunner:SetPos(self:GetPos())
|
||||
self.seatGunner:SetAngles(self:GetAngles())
|
||||
self.seatGunner:SetSolid(SOLID_NONE)
|
||||
self.seatGunner:SetKeyValue("limitview", 0, 0)
|
||||
self.seatGunner:SetNoDraw(true)
|
||||
self.seatGunner:Spawn()
|
||||
self.seatGunner:SetParent(self)
|
||||
self.seatGunner:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatGunner)
|
||||
|
||||
self.seatGunner.aw2Ent = self
|
||||
end
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetBodygroup(1, 1)
|
||||
|
||||
self.driver, self.gunner = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.isActive = false
|
||||
self.isFiring = false
|
||||
|
||||
self.nextShot = 0
|
||||
|
||||
self.passengers = {}
|
||||
|
||||
self:SetSpeedMult(GetConVar("aw2_dropship_speedmult"):GetInt())
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
local sequence = self:GetPod():GetSequenceName(self:GetPod():GetSequence())
|
||||
|
||||
if not self.driver then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(ply)
|
||||
end
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
elseif self.useGunner and not self.gunner then
|
||||
ply:EnterVehicle(self.seatGunner)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.gunner = ply
|
||||
self:SetGunOperator(ply)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
elseif sequence == "open_idle" then
|
||||
local seat = ents.Create("prop_vehicle_prisoner_pod")
|
||||
seat:SetModel("models/props_lab/cactus.mdl")
|
||||
seat:SetPos(self:GetPos())
|
||||
seat:SetAngles(self:GetAngles())
|
||||
seat:SetSolid(SOLID_NONE)
|
||||
seat:SetKeyValue("limitview", 0, 0)
|
||||
seat:SetNoDraw(true)
|
||||
seat:Spawn()
|
||||
seat:SetParent(self)
|
||||
seat:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(seat)
|
||||
|
||||
seat.aw2Ent = self
|
||||
|
||||
table.insert(self.passengers, seat)
|
||||
|
||||
ply:EnterVehicle(seat)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopSound("NPC_CombineDropship.NearRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
end
|
||||
|
||||
function ENT:enableEffects()
|
||||
self.wash = ents.Create("env_rotorwash_emitter")
|
||||
self.wash:SetPos(self:GetPos())
|
||||
self.wash:SetAngles(self:GetAngles())
|
||||
self.wash:SetParent(self)
|
||||
self.wash:Spawn()
|
||||
|
||||
self:EmitSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:EmitSound("NPC_CombineDropship.NearRotorLoop")
|
||||
|
||||
self:ResetSequence("cargo_idle")
|
||||
self:SetPlaybackRate(1)
|
||||
|
||||
self:SetBodygroup(1, 0)
|
||||
end
|
||||
|
||||
function ENT:disableEffects()
|
||||
if self.wash and self.wash:IsValid() then
|
||||
self.wash:Remove()
|
||||
end
|
||||
|
||||
self:GetPod():ResetSequence("idle")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
|
||||
self:StopSound("NPC_CombineDropship.OnGroundRotorLoop")
|
||||
self:StopSound("NPC_CombineDropship.NearRotorLoop")
|
||||
|
||||
self:ResetSequence("cargo_hover")
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetBodygroup(1, 1)
|
||||
end
|
||||
|
||||
function ENT:weaponThink()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if not ply or not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local fire = ply:KeyDown(IN_ATTACK) and not ply:KeyDown(IN_RELOAD) and self:hasLOS()
|
||||
|
||||
if fire then
|
||||
if self.nextShot <= CurTime() then
|
||||
self.nextShot = CurTime() + self.delay
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self:GetPod():GetAttachment(self.barrelAttach).Pos
|
||||
bullet.Dir = (self:getHitpos(ply) - self:GetPod():GetAttachment(self.barrelAttach).Pos):GetNormalized():Angle():Forward()
|
||||
bullet.Spread = Vector(self.accuracy, self.accuracy, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "HelicopterTracer"
|
||||
bullet.Force = 20
|
||||
bullet.Damage = self.damage
|
||||
bullet.Attacker = ply
|
||||
bullet.Callback = function(attacker, trace, dmginfo)
|
||||
if not trace.HitPos or not trace.HitNormal then
|
||||
return
|
||||
end
|
||||
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT)
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(trace.HitPos)
|
||||
e:SetNormal(trace.HitNormal)
|
||||
util.Effect("AR2Impact", e)
|
||||
end
|
||||
|
||||
self:GetPod():FireBullets(bullet)
|
||||
|
||||
local effectData = EffectData()
|
||||
effectData:SetOrigin(self:GetPod():GetAttachment(self.barrelAttach).Pos)
|
||||
effectData:SetAngles(self:GetPod():GetAttachment(self.barrelAttach).Ang)
|
||||
effectData:SetEntity(self:GetPod())
|
||||
|
||||
util.Effect("ChopperMuzzleFlash", effectData)
|
||||
|
||||
if not self.isFiring then
|
||||
self:EmitSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
self.isFiring = true
|
||||
end
|
||||
end
|
||||
elseif self.isFiring then
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
self.isFiring = false
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
if ply == self.driver and key == IN_RELOAD then
|
||||
local pod = self:GetPod()
|
||||
|
||||
local sequence = pod:GetSequenceName(pod:GetSequence())
|
||||
|
||||
if sequence == "idle" then
|
||||
pod:ResetSequence("open_idle")
|
||||
self:EmitSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
else
|
||||
pod:ResetSequence("idle")
|
||||
self:StopSound("NPC_CombineDropship.DescendingWarningLoop")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:aimGun()
|
||||
local ply = self:GetGunOperator()
|
||||
local pod = self:GetPod()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
-- Thanks wiremod
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), pod:GetAttachment(self.baseAttach).Pos, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = pod:GetPoseParameterRange(self.pitchIndex)
|
||||
local yawMin, yawMax = pod:GetPoseParameterRange(self.yawIndex)
|
||||
|
||||
pitch = math.Clamp(pitch, pitchMin, pitchMax)
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
pod:SetPoseParameter("weapon_pitch", pitch)
|
||||
pod:SetPoseParameter("weapon_yaw", yaw)
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(nil)
|
||||
end
|
||||
elseif self.gunner == ply then
|
||||
self.gunner = nil
|
||||
|
||||
self:SetGunOperator(nil)
|
||||
else
|
||||
for k, v in pairs(self.passengers) do
|
||||
if v == vehicle then
|
||||
table.remove(self.passengers, k)
|
||||
vehicle:Remove()
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ang = Angle(0, self:GetAngles().y, 0)
|
||||
|
||||
ply:SetEyeAngles(ang)
|
||||
ply:SetPos(self:LocalToWorld(Vector(170, 0, -50)))
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
local vel = phys:GetVelocity()
|
||||
|
||||
local localVel = WorldToLocal(phys:GetVelocity(), Angle(), Vector(), phys:GetAngles())
|
||||
|
||||
if self.isActive then
|
||||
local accel = self:GetPoseParameter("cargo_body_accel")
|
||||
accel = math.Approach(accel, math.Remap(localVel.x, 0, 1600, -0.7, 1), 0.04)
|
||||
|
||||
self:SetPoseParameter("cargo_body_accel", accel)
|
||||
|
||||
local sway = math.Remap(localVel.y, -800, 800, -1, 1)
|
||||
|
||||
self:SetPoseParameter("cargo_body_sway", -sway)
|
||||
else
|
||||
self:SetPoseParameter("cargo_body_accel", 0)
|
||||
self:SetPoseParameter("cargo_body_sway", 0)
|
||||
end
|
||||
|
||||
local desiredPitch = -(self.storedVel:Dot(self:GetForward()) - vel:Dot(self:GetForward())) * 3
|
||||
local desiredRoll = -(self.storedVel:Dot(self:GetRight()) - vel:Dot(self:GetRight())) * 3
|
||||
|
||||
local pLerp = 1 - math.sin(delta * math.pi * 0.5)
|
||||
|
||||
desiredPitch = Lerp(pLerp * delta + delta, self.storedPitch, desiredPitch)
|
||||
|
||||
self.storedPitch = desiredPitch
|
||||
self.storedVel = vel
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.2
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.2
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.2
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
desiredYaw = self.storedYaw
|
||||
else
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = self:GetSpeedMult()
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 10, math.sin(math.sin(CurTime())) * 10, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.8
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if ply and ply:IsValid() or GetConVar("aw2_alwayson"):GetBool() then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
22
lua/entities/aw2_dropship2.lua
Normal file
22
lua/entities/aw2_dropship2.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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.Base = "aw2_dropship"
|
||||
|
||||
ENT.PrintName = "Combine Dropship (2 seater)"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.useGunner = true
|
||||
605
lua/entities/aw2_gunship.lua
Normal file
605
lua/entities/aw2_gunship.lua
Normal file
@@ -0,0 +1,605 @@
|
||||
--[[
|
||||
| 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.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Gunship"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.firstPersonOffset = Vector(100, 0, -50)
|
||||
ENT.thirdPersonOffset = Vector(-600, 0, 0)
|
||||
|
||||
ENT.baseAttach = 1
|
||||
|
||||
ENT.pitchIndex = 0
|
||||
ENT.yawIndex = 1
|
||||
|
||||
ENT.accuracy = 0.01
|
||||
ENT.damage = 25
|
||||
ENT.delay = 0.05
|
||||
|
||||
util.PrecacheSound("NPC_CombineGunship.RotorSound")
|
||||
util.PrecacheSound("NPC_CombineGunship.ExhaustSound")
|
||||
util.PrecacheSound("NPC_CombineGunship.RotorBlastSound")
|
||||
util.PrecacheSound("NPC_CombineGunship.CannonSound")
|
||||
util.PrecacheSound("NPC_CombineGunship.CannonStopSound")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 120
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "GunOperator")
|
||||
|
||||
self:NetworkVar("Int", 0, "SpeedMult")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:aimGun()
|
||||
self:weaponThink()
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() or self.healthStatus == AW2_CRASHING or GetConVar("aw2_alwayson"):GetBool() then
|
||||
if not self.isActive then
|
||||
self:enableEffects()
|
||||
self.isActive = true
|
||||
end
|
||||
else
|
||||
if self.isActive then
|
||||
self:disableEffects()
|
||||
self.isActive = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:hasLOS()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local hitpos = self:getHitpos(ply)
|
||||
|
||||
local barrel = self:GetAttachment(self.baseAttach)
|
||||
|
||||
local dot = barrel.Ang:Forward():Dot((hitpos - barrel.Pos):GetNormalized())
|
||||
|
||||
if dot >= 0.95 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local thirdperson = ply:GetVehicle():GetThirdPersonMode()
|
||||
|
||||
local pos, ang
|
||||
|
||||
if thirdperson then
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
pos = trace.HitPos + trace.HitNormal * 5
|
||||
ang = eyeAng
|
||||
else
|
||||
local entAng = self:GetAngles()
|
||||
|
||||
entAng.p = 0
|
||||
entAng.r = 0
|
||||
|
||||
local offset = self.firstPersonOffset
|
||||
|
||||
pos = self:LocalToWorld(offset)
|
||||
ang = eyeAng
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:getHitpos(ply)
|
||||
local pos, ang = self:getViewData(ply)
|
||||
|
||||
return util.QuickTrace(pos, ang:Forward() * 10000, {self}).HitPos
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/gunship.mdl")
|
||||
self:ResetSequence("idle")
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(500000)
|
||||
end
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetMaxHealth(GetConVar("aw2_gunship_health"):GetInt())
|
||||
self:SetHealth(self:GetMaxHealth())
|
||||
|
||||
self.healthStatus = AW2_HEALTHY
|
||||
self.lastPercentage = 100
|
||||
|
||||
self.driver = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.isActive = false
|
||||
self.isFiring = false
|
||||
|
||||
self.nextShot = 0
|
||||
|
||||
self.nextPing = 0
|
||||
|
||||
self:SetSpeedMult(GetConVar("aw2_gunship_speedmult"):GetInt())
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
if not self.driver then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
self:SetGunOperator(ply)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopSound("NPC_CombineGunship.RotorSound")
|
||||
self:StopSound("NPC_CombineGunship.ExhaustSound")
|
||||
self:StopSound("NPC_CombineGunship.RotorBlastSound")
|
||||
self:StopSound("NPC_CombineGunship.CannonSound")
|
||||
self:StopSound("NPC_CombineGunship.DyingSound")
|
||||
end
|
||||
|
||||
function ENT:enableEffects()
|
||||
self:SetPlaybackRate(1)
|
||||
self:ResetSequence("prop_turn")
|
||||
|
||||
self.wash = ents.Create("env_rotorwash_emitter")
|
||||
self.wash:SetPos(self:GetPos())
|
||||
self.wash:SetAngles(self:GetAngles())
|
||||
self.wash:SetParent(self)
|
||||
self.wash:Spawn()
|
||||
|
||||
self:EmitSound("NPC_CombineGunship.RotorSound")
|
||||
self:EmitSound("NPC_CombineGunship.ExhaustSound")
|
||||
self:EmitSound("NPC_CombineGunship.RotorBlastSound")
|
||||
end
|
||||
|
||||
function ENT:disableEffects()
|
||||
self:SetPlaybackRate(0)
|
||||
self:ResetSequence("idle")
|
||||
|
||||
if self.wash and self.wash:IsValid() then
|
||||
self.wash:Remove()
|
||||
end
|
||||
|
||||
self:StopSound("NPC_CombineGunship.RotorSound")
|
||||
self:StopSound("NPC_CombineGunship.ExhaustSound")
|
||||
self:StopSound("NPC_CombineGunship.RotorBlastSound")
|
||||
end
|
||||
|
||||
function ENT:weaponThink()
|
||||
if self.healthStatus ~= AW2_HEALTHY then
|
||||
return
|
||||
end
|
||||
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if not ply or not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local fire = ply:KeyDown(IN_ATTACK) and not ply:KeyDown(IN_RELOAD) and self:hasLOS()
|
||||
|
||||
if fire then
|
||||
if self.nextShot <= CurTime() then
|
||||
self.nextShot = CurTime() + self.delay
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self:GetAttachment(self.baseAttach).Pos
|
||||
bullet.Dir = (self:getHitpos(ply) - self:GetAttachment(self.baseAttach).Pos):GetNormalized():Angle():Forward()
|
||||
bullet.Spread = Vector(self.accuracy, self.accuracy, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "HelicopterTracer"
|
||||
bullet.Force = 20
|
||||
bullet.Damage = self.damage
|
||||
bullet.Attacker = ply
|
||||
bullet.Callback = function(attacker, trace, dmginfo)
|
||||
if not trace.HitPos or not trace.HitNormal then
|
||||
return
|
||||
end
|
||||
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT)
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(trace.HitPos)
|
||||
e:SetNormal(trace.HitNormal)
|
||||
util.Effect("AR2Impact", e)
|
||||
end
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
if not self.isFiring then
|
||||
self:EmitSound("NPC_CombineGunship.CannonSound")
|
||||
|
||||
self.isFiring = true
|
||||
end
|
||||
end
|
||||
elseif self.isFiring then
|
||||
self:StopSound("NPC_CombineGunship.CannonSound")
|
||||
self:EmitSound("NPC_CombineGunship.CannonStopSound")
|
||||
|
||||
self.isFiring = false
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
if key == IN_ATTACK2 and self.nextPing <= CurTime() then
|
||||
self:EmitSound("NPC_CombineGunship.SeeEnemy")
|
||||
|
||||
self.nextPing = CurTime() + 4
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:aimGun()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
-- Thanks wiremod
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), self:GetAttachment(self.baseAttach).Pos, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = self:GetPoseParameterRange(self.pitchIndex)
|
||||
local yawMin, yawMax = self:GetPoseParameterRange(self.yawIndex)
|
||||
|
||||
pitch = math.Clamp(pitch, pitchMin, pitchMax)
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
self:SetPoseParameter("flex_vert", -pitch)
|
||||
self:SetPoseParameter("flex_horz", yaw)
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
|
||||
self:SetGunOperator(nil)
|
||||
end
|
||||
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmgInfo)
|
||||
local ply = self.driver
|
||||
|
||||
if not ply or not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
if self.healthStatus ~= AW2_HEALTHY then
|
||||
return
|
||||
end
|
||||
|
||||
if GetConVar("aw2_gunship_rocketonly"):GetBool() and not dmgInfo:IsDamageType(DMG_BLAST) and not dmgInfo:IsDamageType(DMG_AIRBOAT) then
|
||||
return
|
||||
end
|
||||
|
||||
local health = self:Health()
|
||||
|
||||
if health <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
self:SetHealth(health - dmgInfo:GetDamage())
|
||||
|
||||
health = self:Health()
|
||||
|
||||
local percentage = (health / self:GetMaxHealth()) * 100
|
||||
local doSound = ""
|
||||
|
||||
if percentage <= 75 and self.lastPercentage > 75 then
|
||||
doSound = "NPC_CombineGunship.Pain"
|
||||
elseif percentage <= 50 and self.lastPercentage > 50 then
|
||||
doSound = "NPC_CombineGunship.Pain"
|
||||
elseif percentage <= 25 and self.lastPercentage > 25 then
|
||||
doSound = "NPC_CombineGunship.Pain"
|
||||
elseif percentage <= 15 and self.lastPercentage > 15 then
|
||||
doSound = "NPC_CombineGunship.Pain"
|
||||
end
|
||||
|
||||
if health <= 0 then
|
||||
self.healthStatus = AW2_CRASHING
|
||||
|
||||
self.crashAng = self:GetAngles()
|
||||
|
||||
self:StopSound("NPC_CombineGunship.RotorSound")
|
||||
self:StopSound("NPC_CombineGunship.ExhaustSound")
|
||||
self:StopSound("NPC_CombineGunship.RotorBlastSound")
|
||||
|
||||
self:EmitSound("NPC_CombineGunship.DyingSound")
|
||||
end
|
||||
|
||||
if #doSound > 0 then
|
||||
local attachment = math.random(2, 5)
|
||||
|
||||
local explosion = ents.Create("env_explosion")
|
||||
explosion:SetPos(self:GetAttachment(attachment).Pos)
|
||||
explosion:SetKeyValue("iMagnitude", 100)
|
||||
explosion:SetKeyValue("iRadiusOverride", 128)
|
||||
explosion:SetKeyValue("spawnflags", 1)
|
||||
explosion:SetParent(self)
|
||||
explosion:Spawn()
|
||||
explosion:Activate()
|
||||
explosion:Fire("explode")
|
||||
|
||||
self:EmitSound(doSound)
|
||||
end
|
||||
|
||||
self.lastPercentage = percentage
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, phys)
|
||||
if self.healthStatus == AW2_CRASHING then
|
||||
self:StopSound("NPC_CombineGunship.DyingSound")
|
||||
self:EmitSound("NPC_CombineGunship.Explode")
|
||||
|
||||
local effect = ents.Create("env_ar2explosion")
|
||||
effect:SetPos(colData.HitPos)
|
||||
effect:Spawn()
|
||||
effect:Activate()
|
||||
effect:Fire("explode")
|
||||
|
||||
local ragdoll = ents.Create("prop_ragdoll")
|
||||
ragdoll:SetModel(self:GetModel())
|
||||
ragdoll:SetPos(self:GetPos())
|
||||
ragdoll:SetAngles(self:GetAngles())
|
||||
ragdoll:Spawn()
|
||||
ragdoll:Activate()
|
||||
ragdoll:GetPhysicsObject():SetVelocity(colData.OurOldVelocity)
|
||||
|
||||
ragdoll:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
local vel = phys:GetVelocity()
|
||||
|
||||
local desiredPitch = -(self.storedVel:Dot(self:GetForward()) - vel:Dot(self:GetForward())) * 3
|
||||
local desiredRoll = -(self.storedVel:Dot(self:GetRight()) - vel:Dot(self:GetRight())) * 3
|
||||
|
||||
if self.isActive then
|
||||
local accel = self:GetPoseParameter("fin_accel")
|
||||
accel = math.Approach(accel, math.Remap(desiredPitch, -60, 60, -1, 1), delta)
|
||||
self:SetPoseParameter("fin_accel", accel)
|
||||
self:SetPoseParameter("antenna_accel", accel)
|
||||
|
||||
local sway = self:GetPoseParameter("fin_sway")
|
||||
sway = math.Approach(sway, math.Remap(desiredRoll, -60, 60, -1, 1), delta)
|
||||
self:SetPoseParameter("fin_sway", sway)
|
||||
self:SetPoseParameter("antenna_sway", sway)
|
||||
else
|
||||
self:SetPoseParameter("fin_accel", -1)
|
||||
self:SetPoseParameter("fin_sway", 0)
|
||||
self:SetPoseParameter("antenna_accel", 1)
|
||||
self:SetPoseParameter("antenna_sway", 0)
|
||||
end
|
||||
|
||||
local pLerp = 1 - math.sin(delta * math.pi * 0.5)
|
||||
|
||||
desiredPitch = Lerp(pLerp * delta + delta, self.storedPitch, desiredPitch)
|
||||
|
||||
self.storedPitch = desiredPitch
|
||||
self.storedVel = vel
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.7
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.7
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.7
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = self:GetSpeedMult()
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 10, math.sin(math.sin(CurTime())) * 10, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
if self.healthStatus == AW2_CRASHING then
|
||||
local vec = Vector(300, 0, 0)
|
||||
vec:Rotate(self.crashAng)
|
||||
vec.z = -400
|
||||
|
||||
desiredPos = desiredPos + vec
|
||||
end
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.8
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if ply and ply:IsValid() or self.healthStatus == AW2_CRASHING or GetConVar("aw2_alwayson"):GetBool() then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
926
lua/entities/aw2_hk.lua
Normal file
926
lua/entities/aw2_hk.lua
Normal file
@@ -0,0 +1,926 @@
|
||||
--[[
|
||||
| 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.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Hunter Killer"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.firstPersonOffset = Vector(155, 0, -65)
|
||||
ENT.thirdPersonOffset = Vector(-600, 0, 0)
|
||||
|
||||
ENT.pitchMultiplier = 1
|
||||
ENT.rollMultiplier = 1.5
|
||||
|
||||
ENT.cannonMuzzle = 4
|
||||
ENT.cannonPitch = 5
|
||||
ENT.cannonYaw = 4
|
||||
|
||||
ENT.turretMuzzle1 = 5
|
||||
ENT.turretMuzzle2 = 6
|
||||
ENT.turretPitch = 7
|
||||
ENT.turretYaw = 6
|
||||
|
||||
ENT.spotlightAttach1 = 7
|
||||
ENT.spotlightAttach2 = 8
|
||||
ENT.lightPitch = 9
|
||||
ENT.lightYaw = 8
|
||||
|
||||
ENT.pitchIndex = 5
|
||||
ENT.yawIndex = 4
|
||||
|
||||
ENT.accuracy = 1
|
||||
ENT.damage = 20
|
||||
ENT.delay = 0.12
|
||||
|
||||
ENT.cannonDelay = 1.5
|
||||
|
||||
util.PrecacheSound("NPC_AttackHelicopter.Rotors")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.BadlyDamagedAlert")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.MegabombAlert")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.Crash")
|
||||
util.PrecacheSound("NPC_Strider.Shoot")
|
||||
util.PrecacheSound("hk/plasma.wav")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 120
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "GunOperator")
|
||||
|
||||
self:NetworkVar("Int", 0, "SpeedMult")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:aimCannon()
|
||||
self:aimTurrets()
|
||||
self:aimLights()
|
||||
self:weaponThink()
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() or self.healthStatus == AW2_CRASHING or (GetConVar("aw2_alwayson"):GetBool() and self.healthStatus ~= AW2_DEAD) then
|
||||
if not self.isActive then
|
||||
self:enableEffects()
|
||||
self.isActive = true
|
||||
end
|
||||
else
|
||||
if self.isActive then
|
||||
self:disableEffects()
|
||||
self.isActive = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:hasLOS(origin)
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local barrel
|
||||
|
||||
if not origin then
|
||||
barrel = self:GetAttachment(self.turretMuzzle1)
|
||||
else
|
||||
barrel = self:GetAttachment(origin)
|
||||
end
|
||||
|
||||
local hitpos = self:getHitpos(ply)
|
||||
local dot = barrel.Ang:Forward():Dot((hitpos - barrel.Pos):GetNormalized())
|
||||
|
||||
if dot >= 0.95 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local thirdperson = ply:GetVehicle():GetThirdPersonMode()
|
||||
|
||||
local pos, ang
|
||||
|
||||
if thirdperson then
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
pos = trace.HitPos + trace.HitNormal * 5
|
||||
ang = eyeAng
|
||||
else
|
||||
local entAng = self:GetAngles()
|
||||
|
||||
entAng.p = 0
|
||||
entAng.r = 0
|
||||
|
||||
local offset = self.firstPersonOffset
|
||||
|
||||
if self.useGunner and self:GetGunOperator() == ply then
|
||||
offset = self.gunnerOffset
|
||||
end
|
||||
|
||||
pos = self:LocalToWorld(offset)
|
||||
ang = eyeAng
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:getHitpos(ply)
|
||||
local pos, ang = self:getViewData(ply)
|
||||
|
||||
return util.QuickTrace(pos, ang:Forward() * 10000, {self}).HitPos
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/inaki/props_vehicles/terminator_aerialhk.mdl")
|
||||
self:SetBodyGroups("1")
|
||||
self:ResetSequence("idle")
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(500000)
|
||||
end
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
if self.useGunner then
|
||||
self.seatGunner = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatGunner:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatGunner:SetPos(self:GetPos())
|
||||
self.seatGunner:SetAngles(self:GetAngles())
|
||||
self.seatGunner:SetSolid(SOLID_NONE)
|
||||
self.seatGunner:SetKeyValue("limitview", 0, 0)
|
||||
self.seatGunner:SetNoDraw(true)
|
||||
self.seatGunner:Spawn()
|
||||
self.seatGunner:SetParent(self)
|
||||
self.seatGunner:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatGunner)
|
||||
|
||||
self.seatGunner.aw2Ent = self
|
||||
end
|
||||
|
||||
self:initLights()
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self:SetSubMaterial(1, "phoenix_storms/glass")
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
self:SetMaxHealth(GetConVar("aw2_hk_health"):GetInt())
|
||||
self:SetHealth(self:GetMaxHealth())
|
||||
|
||||
self.healthStatus = AW2_HEALTHY
|
||||
self.lastPercentage = 100
|
||||
|
||||
self.driver, self.gunner = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
self.storedLocalVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.isActive = false
|
||||
|
||||
self.bulletSide = false
|
||||
|
||||
self.spotlightActive = false
|
||||
|
||||
self.nextShot = 0
|
||||
self.nextCannon = 0
|
||||
|
||||
self.passengers = {}
|
||||
|
||||
self:SetSpeedMult(GetConVar("aw2_hk_speedmult"):GetInt())
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
if self.healthStatus ~= AW2_HEALTHY then
|
||||
return
|
||||
end
|
||||
|
||||
if not self.driver then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(ply)
|
||||
end
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
elseif self.useGunner and not self.gunner then
|
||||
ply:EnterVehicle(self.seatGunner)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.gunner = ply
|
||||
self:SetGunOperator(ply)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
else
|
||||
local seat = ents.Create("prop_vehicle_prisoner_pod")
|
||||
seat:SetModel("models/props_lab/cactus.mdl")
|
||||
seat:SetPos(self:GetPos())
|
||||
seat:SetAngles(self:GetAngles())
|
||||
seat:SetSolid(SOLID_NONE)
|
||||
seat:SetKeyValue("limitview", 0, 0)
|
||||
seat:SetNoDraw(true)
|
||||
seat:Spawn()
|
||||
seat:SetParent(self)
|
||||
seat:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(seat)
|
||||
|
||||
seat.aw2Ent = self
|
||||
|
||||
table.insert(self.passengers, seat)
|
||||
|
||||
ply:EnterVehicle(seat)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopSound("NPC_AttackHelicopter.Rotors")
|
||||
self:StopSound("NPC_AttackHelicopter.Crash")
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
|
||||
self.spotlight1:SetParent()
|
||||
self.spotlight1:Fire("lightoff")
|
||||
self.spotlight1:Fire("kill",self.spotlight1, 0.5)
|
||||
|
||||
self.spotlight2:SetParent()
|
||||
self.spotlight2:Fire("lightoff")
|
||||
self.spotlight2:Fire("kill",self.spotlight2, 0.5)
|
||||
end
|
||||
|
||||
function ENT:enableEffects()
|
||||
self:SetPlaybackRate(1)
|
||||
|
||||
self.wash = ents.Create("env_rotorwash_emitter")
|
||||
self.wash:SetPos(self:GetPos())
|
||||
self.wash:SetAngles(self:GetAngles())
|
||||
self.wash:SetParent(self)
|
||||
self.wash:Spawn()
|
||||
|
||||
self:EmitSound("NPC_AttackHelicopter.Rotors")
|
||||
end
|
||||
|
||||
function ENT:disableEffects()
|
||||
self:SetPlaybackRate(0)
|
||||
|
||||
if self.wash and self.wash:IsValid() then
|
||||
self.wash:Remove()
|
||||
end
|
||||
|
||||
self:StopSound("NPC_AttackHelicopter.Rotors")
|
||||
end
|
||||
|
||||
function ENT:initLights()
|
||||
local spotlight1 = ents.Create("point_spotlight")
|
||||
|
||||
spotlight1:SetPos(self:GetAttachment(self.spotlightAttach1).Pos)
|
||||
spotlight1:SetKeyValue("spotlightlength", "500")
|
||||
spotlight1:SetKeyValue("spotlightwidth", "45")
|
||||
spotlight1:SetKeyValue("spawnflags", 3)
|
||||
spotlight1:SetParent(self)
|
||||
spotlight1:Spawn()
|
||||
spotlight1:Activate()
|
||||
|
||||
self.spotlight1 = spotlight1
|
||||
|
||||
local spotlight2 = ents.Create("point_spotlight")
|
||||
|
||||
spotlight2:SetPos(self:GetAttachment(self.spotlightAttach2).Pos)
|
||||
spotlight2:SetKeyValue("spotlightlength", "500")
|
||||
spotlight2:SetKeyValue("spotlightwidth", "45")
|
||||
spotlight2:SetKeyValue("spawnflags", 3)
|
||||
spotlight2:SetParent(self)
|
||||
spotlight2:Spawn()
|
||||
spotlight2:Activate()
|
||||
|
||||
self.spotlight2 = spotlight2
|
||||
|
||||
spotlight1:Fire("lightoff")
|
||||
spotlight2:Fire("lightoff")
|
||||
end
|
||||
|
||||
function ENT:createBomb(vel)
|
||||
local bomb = ents.Create("grenade_helicopter")
|
||||
bomb:SetPos(self:GetAttachment(self.bombAttach).Pos)
|
||||
bomb:SetOwner(self)
|
||||
bomb:Spawn()
|
||||
|
||||
bomb:GetPhysicsObject():SetVelocity(vel)
|
||||
bomb:GetPhysicsObject():SetBuoyancyRatio(1)
|
||||
|
||||
return bomb
|
||||
end
|
||||
|
||||
function ENT:weaponThink()
|
||||
if self.healthStatus ~= AW2_HEALTHY then
|
||||
return
|
||||
end
|
||||
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if not IsValid(ply) then
|
||||
return
|
||||
end
|
||||
|
||||
local fire = ply:KeyDown(IN_ATTACK) and not ply:KeyDown(IN_RELOAD)
|
||||
|
||||
if fire and self:hasLOS() and self.nextShot <= CurTime() then
|
||||
self.nextShot = CurTime() + self.delay
|
||||
|
||||
local attach = self.bulletSide and self.turretMuzzle1 or self.turretMuzzle2
|
||||
|
||||
self.bulletSide = not self.bulletSide
|
||||
|
||||
local spread = math.sin(self.accuracy * 0.5 * (math.pi / 180))
|
||||
local pos = self:GetAttachment(attach).Pos
|
||||
local bullet = {}
|
||||
|
||||
bullet.Num = 1
|
||||
bullet.Src = pos
|
||||
bullet.Dir = (self:getHitpos(ply) - pos):Angle():Forward()
|
||||
bullet.Spread = Vector(spread, spread, 0)
|
||||
bullet.Tracer = 0
|
||||
bullet.Force = 20
|
||||
bullet.Damage = self.damage
|
||||
bullet.Attacker = ply
|
||||
bullet.Callback = function(attacker, trace, dmginfo)
|
||||
if not trace.HitPos or not trace.HitNormal then
|
||||
return
|
||||
end
|
||||
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT)
|
||||
|
||||
local e = EffectData()
|
||||
e:SetOrigin(trace.HitPos)
|
||||
e:SetEntity(self)
|
||||
e:SetAttachment(attach)
|
||||
e:SetNormal(trace.HitNormal)
|
||||
e:SetScale(32)
|
||||
util.Effect("hk_laser", e)
|
||||
end
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
self:EmitSound("hk/plasma.wav", 140)
|
||||
end
|
||||
|
||||
local altFire = ply:KeyDown(IN_ATTACK2) and not ply:KeyDown(IN_RELOAD)
|
||||
|
||||
if altFire and self.nextCannon <= CurTime() and self:hasLOS(self.cannonMuzzle) then
|
||||
self.nextCannon = CurTime() + self.cannonDelay
|
||||
|
||||
local pos = self:GetAttachment(self.cannonMuzzle).Pos
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = pos
|
||||
bullet.Dir = (self:getHitpos(ply) - pos):GetNormalized():Angle():Forward()
|
||||
bullet.Spread = Vector(0, 0, 0)
|
||||
bullet.Tracer = 0
|
||||
bullet.Force = 20
|
||||
bullet.Damage = 1000
|
||||
bullet.Attacker = ply
|
||||
bullet.Callback = function(attacker, trace, dmginfo)
|
||||
if not trace.HitPos or not trace.HitNormal then
|
||||
return
|
||||
end
|
||||
|
||||
util.ParticleTracerEx("Weapon_Combine_Ion_Cannon", pos, trace.HitPos, true, self:EntIndex(), self.cannonMuzzle)
|
||||
|
||||
local explosion = ents.Create("env_explosion")
|
||||
explosion:SetPos(trace.HitPos)
|
||||
explosion:SetKeyValue("iMagnitude", 120)
|
||||
explosion:Spawn()
|
||||
explosion:Activate()
|
||||
explosion:Fire("explode")
|
||||
end
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
self:EmitSound("NPC_Strider.Shoot")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
if ply:KeyDown(IN_RELOAD) and key == IN_ATTACK then
|
||||
if ply == self:GetGunOperator() then
|
||||
if self.spotlightActive then
|
||||
self.spotlight1:Fire("lightoff")
|
||||
self.spotlight2:Fire("lightoff")
|
||||
self.spotlightActive = false
|
||||
else
|
||||
self.spotlight1:Fire("lighton")
|
||||
self.spotlight2:Fire("lighton")
|
||||
self.spotlightActive = true
|
||||
end
|
||||
end
|
||||
|
||||
ply:EmitSound("buttons/lightswitch2.wav")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:aimTurrets()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if IsValid(ply) and self.healthStatus == AW2_HEALTHY then
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local turretMiddle = self:LocalToWorld(self:WorldToLocal(self:GetAttachment(self.turretMuzzle1).Pos) - self:WorldToLocal(self:GetAttachment(self.turretMuzzle2).Pos))
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), turretMiddle, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = self:GetPoseParameterRange(self.turretPitch)
|
||||
local yawMin, yawMax = self:GetPoseParameterRange(self.turretYaw)
|
||||
|
||||
pitch = math.Clamp(pitch, pitchMin, pitchMax)
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.turretPitch), -pitch)
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.turretYaw), -yaw)
|
||||
end
|
||||
|
||||
function ENT:aimCannon()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if IsValid(ply) and self.healthStatus == AW2_HEALTHY then
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), self:GetAttachment(self.cannonMuzzle).Pos, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = self:GetPoseParameterRange(self.cannonPitch)
|
||||
local yawMin, yawMax = self:GetPoseParameterRange(self.cannonYaw)
|
||||
|
||||
pitch = math.Clamp(pitch, pitchMin, pitchMax)
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.cannonPitch), pitch)
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.cannonYaw), -yaw)
|
||||
end
|
||||
|
||||
function ENT:aimLights()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if IsValid(ply) and self.healthStatus == AW2_HEALTHY then
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local lightMiddle = self:LocalToWorld(self:WorldToLocal(self:GetAttachment(self.spotlightAttach1).Pos) - self:WorldToLocal(self:GetAttachment(self.spotlightAttach2).Pos))
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), lightMiddle, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
local pitchMin, pitchMax = self:GetPoseParameterRange(self.lightPitch)
|
||||
local yawMin, yawMax = self:GetPoseParameterRange(self.lightYaw)
|
||||
|
||||
pitch = math.Clamp(pitch + 90, pitchMin, pitchMax + 35)
|
||||
|
||||
yaw = math.Clamp(yaw, yawMin, yawMax)
|
||||
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.lightPitch), -pitch)
|
||||
self:SetPoseParameter(self:GetPoseParameterName(self.lightYaw), -yaw)
|
||||
|
||||
self.spotlight1:SetAngles(self:GetAngles() + Angle(-pitch + 90, yaw, 0))
|
||||
self.spotlight2:SetAngles(self:GetAngles() + Angle(-pitch + 90, yaw, 0))
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
|
||||
if not self.useGunner then
|
||||
self:SetGunOperator(nil)
|
||||
end
|
||||
elseif self.gunner == ply then
|
||||
self.gunner = nil
|
||||
|
||||
self:SetGunOperator(nil)
|
||||
else
|
||||
for k, v in pairs(self.passengers) do
|
||||
if v == vehicle then
|
||||
table.remove(self.passengers, k)
|
||||
vehicle:Remove()
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmgInfo)
|
||||
local ply = self.driver
|
||||
|
||||
if not ply or not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
if self.healthStatus ~= AW2_HEALTHY then
|
||||
return
|
||||
end
|
||||
|
||||
if GetConVar("aw2_hk_rocketonly"):GetBool() and not dmgInfo:IsDamageType(DMG_BLAST) and not dmgInfo:IsDamageType(DMG_AIRBOAT) then
|
||||
return
|
||||
end
|
||||
|
||||
local health = self:Health()
|
||||
|
||||
if health <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
self:SetHealth(health - dmgInfo:GetDamage())
|
||||
|
||||
health = self:Health()
|
||||
|
||||
local percentage = (health / self:GetMaxHealth()) * 100
|
||||
local addSmoke = false
|
||||
local attachPoint = 0
|
||||
local doSound = ""
|
||||
|
||||
if percentage <= 75 and self.lastPercentage > 75 then
|
||||
addSmoke = true
|
||||
attachPoint = 11
|
||||
doSound = "NPC_AttackHelicopter.BadlyDamagedAlert"
|
||||
elseif percentage <= 50 and self.lastPercentage > 50 then
|
||||
addSmoke = true
|
||||
attachPoint = 12
|
||||
doSound = "NPC_AttackHelicopter.BadlyDamagedAlert"
|
||||
elseif percentage <= 25 and self.lastPercentage > 25 then
|
||||
addSmoke = true
|
||||
attachPoint = 13
|
||||
doSound = "NPC_AttackHelicopter.BadlyDamagedAlert"
|
||||
elseif percentage <= 15 and self.lastPercentage > 15 then
|
||||
addSmoke = true
|
||||
attachPoint = 14
|
||||
doSound = "NPC_AttackHelicopter.MegabombAlert"
|
||||
end
|
||||
|
||||
if health <= 0 then
|
||||
addSmoke = true
|
||||
attachPoint = 15
|
||||
|
||||
self.healthStatus = AW2_CRASHING
|
||||
self:EmitSound("NPC_AttackHelicopter.CrashingAlarm1")
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
end
|
||||
|
||||
if addSmoke then
|
||||
local explosion = ents.Create("env_explosion")
|
||||
explosion:SetPos(self:GetAttachment(attachPoint).Pos)
|
||||
explosion:SetKeyValue("iMagnitude", 100)
|
||||
explosion:SetKeyValue("iRadiusOverride", 128)
|
||||
explosion:SetKeyValue("spawnflags", 1)
|
||||
explosion:SetParent(self)
|
||||
explosion:Spawn()
|
||||
explosion:Activate()
|
||||
explosion:Fire("explode")
|
||||
|
||||
local smoke = ents.Create("env_smoketrail")
|
||||
smoke:SetPos(self:GetAttachment(attachPoint).Pos)
|
||||
smoke:SetKeyValue("opacity", 0.2)
|
||||
smoke:SetKeyValue("spawnrate", 48)
|
||||
smoke:SetKeyValue("lifetime", 0.5)
|
||||
smoke:SetKeyValue("minspeed", 16)
|
||||
smoke:SetKeyValue("maxspeed", 64)
|
||||
smoke:SetKeyValue("startcolor", "0.15 0.15 0.15")
|
||||
smoke:SetKeyValue("endcolor", "0 0 0")
|
||||
smoke:SetKeyValue("startsize", 16)
|
||||
smoke:SetKeyValue("endsize", 64)
|
||||
smoke:SetKeyValue("spawnradius", 8)
|
||||
smoke:SetParent(self)
|
||||
smoke:Spawn()
|
||||
smoke:Activate()
|
||||
|
||||
local fire = ents.Create("env_fire_trail")
|
||||
fire:SetPos(self:GetAttachment(attachPoint).Pos)
|
||||
fire:SetParent(self)
|
||||
fire:Spawn()
|
||||
fire:Activate()
|
||||
|
||||
self:EmitSound(doSound)
|
||||
end
|
||||
|
||||
self.lastPercentage = percentage
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, phys)
|
||||
if self.healthStatus == AW2_CRASHING then
|
||||
self.healthStatus = AW2_DEAD
|
||||
|
||||
self:disableEffects()
|
||||
|
||||
self:StopMotionController()
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_PUSH)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetPos(colData.HitPos - (colData.HitPos - self:GetPos()) * 0.25)
|
||||
|
||||
self:StopSound("NPC_AttackHelicopter.CrashingAlarm1")
|
||||
|
||||
self:EmitSound("NPC_AttackHelicopter.Crash")
|
||||
|
||||
local effect = ents.Create("env_ar2explosion")
|
||||
effect:SetPos(colData.HitPos)
|
||||
effect:Spawn()
|
||||
effect:Activate()
|
||||
effect:Fire("explode")
|
||||
|
||||
self.spotlight1:Fire("lightoff")
|
||||
self.spotlight2:Fire("lightoff")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
local avel = phys:GetAngleVelocity()
|
||||
local lvel = WorldToLocal(phys:GetVelocity(), Angle(), Vector(), phys:GetAngles())
|
||||
local gvel = phys:GetVelocity()
|
||||
|
||||
local desiredPitch = -(self.storedVel:Dot(self:GetForward()) - gvel:Dot(self:GetForward())) * self.pitchMultiplier
|
||||
local desiredRoll = -(self.storedVel:Dot(self:GetRight()) - gvel:Dot(self:GetRight())) * self.rollMultiplier
|
||||
|
||||
local pLerp = 1 - math.sin(delta * math.pi * 0.5)
|
||||
|
||||
desiredPitch = Lerp(pLerp * delta + delta, self.storedPitch, desiredPitch)
|
||||
|
||||
self.storedPitch = desiredPitch
|
||||
self.storedVel = gvel
|
||||
|
||||
if self.isActive then
|
||||
local paramL = self:GetPoseParameter("rotor_left")
|
||||
local paramR = self:GetPoseParameter("rotor_right")
|
||||
|
||||
local accel = math.Remap(lvel.x - self.storedLocalVel.x, -15, 15, 90, -90)
|
||||
local vel = math.Remap(lvel.x, -2200, 2200, 90, -90)
|
||||
|
||||
local rot = math.Clamp(avel:Dot(Vector(0, 0, 1)), -90, 90)
|
||||
|
||||
local targetL = accel + vel + rot
|
||||
local targetR = accel + vel - rot
|
||||
|
||||
paramL = math.Approach(paramL, targetL, (paramL - targetL) * FrameTime() * math.pi)
|
||||
paramR = math.Approach(paramR, targetR, (paramR - targetR) * FrameTime() * math.pi)
|
||||
|
||||
self:SetPoseParameter("rotor_left", paramL)
|
||||
self:SetPoseParameter("rotor_right", paramR)
|
||||
|
||||
local sway = math.Remap(lvel.y, -1600, 1600, -45, 45)
|
||||
|
||||
self:SetPoseParameter("move_yaw", -sway)
|
||||
else
|
||||
self:SetPoseParameter("rotor_left", 0)
|
||||
self:SetPoseParameter("rotor_right", 0)
|
||||
|
||||
self:SetPoseParameter("move_yaw", 0)
|
||||
end
|
||||
|
||||
self.storedLocalVel = lvel
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.7
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.5
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.5
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
desiredYaw = self.storedYaw
|
||||
else
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = self:GetSpeedMult()
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 10, math.sin(math.sin(CurTime())) * 10, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
if self.healthStatus == AW2_CRASHING then
|
||||
desiredYaw = self:GetAngles().y + 90
|
||||
|
||||
local vec = Vector(100, 0, 0)
|
||||
vec:Rotate(self:GetAngles())
|
||||
vec.z = -300
|
||||
|
||||
desiredPos = desiredPos + vec
|
||||
end
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.6
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if ply and ply:IsValid() or self.healthStatus == AW2_CRASHING or (GetConVar("aw2_alwayson"):GetBool() and self.healthStatus ~= AW2_DEAD) then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
1030
lua/entities/aw2_hunterchopper.lua
Normal file
1030
lua/entities/aw2_hunterchopper.lua
Normal file
File diff suppressed because it is too large
Load Diff
22
lua/entities/aw2_hunterchopper2.lua
Normal file
22
lua/entities/aw2_hunterchopper2.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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.Base = "aw2_hunterchopper"
|
||||
|
||||
ENT.PrintName = "Hunter Chopper (2 seater)"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.useGunner = true
|
||||
797
lua/entities/aw2_manhack.lua
Normal file
797
lua/entities/aw2_manhack.lua
Normal file
@@ -0,0 +1,797 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
EYES_OFF = 0
|
||||
EYES_ON1 = 1
|
||||
EYES_ON2 = 2
|
||||
EYES_STUNNED = 3
|
||||
EYES_DEAD = 4
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Manhack"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.firstPersonOffset = Vector()
|
||||
ENT.thirdPersonOffset = Vector(-50, 0, 10)
|
||||
|
||||
ENT.pitchMultiplier = 0.05
|
||||
ENT.rollMultiplier = 0.05
|
||||
|
||||
ENT.EventStartEngine = 50
|
||||
ENT.EventDoneUnpacking = 51
|
||||
ENT.EventOpenBlade = 52
|
||||
|
||||
ENT.PoseParameters = {
|
||||
"Panel1",
|
||||
"Panel2",
|
||||
"Panel3",
|
||||
"Panel4"
|
||||
}
|
||||
|
||||
ENT.EyeSprite = "sprites/glow1.vmt"
|
||||
|
||||
util.PrecacheSound("NPC_Manhack.EngineSound1")
|
||||
util.PrecacheSound("NPC_Manhack.BladeSound")
|
||||
|
||||
util.PrecacheSound("NPC_Manhack.ChargeAnnounce")
|
||||
util.PrecacheSound("NPC_Manhack.ChargeEnd")
|
||||
|
||||
util.PrecacheSound("NPC_Manhack.Unpack")
|
||||
util.PrecacheSound("NPC_Manhack.Grind")
|
||||
util.PrecacheSound("NPC_Manhack.Slice")
|
||||
|
||||
util.PrecacheSound("NPC_Manhack.Stunned")
|
||||
util.PrecacheSound("NPC_RollerMine.Reprogram")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 20
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Int", 0, "SpeedMult")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
if not self.Dead then
|
||||
if not IsValid(self.driver) and self.Active then
|
||||
self:TurnOff()
|
||||
end
|
||||
|
||||
self:UpdatePoseParameters()
|
||||
self:UpdateMotor()
|
||||
self:UpdateSound()
|
||||
self:UpdateEyes()
|
||||
else
|
||||
self:DoSparks()
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
local pos = trace.HitPos + trace.HitNormal * 5
|
||||
local ang = eyeAng
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/manhack.mdl")
|
||||
self:ResetSequence("idle")
|
||||
|
||||
self:SetBodyGroups("000")
|
||||
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(30)
|
||||
end
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self:SetMaxHealth(GetConVar("aw2_manhack_health"):GetInt())
|
||||
self:SetHealth(self:GetMaxHealth())
|
||||
|
||||
self.driver = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.Active = false
|
||||
self.Dead = false
|
||||
self.EyeState = EYES_OFF
|
||||
self.IdleState = false
|
||||
self.Friendly = false
|
||||
|
||||
self.EnginePower = 0
|
||||
self.BladeSpeed = 0
|
||||
self.StallTime = 0
|
||||
self.SparkTime = 0
|
||||
|
||||
local filter = RecipientFilter()
|
||||
filter:AddAllPlayers()
|
||||
|
||||
self.EngineSound1 = CreateSound(self, "NPC_Manhack.EngineSound1", filter)
|
||||
self.EngineSound1:ChangeVolume(0.55)
|
||||
|
||||
self:SetSpeedMult(GetConVar("aw2_manhack_speedmult"):GetInt())
|
||||
end
|
||||
|
||||
function ENT:Stalled()
|
||||
return self.StallTime > CurTime()
|
||||
end
|
||||
|
||||
function ENT:DoSparks()
|
||||
if self.SparkTime > CurTime() then
|
||||
return
|
||||
end
|
||||
|
||||
local data = EffectData()
|
||||
|
||||
data:SetOrigin(self:GetPos())
|
||||
data:SetAngles(self:GetAngles())
|
||||
data:SetNormal(VectorRand())
|
||||
|
||||
util.Effect("ManhackSparks", data)
|
||||
|
||||
self.SparkTime = CurTime() + math.Rand(0.5, 3)
|
||||
end
|
||||
|
||||
function ENT:HandleAnimEvent(event)
|
||||
if event == self.EventStartEngine then
|
||||
self.Active = true
|
||||
|
||||
self:EmitSound("NPC_Manhack.Unpack")
|
||||
elseif event == self.EventDoneUnpacking then
|
||||
self.EngineSound1:Play()
|
||||
self:ResetSequence("fly")
|
||||
elseif event == self.EventOpenBlade then
|
||||
self:SetBodyGroups("010")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:FullyActive()
|
||||
return self.Active and self:GetSequenceName(self:GetSequence()) == "fly"
|
||||
end
|
||||
|
||||
function ENT:TurnOff()
|
||||
self.Active = false
|
||||
self.IsHostile = false
|
||||
|
||||
self:ResetSequence("idle")
|
||||
|
||||
self.EngineSound1:Stop()
|
||||
|
||||
self:StopSound("NPC_Manhack.BladeSound")
|
||||
end
|
||||
|
||||
function ENT:IsIdle()
|
||||
return not self.Active or self:GetSequenceName(self:GetSequence()) == "idle"
|
||||
end
|
||||
|
||||
function ENT:SetEyes(state)
|
||||
if self.EyeState == state and self.IdleState == self:IsIdle() then
|
||||
return
|
||||
end
|
||||
|
||||
if state == EYES_OFF and not IsValid(self.EyeGlow) and not IsValid(self.LightGlow) then
|
||||
return
|
||||
end
|
||||
|
||||
if not self.EyeGlow then
|
||||
local attach = self:LookupAttachment("Eye")
|
||||
|
||||
self.EyeGlow = ents.Create("env_sprite")
|
||||
self.EyeGlow:SetPos(self:GetAttachment(attach).Pos)
|
||||
self.EyeGlow:SetKeyValue("rendermode", 9)
|
||||
self.EyeGlow:SetKeyValue("model", self.EyeSprite)
|
||||
self.EyeGlow:SetKeyValue("scale", 0.15)
|
||||
self.EyeGlow:SetParent(self, attach)
|
||||
|
||||
self.EyeGlow:Spawn()
|
||||
self.EyeGlow:Activate()
|
||||
|
||||
self:DeleteOnRemove(self.EyeGlow)
|
||||
end
|
||||
|
||||
if not self.LightGlow then
|
||||
local attach = self:LookupAttachment("Light")
|
||||
|
||||
self.LightGlow = ents.Create("env_sprite")
|
||||
self.LightGlow:SetPos(self:GetAttachment(attach).Pos)
|
||||
self.LightGlow:SetKeyValue("rendermode", 9)
|
||||
self.LightGlow:SetKeyValue("model", self.EyeSprite)
|
||||
self.LightGlow:SetKeyValue("scale", 0.15)
|
||||
self.LightGlow:SetParent(self, attach)
|
||||
|
||||
self.LightGlow:Spawn()
|
||||
self.LightGlow:Activate()
|
||||
|
||||
self:DeleteOnRemove(self.LightGlow)
|
||||
end
|
||||
|
||||
self.EyeState = state
|
||||
self.IdleState = self:IsIdle()
|
||||
|
||||
if state == EYES_OFF then
|
||||
self.EyeGlow:SetNoDraw(true)
|
||||
self.LightGlow:SetNoDraw(true)
|
||||
elseif state == EYES_ON1 then
|
||||
self.EyeGlow:SetNoDraw(false)
|
||||
self.EyeGlow:Fire("Color", "255 0 0")
|
||||
self.EyeGlow:SetKeyValue("renderfx", 0)
|
||||
|
||||
self.LightGlow:SetNoDraw(false)
|
||||
self.LightGlow:Fire("Color", "255 0 0")
|
||||
self.LightGlow:SetKeyValue("renderfx", 0)
|
||||
elseif state == EYES_ON2 then
|
||||
self.EyeGlow:SetNoDraw(false)
|
||||
self.EyeGlow:Fire("Color", "0 255 0")
|
||||
self.EyeGlow:SetKeyValue("renderfx", 0)
|
||||
|
||||
self.LightGlow:SetNoDraw(false)
|
||||
self.LightGlow:Fire("Color", "0 255 0")
|
||||
self.LightGlow:SetKeyValue("renderfx", 0)
|
||||
elseif state == EYES_STUNNED then
|
||||
self.EyeGlow:SetNoDraw(false)
|
||||
self.EyeGlow:Fire("Color", "255 128 0")
|
||||
self.EyeGlow:SetKeyValue("renderfx", 10)
|
||||
|
||||
self.LightGlow:SetNoDraw(false)
|
||||
self.LightGlow:Fire("Color", "255 128 0")
|
||||
self.LightGlow:SetKeyValue("renderfx", 10)
|
||||
elseif state == EYES_DEAD then
|
||||
self.EyeGlow:SetNoDraw(false)
|
||||
self.EyeGlow:Fire("Color", "255 128 0")
|
||||
self.EyeGlow:SetKeyValue("renderfx", 9)
|
||||
|
||||
self.LightGlow:SetNoDraw(false)
|
||||
self.LightGlow:Fire("Color", "255 128 0")
|
||||
self.LightGlow:SetKeyValue("renderfx", 9)
|
||||
end
|
||||
|
||||
if self:IsIdle() then
|
||||
self.LightGlow:SetNoDraw(true)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:UpdateEyes()
|
||||
if self:Stalled() then
|
||||
self:SetEyes(EYES_STUNNED)
|
||||
else
|
||||
self:SetEyes(self.Friendly and EYES_ON2 or EYES_ON1)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
if not self.driver and not self.Dead then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:UpdatePoseParameters()
|
||||
local param = self:GetPoseParameter(self.PoseParameters[1])
|
||||
|
||||
if not self.Active then
|
||||
param = 0
|
||||
elseif self.IsHostile then
|
||||
param = math.Approach(param, 90, 700 * FrameTime())
|
||||
else
|
||||
param = math.Approach(param, 0, 700 * FrameTime())
|
||||
end
|
||||
|
||||
for _, v in pairs(self.PoseParameters) do
|
||||
self:SetPoseParameter(v, param)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:UpdateSound()
|
||||
if not self.Active then
|
||||
return
|
||||
end
|
||||
|
||||
local vel = math.abs(self:GetVelocity():Length())
|
||||
local pitch1 = math.Remap(vel, 0, 400, 100, 160)
|
||||
|
||||
self.EngineSound1:ChangePitch(pitch1, 0.5)
|
||||
end
|
||||
|
||||
function ENT:UpdateMotor()
|
||||
if not self.Active then
|
||||
self.EnginePower = 0
|
||||
self.BladeSpeed = 0
|
||||
|
||||
self:SetBodyGroups("000")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:WaterLevel() > 1 then
|
||||
self.EnginePower = 0.75
|
||||
elseif self.EnginePower < 1 and not self:Stalled() then
|
||||
self.EnginePower = math.Min(self.EnginePower + (1 * FrameTime()), 1)
|
||||
end
|
||||
|
||||
if self:FullyActive() then
|
||||
if not self:Stalled() then
|
||||
if self.BladeSpeed < 10 then
|
||||
self.BladeSpeed = self.BladeSpeed * 2 + 1
|
||||
else
|
||||
self.BladeSpeed = math.Min(self.BladeSpeed + (80 * FrameTime()), 100)
|
||||
end
|
||||
end
|
||||
|
||||
self:SetPlaybackRate(self.BladeSpeed * 0.01)
|
||||
else
|
||||
self:SetPlaybackRate(1)
|
||||
end
|
||||
|
||||
if self.BladeSpeed < 20 then
|
||||
self:SetBodyGroups("010")
|
||||
elseif self.BladeSpeed < 40 then
|
||||
self:SetBodyGroups("011")
|
||||
else
|
||||
self:SetBodyGroups("001")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ShowHostile(state)
|
||||
if self.IsHostile == state then
|
||||
return
|
||||
end
|
||||
|
||||
self.IsHostile = state
|
||||
|
||||
if state then
|
||||
self:EmitSound("NPC_Manhack.ChargeAnnounce")
|
||||
self:EmitSound("NPC_Manhack.BladeSound")
|
||||
else
|
||||
self:EmitSound("NPC_Manhack.ChargeEnd")
|
||||
self:StopSound("NPC_Manhack.BladeSound")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:TurnOff()
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
if self.Dead then
|
||||
return
|
||||
end
|
||||
|
||||
if key == IN_ATTACK then
|
||||
if not self.Active then
|
||||
self:ResetSequence("deploy")
|
||||
self:SetCycle(0)
|
||||
else
|
||||
self:ShowHostile(not self.IsHostile)
|
||||
end
|
||||
end
|
||||
|
||||
if key == IN_ATTACK2 then
|
||||
self:Stall(true)
|
||||
end
|
||||
|
||||
if key == IN_RELOAD then
|
||||
self.Friendly = not self.Friendly
|
||||
|
||||
self:EmitSound("NPC_RollerMine.Reprogram")
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
end
|
||||
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
|
||||
self.storedPos = Vector()
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmgInfo)
|
||||
local ply = self.driver
|
||||
|
||||
if not IsValid(ply) then
|
||||
return
|
||||
end
|
||||
|
||||
local scale = 1
|
||||
local dmg = dmgInfo:GetDamage()
|
||||
|
||||
if dmgInfo:IsDamageType(DMG_CLUB) then
|
||||
scale = 1.5
|
||||
|
||||
local dir = dmgInfo:GetDamageForce():GetNormalized()
|
||||
local force = dir * (dmg * scale) * 100
|
||||
|
||||
self.storedPos = force
|
||||
self:Stall()
|
||||
end
|
||||
|
||||
self:SetHealth(self:Health() - (dmg * scale))
|
||||
|
||||
if self:Health() <= 0 then
|
||||
self:StopSound("NPC_Manhack.Stunned")
|
||||
self:Die()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Stall(force)
|
||||
if force then
|
||||
self.storedPos = VectorRand() * 100
|
||||
self:EmitSound("NPC_Manhack.Bat")
|
||||
end
|
||||
|
||||
self.BladeSpeed = 10
|
||||
self.EnginePower = 0
|
||||
|
||||
self.StallTime = CurTime() + 2
|
||||
|
||||
self:ShowHostile(false)
|
||||
self:EmitSound("NPC_Manhack.Stunned")
|
||||
end
|
||||
|
||||
function ENT:Die()
|
||||
self.Dead = true
|
||||
|
||||
self:EmitSound("NPC_Manhack.Die")
|
||||
|
||||
self:TurnOff()
|
||||
self:SetEyes(EYES_DEAD)
|
||||
|
||||
self:SetBodyGroups("000")
|
||||
|
||||
for _, v in pairs(self.PoseParameters) do
|
||||
self:SetPoseParameter(v, 0)
|
||||
end
|
||||
|
||||
self:SetLocalAngularVelocity(AngleRand() * 100)
|
||||
|
||||
self.Smoke = ents.Create("env_smoketrail")
|
||||
self.Smoke:SetPos(self:GetPos())
|
||||
self.Smoke:SetKeyValue("opacity", 0.2)
|
||||
self.Smoke:SetKeyValue("spawnrate", 20)
|
||||
self.Smoke:SetKeyValue("lifetime", 0.5)
|
||||
self.Smoke:SetKeyValue("minspeed", 15)
|
||||
self.Smoke:SetKeyValue("maxspeed", 12)
|
||||
self.Smoke:SetKeyValue("startcolor", "0.4 0.4 0.4")
|
||||
self.Smoke:SetKeyValue("endcolor", "0 0 0")
|
||||
self.Smoke:SetKeyValue("startsize", 8)
|
||||
self.Smoke:SetKeyValue("endsize", 32)
|
||||
self.Smoke:SetKeyValue("spawnradius", 5)
|
||||
self.Smoke:SetParent(self)
|
||||
self.Smoke:Spawn()
|
||||
self.Smoke:Activate()
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(colData, phys)
|
||||
if not self:FullyActive() then
|
||||
return
|
||||
end
|
||||
|
||||
local ent = colData.HitEntity
|
||||
|
||||
if ent:Health() > 0 then
|
||||
self:Slice(colData, phys)
|
||||
else
|
||||
self:Bump(colData, phys)
|
||||
end
|
||||
|
||||
self.BladeSpeed = 20
|
||||
end
|
||||
|
||||
function ENT:Slice(colData, phys)
|
||||
local ent = colData.HitEntity
|
||||
local damage = self.IsHostile and 30 or 5
|
||||
|
||||
if ent:IsNPC() then
|
||||
damage = damage * 0.5
|
||||
elseif string.find(ent:GetClass(), "prop_*") and ent:Health() > 0 then
|
||||
damage = ent:Health() * 2
|
||||
end
|
||||
|
||||
if ent:GetClass() != self:GetClass() then
|
||||
local info = DamageInfo()
|
||||
|
||||
info:SetAttacker(self.driver or self)
|
||||
info:SetDamage(damage)
|
||||
info:SetDamageForce(colData.OurOldVelocity)
|
||||
info:SetDamagePosition(colData.HitPos)
|
||||
info:SetDamageType(DMG_SLASH)
|
||||
info:SetInflictor(self)
|
||||
info:SetReportedPosition(colData.HitPos)
|
||||
|
||||
ent:TakeDamageInfo(info)
|
||||
end
|
||||
|
||||
local blood = ent:GetBloodColor()
|
||||
|
||||
if blood == DONT_BLEED or blood == nil then
|
||||
local vel = -self.storedPos:GetNormalized()
|
||||
local data = EffectData()
|
||||
|
||||
data:SetOrigin(colData.HitPos)
|
||||
data:SetAngles(self:GetAngles())
|
||||
data:SetNormal((colData.HitNormal + vel) * 0.5)
|
||||
|
||||
util.Effect("ManhackSparks", data)
|
||||
|
||||
self:EmitSound("NPC_Manhack.Grind")
|
||||
else
|
||||
local env = ents.Create("env_blood")
|
||||
|
||||
env:SetPos(colData.HitPos)
|
||||
env:SetKeyValue("spawnflags", 8)
|
||||
env:SetKeyValue("amount", 250)
|
||||
env:SetCollisionGroup(COLLISION_GROUP_WORLD)
|
||||
env:Spawn()
|
||||
env:Activate()
|
||||
env:Fire("EmitBlood")
|
||||
|
||||
self:EmitSound("NPC_Manhack.Slice")
|
||||
end
|
||||
|
||||
self:Rebound(ent)
|
||||
self:ShowHostile(false)
|
||||
end
|
||||
|
||||
function ENT:Bump(colData, phys)
|
||||
local ent = colData.HitEntity
|
||||
|
||||
if ent:GetMoveType() == MOVETYPE_VPHYSICS then
|
||||
self:HitPhysicsObject(phys, colData.HitObject)
|
||||
end
|
||||
|
||||
if math.abs(self:GetUp():Dot(colData.HitNormal)) < 0.55 then
|
||||
local vel = -self.storedPos:GetNormalized()
|
||||
local data = EffectData()
|
||||
|
||||
data:SetOrigin(colData.HitPos)
|
||||
data:SetAngles(self:GetAngles())
|
||||
data:SetNormal((colData.HitNormal + vel) * 0.5)
|
||||
|
||||
util.Effect("ManhackSparks", data)
|
||||
|
||||
self:EmitSound("NPC_Manhack.Grind")
|
||||
|
||||
self:ShowHostile(false)
|
||||
end
|
||||
|
||||
local dot = self.storedPos:Dot(colData.HitNormal) * colData.HitNormal
|
||||
local reflect = -2 * dot + self.storedPos
|
||||
|
||||
self.storedPos = reflect * 0.5
|
||||
end
|
||||
|
||||
function ENT:Rebound(ent)
|
||||
if ent:Health() > 0 and ent:GetClass() == "func_breakable_surf" then
|
||||
return
|
||||
end
|
||||
|
||||
local dir = (self:WorldSpaceCenter() - ent:WorldSpaceCenter()):GetNormalized()
|
||||
|
||||
dir = dir * 100
|
||||
dir.y = 0
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
|
||||
if IsValid(phys) then
|
||||
phys:ApplyForceOffset(dir * 4, self:GetPos())
|
||||
end
|
||||
|
||||
self.storedPos = dir
|
||||
end
|
||||
|
||||
function ENT:HitPhysicsObject(phys, other)
|
||||
local pos = other:GetPos()
|
||||
local pos2 = phys:GetPos()
|
||||
|
||||
local dir = (pos - pos2):GetNormalized()
|
||||
local cross = dir:Cross(Vector(0, 0, 1)):GetNormalized()
|
||||
|
||||
other:ApplyForceOffset(cross * 30 * 100, pos)
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
if not self.Active then
|
||||
return
|
||||
end
|
||||
|
||||
local gvel = phys:GetVelocity()
|
||||
|
||||
local desiredPitch = gvel:Dot(self:GetForward()) * self.pitchMultiplier
|
||||
local desiredRoll = gvel:Dot(self:GetRight()) * self.rollMultiplier
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if IsValid(ply) and self:FullyActive() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.7
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.5
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.5
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
desiredYaw = self.storedYaw
|
||||
else
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = self:GetSpeedMult() * math.max(0.01, self.EnginePower)
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 1, math.sin(math.sin(CurTime())) * 1, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.6
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if IsValid(ply) then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
485
lua/entities/aw2_stormtalon.lua
Normal file
485
lua/entities/aw2_stormtalon.lua
Normal file
@@ -0,0 +1,485 @@
|
||||
--[[
|
||||
| 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.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Storm Talon"
|
||||
ENT.Category = "Airwatch 2"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
ENT.firstPersonOffset = Vector(155, 0, 50)
|
||||
ENT.thirdPersonOffset = Vector(-600, 0, 100)
|
||||
|
||||
ENT.pitchMultiplier = 1
|
||||
ENT.rollMultiplier = 1.5
|
||||
|
||||
ENT.cannonMuzzle = 4
|
||||
ENT.cannonPitch = 5
|
||||
ENT.cannonYaw = 4
|
||||
|
||||
ENT.turretMuzzle1 = 5
|
||||
ENT.turretMuzzle2 = 6
|
||||
ENT.turretPitch = 7
|
||||
ENT.turretYaw = 6
|
||||
|
||||
ENT.spotlightAttach1 = 7
|
||||
ENT.spotlightAttach2 = 8
|
||||
ENT.lightPitch = 9
|
||||
ENT.lightYaw = 8
|
||||
|
||||
ENT.pitchIndex = 5
|
||||
ENT.yawIndex = 4
|
||||
|
||||
ENT.accuracy = 1
|
||||
ENT.damage = 20
|
||||
ENT.delay = 0.12
|
||||
|
||||
ENT.cannonDelay = 1.5
|
||||
|
||||
util.PrecacheSound("NPC_AttackHelicopter.Rotors")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.BadlyDamagedAlert")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.MegabombAlert")
|
||||
util.PrecacheSound("NPC_AttackHelicopter.Crash")
|
||||
util.PrecacheSound("NPC_Strider.Shoot")
|
||||
util.PrecacheSound("hk/plasma.wav")
|
||||
|
||||
function ENT:SpawnFunction(ply, tr, className)
|
||||
if not tr.Hit then
|
||||
return
|
||||
end
|
||||
|
||||
local spawnPos = tr.HitPos + tr.HitNormal * 120
|
||||
|
||||
local ent = ents.Create(className)
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ent:SetPos(spawnPos)
|
||||
|
||||
ent.Owner = ply
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "GunOperator")
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
self:aimTurrets()
|
||||
self:weaponThink()
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() or self.healthStatus == AW2_CRASHING or (GetConVar("aw2_alwayson"):GetBool() and self.healthStatus ~= AW2_DEAD) then
|
||||
if not self.isActive then
|
||||
self:enableEffects()
|
||||
self.isActive = true
|
||||
end
|
||||
else
|
||||
if self.isActive then
|
||||
self:disableEffects()
|
||||
self.isActive = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:hasLOS(origin)
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if IsValid(ply) then
|
||||
local pos, ang = self:GetBonePosition(7)
|
||||
|
||||
ang = ang + Angle(0, self:GetManipulateBoneAngles(4).p, 0) + Angle(self:GetManipulateBoneAngles(7).r, 0, 0)
|
||||
|
||||
local hitpos = self:getHitpos(ply)
|
||||
local dot = ang:Forward():Dot((hitpos - pos):GetNormalized())
|
||||
|
||||
if dot >= 0.95 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:getViewData(ply)
|
||||
if not ply:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
local eyeAng = ply:EyeAngles()
|
||||
|
||||
-- Hours wasted on trying to find what the issue was: 4.5
|
||||
-- Hours wasted on trying to fix the issue before finding out the fix was the issue: Too many
|
||||
if SERVER then
|
||||
eyeAng = self:WorldToLocalAngles(eyeAng) -- Note to self: NEVER subtract angles when you can WorldToLocal/LocalToWorld
|
||||
end
|
||||
|
||||
local thirdperson = ply:GetVehicle():GetThirdPersonMode()
|
||||
|
||||
local pos, ang
|
||||
|
||||
if thirdperson then
|
||||
local trace = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + eyeAng:Up() * self.thirdPersonOffset.z + eyeAng:Forward() * self.thirdPersonOffset.x,
|
||||
filter = {self},
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
})
|
||||
|
||||
pos = trace.HitPos + trace.HitNormal * 5
|
||||
ang = eyeAng
|
||||
else
|
||||
local entAng = self:GetAngles()
|
||||
|
||||
entAng.p = 0
|
||||
entAng.r = 0
|
||||
|
||||
local offset = self.firstPersonOffset
|
||||
|
||||
if self.useGunner and self:GetGunOperator() == ply then
|
||||
offset = self.gunnerOffset
|
||||
end
|
||||
|
||||
pos = self:LocalToWorld(offset)
|
||||
ang = eyeAng
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function ENT:getHitpos(ply)
|
||||
local pos, ang = self:getViewData(ply)
|
||||
|
||||
return util.QuickTrace(pos, ang:Forward() * 10000, {self}).HitPos
|
||||
end
|
||||
|
||||
function ENT:CanPhysgun(ply)
|
||||
if ply and ply:IsValid() then
|
||||
return ply:IsAdmin()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/Joazzz/Warhammer40k/Spacemarines/Ultramarines/veh_stormtalon.mdl")
|
||||
self:SetBodyGroups("001")
|
||||
self:ResetSequence("idle")
|
||||
|
||||
if SERVER then
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:SetMass(500000)
|
||||
end
|
||||
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
|
||||
self.seatDriver = ents.Create("prop_vehicle_prisoner_pod")
|
||||
self.seatDriver:SetModel("models/props_lab/cactus.mdl")
|
||||
self.seatDriver:SetPos(self:GetPos())
|
||||
self.seatDriver:SetAngles(self:GetAngles())
|
||||
self.seatDriver:SetSolid(SOLID_NONE)
|
||||
self.seatDriver:SetKeyValue("limitview", 0, 0)
|
||||
self.seatDriver:SetNoDraw(true)
|
||||
self.seatDriver:Spawn()
|
||||
self.seatDriver:SetParent(self)
|
||||
self.seatDriver:SetNotSolid(true)
|
||||
|
||||
self:DeleteOnRemove(self.seatDriver)
|
||||
|
||||
self.seatDriver.aw2Ent = self
|
||||
|
||||
self:StartMotionController()
|
||||
|
||||
self.driver = nil
|
||||
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
self.storedVel = Vector(0, 0, 0)
|
||||
self.storedLocalVel = Vector(0, 0, 0)
|
||||
|
||||
self.storedPitch = 0
|
||||
self.storedYaw = 0
|
||||
|
||||
self.isActive = false
|
||||
|
||||
self.nextShot = 0
|
||||
|
||||
self.passengers = {}
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Use(ply)
|
||||
if not self.driver then
|
||||
ply:EnterVehicle(self.seatDriver)
|
||||
ply:SetNoDraw(true)
|
||||
|
||||
self.driver = ply
|
||||
self:SetGunOperator(ply)
|
||||
|
||||
ply.aw2Ent = self
|
||||
|
||||
net.Start("aw2Enter")
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopSound("NPC_AttackHelicopter.Rotors")
|
||||
self:StopSound("NPC_AttackHelicopter.Crash")
|
||||
self:StopSound("NPC_CombineDropship.FireLoop")
|
||||
end
|
||||
|
||||
function ENT:enableEffects()
|
||||
self.wash = ents.Create("env_rotorwash_emitter")
|
||||
self.wash:SetPos(self:GetPos())
|
||||
self.wash:SetAngles(self:GetAngles())
|
||||
self.wash:SetParent(self)
|
||||
self.wash:Spawn()
|
||||
|
||||
self:EmitSound("NPC_AttackHelicopter.Rotors")
|
||||
end
|
||||
|
||||
function ENT:disableEffects()
|
||||
if IsValid(self.wash) then
|
||||
self.wash:Remove()
|
||||
end
|
||||
|
||||
self:StopSound("NPC_AttackHelicopter.Rotors")
|
||||
end
|
||||
|
||||
function ENT:weaponThink()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
if not IsValid(ply) then
|
||||
return
|
||||
end
|
||||
|
||||
local fire = ply:KeyDown(IN_ATTACK) and not ply:KeyDown(IN_RELOAD)
|
||||
|
||||
if fire and self:hasLOS() and self.nextShot <= CurTime() then
|
||||
self.nextShot = CurTime() + self.delay
|
||||
|
||||
local spread = math.sin(self.accuracy * 0.5 * (math.pi / 180))
|
||||
local pos, ang = self:GetBonePosition(7)
|
||||
local bullet = {}
|
||||
|
||||
ang = ang + Angle(0, self:GetManipulateBoneAngles(4).p, 0) + Angle(self:GetManipulateBoneAngles(7).r, 0, 0)
|
||||
|
||||
bullet.Num = 1
|
||||
bullet.Src = pos
|
||||
bullet.Dir = ang:Forward()
|
||||
bullet.Spread = Vector(spread, spread, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.Force = 20
|
||||
bullet.Damage = self.damage
|
||||
bullet.Attacker = ply
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
self:EmitSound("hk/plasma.wav", 140)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:keyPress(ply, key)
|
||||
end
|
||||
|
||||
function ENT:aimTurrets()
|
||||
local ply = self:GetGunOperator()
|
||||
|
||||
local pitch = 0
|
||||
local yaw = 0
|
||||
|
||||
if IsValid(ply) then
|
||||
local rad2deg = 180 / math.pi
|
||||
|
||||
local turret = self:GetBonePosition(7)
|
||||
|
||||
local pos, _ = WorldToLocal(self:getHitpos(ply), self:GetAngles(), turret, self:GetAngles())
|
||||
local len = pos:Length()
|
||||
|
||||
if len < 0.0000001000000 then
|
||||
pitch = 0
|
||||
else
|
||||
pitch = rad2deg * math.asin(pos.z / len)
|
||||
end
|
||||
|
||||
yaw = rad2deg * math.atan2(pos.y, pos.x)
|
||||
end
|
||||
|
||||
pitch = math.Clamp(pitch, -50, 10)
|
||||
|
||||
self:ManipulateBoneAngles(4, Angle(yaw, 0, 0))
|
||||
self:ManipulateBoneAngles(7, Angle(0, 0, -pitch))
|
||||
end
|
||||
|
||||
function ENT:ejectPlayer(ply, vehicle)
|
||||
ply:SetNoDraw(false)
|
||||
|
||||
ply.aw2Ent = nil
|
||||
|
||||
net.Start("aw2Eject")
|
||||
net.Send(ply)
|
||||
|
||||
if self.driver == ply then
|
||||
self.driver = nil
|
||||
self:SetGunOperator(nil)
|
||||
end
|
||||
|
||||
ply:SetVelocity(self:GetVelocity())
|
||||
end
|
||||
|
||||
function ENT:PhysicsSimulate(phys, delta)
|
||||
local avel = phys:GetAngleVelocity()
|
||||
local lvel = WorldToLocal(phys:GetVelocity(), Angle(), Vector(), phys:GetAngles())
|
||||
local gvel = phys:GetVelocity()
|
||||
|
||||
local desiredPitch = -(self.storedVel:Dot(self:GetForward()) - gvel:Dot(self:GetForward())) * self.pitchMultiplier
|
||||
local desiredRoll = -(self.storedVel:Dot(self:GetRight()) - gvel:Dot(self:GetRight())) * self.rollMultiplier
|
||||
|
||||
local pLerp = 1 - math.sin(delta * math.pi * 0.5)
|
||||
|
||||
desiredPitch = Lerp(pLerp * delta + delta, self.storedPitch, desiredPitch)
|
||||
|
||||
self.storedPitch = desiredPitch
|
||||
self.storedVel = gvel
|
||||
|
||||
if self.isActive then
|
||||
local paramL = self:GetManipulateBoneAngles(2).r
|
||||
local paramR = self:GetManipulateBoneAngles(3).r
|
||||
|
||||
local vel = math.Remap(lvel.x, -2200, 2200, -180, 0)
|
||||
local rot = math.Clamp(avel:Dot(Vector(0, 0, 1)), -45, 45) * math.Remap(math.abs(lvel.x), 0, 2200, -1, 1)
|
||||
local vert = math.Remap(lvel.z, -1000, 1000, 45, -45) * math.Remap(lvel.x, -2200, 2200, -1, 1)
|
||||
|
||||
local targetL = vel + rot + vert
|
||||
local targetR = vel - rot + vert
|
||||
|
||||
paramL = math.Approach(paramL, targetL, (paramL - targetL) * FrameTime() * math.pi)
|
||||
paramR = math.Approach(paramR, targetR, (paramR - targetR) * FrameTime() * math.pi)
|
||||
|
||||
self:ManipulateBoneAngles(2, Angle(0, 0, paramL))
|
||||
self:ManipulateBoneAngles(3, Angle(0, 0, paramR))
|
||||
else
|
||||
self:ManipulateBoneAngles(2, Angle(0, 0, -45))
|
||||
self:ManipulateBoneAngles(3, Angle(0, 0, -45))
|
||||
end
|
||||
|
||||
self.storedLocalVel = lvel
|
||||
|
||||
local desiredPos = self:GetPos()
|
||||
local desiredYaw = self:GetAngles().y
|
||||
|
||||
local ply = self.driver
|
||||
|
||||
if ply and ply:IsValid() then
|
||||
local addPos = Vector(0, 0, 0)
|
||||
|
||||
if ply:KeyDown(IN_FORWARD) then
|
||||
addPos.x = 0.7
|
||||
elseif ply:KeyDown(IN_BACK) then
|
||||
addPos.x = -0.7
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_MOVELEFT) then
|
||||
addPos.y = 0.5
|
||||
elseif ply:KeyDown(IN_MOVERIGHT) then
|
||||
addPos.y = -0.5
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_JUMP) then
|
||||
addPos.z = 0.3
|
||||
elseif ply:KeyDown(IN_SPEED) then
|
||||
addPos.z = -0.3
|
||||
end
|
||||
|
||||
local ang = self:GetAngles()
|
||||
ang.r = 0
|
||||
ang.p = 0
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
desiredYaw = self.storedYaw
|
||||
else
|
||||
desiredYaw = self:WorldToLocalAngles(ply:EyeAngles()).y
|
||||
end
|
||||
|
||||
if ply:KeyDown(IN_WALK) then
|
||||
addPos:Rotate(Angle(0, self.storedYaw, 0))
|
||||
else
|
||||
addPos:Rotate(Angle(0, desiredYaw, 0))
|
||||
self.storedYaw = desiredYaw
|
||||
end
|
||||
|
||||
local mult = 1000
|
||||
|
||||
addPos:Mul(mult)
|
||||
|
||||
local dist = math.Clamp(self.storedPos:Distance(addPos), 0, mult)
|
||||
local time = math.Remap(dist, 0, mult, 0, 1)
|
||||
|
||||
local lerp = 1 - math.sin(time * math.pi * 0.5)
|
||||
|
||||
addPos = LerpVector(lerp * delta + (delta * 0.4), self.storedPos, addPos)
|
||||
|
||||
self.storedPos = addPos
|
||||
|
||||
desiredPos = desiredPos + addPos
|
||||
end
|
||||
|
||||
local randPos = Vector(math.sin(math.cos(CurTime())) * 10, math.sin(math.sin(CurTime())) * 10, 0)
|
||||
randPos:Rotate(self:GetAngles())
|
||||
|
||||
desiredPos = desiredPos + randPos
|
||||
|
||||
local move = {}
|
||||
move.secondstoarrive = 0.5
|
||||
move.pos = desiredPos
|
||||
move.angle = Angle(desiredPitch, desiredYaw, desiredRoll)
|
||||
move.maxangular = 12000
|
||||
move.maxangulardamp = 10000
|
||||
move.maxspeed = 12000
|
||||
move.maxspeeddamp = 10000
|
||||
move.dampfactor = 0.6
|
||||
move.teleportdistance = 0
|
||||
move.deltatime = delta
|
||||
|
||||
if IsValid(ply) or GetConVar("aw2_alwayson"):GetBool() then
|
||||
phys:ComputeShadowControl(move)
|
||||
else
|
||||
self.storedPos = Vector(0, 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
216
lua/entities/crossbolt.lua
Normal file
216
lua/entities/crossbolt.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
if CLIENT then
|
||||
killicon.Add( "Crossbolt", "hud/crossbolt", Color( 255, 255, 255, 255 ) )
|
||||
|
||||
end
|
||||
|
||||
AddCSLuaFile()
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_anim"
|
||||
ENT.Spawnable = false
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local dlight = DynamicLight(self:EntIndex())
|
||||
|
||||
|
||||
end
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetPhysicsAttacker(self.Owner)
|
||||
|
||||
timer.Create("effe35dfs" .. self:EntIndex(), 0.01, 0, function()
|
||||
if not IsValid(self) then timer.Stop("effedfs" .. self:EntIndex()) return end
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(self:GetPos())
|
||||
ef:SetAttachment(1)
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if self:WaterLevel() == 3 then self:Remove() end
|
||||
end
|
||||
|
||||
function ENT:Damage(data, physobj)
|
||||
|
||||
local ind = math.random(1,100)
|
||||
|
||||
|
||||
local models = {
|
||||
|
||||
|
||||
}
|
||||
|
||||
local dmgtyp = {
|
||||
|
||||
DMG_NEVERGIB,
|
||||
DMG_RADIATION
|
||||
|
||||
}
|
||||
|
||||
local dmg = DamageInfo()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) then owner = self end
|
||||
|
||||
dmg:SetAttacker(owner)
|
||||
dmg:SetInflictor(self)
|
||||
|
||||
|
||||
|
||||
if ind >= 990 and ind <= 9900 then
|
||||
dmg:SetDamage(math.random(60,150))
|
||||
dmg:SetDamageType(dmgtyp[math.random(1,#dmgtyp)])
|
||||
data.HitEntity:TakeDamageInfo(dmg)
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
self.Owner:TakeDamage(self.Owner:Health(), self.Owner, self)
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
data.HitEntity:TakeDamage(data.HitEntity:Health(), self.Owner, self)
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
if data.HitEntity:IsPlayer() or data.HitEntity:IsNPC() then
|
||||
|
||||
local damg = math.random(30,60)
|
||||
if data.HitEntity:Health() < damg then damg = data.HitEntity:Health() end
|
||||
|
||||
dmg:SetDamage(damg)
|
||||
dmg:SetDamageType(dmgtyp[math.random(1,#dmgtyp)])
|
||||
data.HitEntity:TakeDamageInfo(dmg)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
data.HitEntity:SetHealth(data.HitEntity:GetMaxHealth())
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
if data.HitEntity:IsPlayer() or data.HitEntity:IsNPC() then
|
||||
|
||||
data.HitEntity:DrawShadow(false)
|
||||
end
|
||||
|
||||
if data.HitEntity:IsPlayer() then
|
||||
timer.Create("shsf"..self:EntIndex(), 30, 1, function()
|
||||
if not data.HitEntity or not IsValid(data.HitEntity) then return end
|
||||
data.HitEntity:SetMaterial("bom")
|
||||
data.HitEntity:DrawShadow(true)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if ind >= 990 and ind <= 9100 then
|
||||
if data.HitEntity:IsNPC() then
|
||||
data.HitEntity:Remove()
|
||||
|
||||
local npc21 = ents.Create(npc2)
|
||||
npc21:SetPos(data.HitPos + Vector(0,0,100))
|
||||
npc21:Spawn()
|
||||
npc21:Activate()
|
||||
end
|
||||
|
||||
if data.HitEntity:IsPlayer() then
|
||||
data.HitEntity:KillSilent()
|
||||
|
||||
local npc21 = ents.Create(npc2)
|
||||
npc21:SetPos(data.HitPos + Vector(0,0,100))
|
||||
npc21:Spawn()
|
||||
npc21:Activate()
|
||||
end
|
||||
end
|
||||
|
||||
if ind >= 50 and ind <= 100 then
|
||||
|
||||
if data.HitEntity:IsNPC() then
|
||||
data.HitEntity:Remove()
|
||||
|
||||
local prop13 = ents.Create("prop_ragdoll")
|
||||
|
||||
|
||||
prop13:SetRenderMode(RENDERMODE_NORMAL)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
if ind >= 9990 and ind <= 9100 then
|
||||
local explode = ents.Create("env_explosion")
|
||||
explode:SetPos(data.HitPos)
|
||||
explode:Spawn()
|
||||
explode:Fire( "Explode", 0, 0 )
|
||||
explode:SetKeyValue( "iMagnitude", "0" )
|
||||
|
||||
util.BlastDamage(self, owner, data.HitPos, 200, 200)
|
||||
end
|
||||
|
||||
if ind >= 910 and ind <= 1000 then
|
||||
local bone = ents.Create(bone)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(data, phys)
|
||||
|
||||
local Ent = data.HitEntity
|
||||
if !(Ent:IsValid() or Ent:IsWorld()) then return end
|
||||
|
||||
if Ent:IsWorld() then
|
||||
util.Decal("ManhackCut", data.HitPos + data.HitNormal, data.HitPos - data.HitNormal)
|
||||
self:SetPos(data.HitPos - data.HitNormal)
|
||||
self:SetAngles(self.Entity:GetAngles())
|
||||
self:GetPhysicsObject():EnableMotion(false)
|
||||
|
||||
self:Disable()
|
||||
|
||||
|
||||
elseif Ent.Health then
|
||||
if not(Ent:IsPlayer() or Ent:IsNPC() or Ent:GetClass() == "prop_ragdoll") then
|
||||
util.Decal("ManhackCut", data.HitPos + data.HitNormal, data.HitPos - data.HitNormal)
|
||||
end
|
||||
local plydmg = math.random(15,18)
|
||||
local entdmg = math.random(30,46)
|
||||
if Ent:IsPlayer() then
|
||||
Ent:TakeDamage(plydmg, self:GetOwner(), self.Entity)
|
||||
end
|
||||
if Ent:IsNPC() then
|
||||
Ent:TakeDamage(entdmg, self:GetOwner(), self.Entity)
|
||||
end
|
||||
if (Ent:IsPlayer() or Ent:IsNPC()) then
|
||||
local blood = Ent:GetBloodColor()
|
||||
local fleshimpact = EffectData()
|
||||
fleshimpact:SetEntity(self.Weapon)
|
||||
fleshimpact:SetOrigin(data.HitPos)
|
||||
fleshimpact:SetNormal(data.HitPos)
|
||||
if blood >= 0 then
|
||||
fleshimpact:SetColor(blood)
|
||||
util.Effect("BloodImpact", fleshimpact)
|
||||
end
|
||||
end
|
||||
self:EmitSound(Sound("Weapon_Crossbow.BoltHitBody"))
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
106
lua/entities/cup_shield2.lua
Normal file
106
lua/entities/cup_shield2.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
--[[
|
||||
| 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.Base = "base_anim"
|
||||
ENT.PrintName = "Tactical Combine Shield"
|
||||
ENT.Author = "Comrade Communist"
|
||||
ENT.Purpose = ""
|
||||
ENT.Category = ""
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if SERVER then
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/weapons/ballisticshield_mod.mdl")
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:DrawShadow( false )
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
self:SetHealth(44420) -- Blaze It ( ͡° ͜ʖ ͡°) --
|
||||
self:SetMaxHealth(self:Health())
|
||||
local phys = self:GetPhysicsObject()
|
||||
if (phys:IsValid()) then
|
||||
phys:Wake()
|
||||
end
|
||||
local self_name = "shield" .. self:EntIndex()
|
||||
self:SetName( self_name )
|
||||
local spawnpos = self:GetPos() + self:GetForward() * 1 + self:GetUp() * 0 + self:GetRight() * 0
|
||||
self.shield2 = ents.Create("prop_physics")
|
||||
self.shield2:SetModel("models/weapons/ballisticshield_mod.mdl")
|
||||
self.shield2:SetPos( spawnpos )
|
||||
self.shield2:SetAngles( self:GetAngles() )
|
||||
self.shield2:SetParent(self)
|
||||
self.shield2:SetNoDraw( true )
|
||||
self.shield2:DrawShadow( false )
|
||||
self.shield2:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self.shield2:SetOwner( self.Owner )
|
||||
self.shield2:Spawn()
|
||||
self.shield2:Activate()
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if IsValid(self.shield2) then
|
||||
self.shield2:SetModel(self:GetModel())
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(data,phys)
|
||||
if data.Speed > 50 and data.Speed < 300 then
|
||||
self:EmitSound("physics/metal/metal_canister_impact_soft" .. math.random(1,3) .. ".wav", 75, math.random(90,110))
|
||||
end
|
||||
if data.Speed > 300 then
|
||||
self:EmitSound("physics/metal/metal_canister_impact_hard" .. math.random(1,3) .. ".wav", 75, math.random(90,110))
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmginfo)
|
||||
self:TakePhysicsDamage(dmginfo)
|
||||
self:SetHealth(self:Health() - dmginfo:GetDamage())
|
||||
self:EmitSound("physics/metal/metal_sheet_impact_bullet" .. math.random(1,2) .. ".wav", 75, math.random(90,110))
|
||||
if self:Health() <= 0 then
|
||||
if IsValid(self.shield2) then
|
||||
self.shield2:Remove()
|
||||
end
|
||||
self:EmitSound("physics/metal/metal_box_break" .. math.random(1,2) .. ".wav", 75, math.random(90,110))
|
||||
self.shield = ents.Create("prop_physics")
|
||||
self.shield:SetModel("models/weapons/ballisticshield_mod.mdl")
|
||||
self.shield:SetPos( self:GetPos() )
|
||||
self.shield:SetAngles( self:GetAngles() )
|
||||
self.shield:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self.shield:SetOwner( self.Owner )
|
||||
self.shield:Spawn()
|
||||
self.shield:Activate()
|
||||
local phys2 = self.shield:GetPhysicsObject()
|
||||
if (phys2:IsValid()) then
|
||||
phys2:SetVelocity(self:GetForward() * math.random(-200,200) + self:GetUp() * math.random(-200,200) + self:GetRight() * math.random(-200,200))
|
||||
end
|
||||
SafeRemoveEntityDelayed(self.shield,5)
|
||||
self.dissolver = ents.Create("env_entity_dissolver")
|
||||
self.dissolver:SetKeyValue("dissolvetype", "0")
|
||||
self.dissolver:SetKeyValue("magnitude", "1")
|
||||
self.dissolver:SetPos(self.shield:GetPos())
|
||||
self.dissolver:Spawn()
|
||||
local name = "Dissolving_"..math.random(1,9999)
|
||||
self.shield:SetName(name)
|
||||
self.dissolver:Fire("Dissolve",name,0)
|
||||
self.dissolver:Fire("kill","",0.01)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
106
lua/entities/cup_shield3.lua
Normal file
106
lua/entities/cup_shield3.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
--[[
|
||||
| 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.Base = "base_anim"
|
||||
ENT.PrintName = "Tactical Metrocop Shield"
|
||||
ENT.Author = "Comrade Communist"
|
||||
ENT.Purpose = ""
|
||||
ENT.Category = ""
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if SERVER then
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel("models/items/shields/shield_cop.mdl")
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:DrawShadow( false )
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
self:SetHealth(44420) -- Blaze It ( ͡° ͜ʖ ͡°) --
|
||||
self:SetMaxHealth(self:Health())
|
||||
local phys = self:GetPhysicsObject()
|
||||
if (phys:IsValid()) then
|
||||
phys:Wake()
|
||||
end
|
||||
local self_name = "shield" .. self:EntIndex()
|
||||
self:SetName( self_name )
|
||||
local spawnpos = self:GetPos() + self:GetForward() * 1 + self:GetUp() * 0 + self:GetRight() * 0
|
||||
self.shield2 = ents.Create("prop_physics")
|
||||
self.shield2:SetModel("models/items/shields/shield_cop.mdl")
|
||||
self.shield2:SetPos( spawnpos )
|
||||
self.shield2:SetAngles( self:GetAngles() )
|
||||
self.shield2:SetParent(self)
|
||||
self.shield2:SetNoDraw( true )
|
||||
self.shield2:DrawShadow( false )
|
||||
self.shield2:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self.shield2:SetOwner( self.Owner )
|
||||
self.shield2:Spawn()
|
||||
self.shield2:Activate()
|
||||
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if IsValid(self.shield2) then
|
||||
self.shield2:SetModel(self:GetModel())
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(data,phys)
|
||||
if data.Speed > 50 and data.Speed < 300 then
|
||||
self:EmitSound("physics/metal/metal_canister_impact_soft" .. math.random(1,3) .. ".wav", 75, math.random(90,110))
|
||||
end
|
||||
if data.Speed > 300 then
|
||||
self:EmitSound("physics/metal/metal_canister_impact_hard" .. math.random(1,3) .. ".wav", 75, math.random(90,110))
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmginfo)
|
||||
self:TakePhysicsDamage(dmginfo)
|
||||
self:SetHealth(self:Health() - dmginfo:GetDamage())
|
||||
self:EmitSound("physics/metal/metal_sheet_impact_bullet" .. math.random(1,2) .. ".wav", 75, math.random(90,110))
|
||||
if self:Health() <= 0 then
|
||||
if IsValid(self.shield2) then
|
||||
self.shield2:Remove()
|
||||
end
|
||||
self:EmitSound("physics/metal/metal_box_break" .. math.random(1,2) .. ".wav", 75, math.random(90,110))
|
||||
self.shield = ents.Create("prop_physics")
|
||||
self.shield:SetModel("models/items/shields/shield_cop.mdl")
|
||||
self.shield:SetPos( self:GetPos() )
|
||||
self.shield:SetAngles( self:GetAngles() )
|
||||
self.shield:SetCollisionGroup(COLLISION_GROUP_WEAPON)
|
||||
self.shield:SetOwner( self.Owner )
|
||||
self.shield:Spawn()
|
||||
self.shield:Activate()
|
||||
local phys2 = self.shield:GetPhysicsObject()
|
||||
if (phys2:IsValid()) then
|
||||
phys2:SetVelocity(self:GetForward() * math.random(-200,200) + self:GetUp() * math.random(-200,200) + self:GetRight() * math.random(-200,200))
|
||||
end
|
||||
SafeRemoveEntityDelayed(self.shield,5)
|
||||
self.dissolver = ents.Create("env_entity_dissolver")
|
||||
self.dissolver:SetKeyValue("dissolvetype", "0")
|
||||
self.dissolver:SetKeyValue("magnitude", "1")
|
||||
self.dissolver:SetPos(self.shield:GetPos())
|
||||
self.dissolver:Spawn()
|
||||
local name = "Dissolving_"..math.random(1,9999)
|
||||
self.shield:SetName(name)
|
||||
self.dissolver:Fire("Dissolve",name,0)
|
||||
self.dissolver:Fire("kill","",0.01)
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
26
lua/entities/eft_ammo_556_hp.lua
Normal file
26
lua/entities/eft_ammo_556_hp.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "5.56x45mm HP"
|
||||
ENT.Category = "ArcCW - EFT Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/entities/eft_ammo/eft_ammo_556_warmage.mdl"
|
||||
|
||||
ENT.AmmoType = "556_hp"
|
||||
ENT.AmmoCount = 60
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/pistol/pistol_fire3.wav"
|
||||
26
lua/entities/eft_ammo_556_m855.lua
Normal file
26
lua/entities/eft_ammo_556_m855.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "5.56x45mm M855"
|
||||
ENT.Category = "ArcCW - EFT Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/entities/eft_ammo/eft_ammo_556_warmage.mdl"
|
||||
|
||||
ENT.AmmoType = "556_M855"
|
||||
ENT.AmmoCount = 60
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/pistol/pistol_fire3.wav"
|
||||
26
lua/entities/eft_ammo_556_m995.lua
Normal file
26
lua/entities/eft_ammo_556_m995.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
--[[
|
||||
| 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 = "arccw_ammo"
|
||||
|
||||
ENT.PrintName = "5.56x45mm M995"
|
||||
ENT.Category = "ArcCW - EFT Ammo"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/entities/eft_ammo/eft_ammo_556_warmage.mdl"
|
||||
|
||||
ENT.AmmoType = "556_M995"
|
||||
ENT.AmmoCount = 60
|
||||
|
||||
ENT.DetonationDamage = 10
|
||||
ENT.DetonationRadius = 256
|
||||
ENT.DetonationSound = "weapons/pistol/pistol_fire3.wav"
|
||||
91
lua/entities/ent_mannable_airboatgun.lua
Normal file
91
lua/entities/ent_mannable_airboatgun.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Airboat gun"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.__ShootSound = nil
|
||||
self.ShootDelay = 0.075
|
||||
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
self.__ShootSound = CreateSound(self, "Airboat.FireGunLoop")
|
||||
self.__ShootSound:Play()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
self:EmitSound("Airboat.FireGunRevDown")
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "AR2Tracer",
|
||||
Damage = 26,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.02,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Num = math.random(1,4),
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
if(_tr.Entity:IsPlayer() or _tr.Entity:IsVehicle()) then
|
||||
_dmg:SetDamage(8)
|
||||
end
|
||||
_dmg:SetDamageType(DMG_AIRBOAT)
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
|
||||
util.Effect("AirboatMuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
self:SetupCustomModel("models/airboatgun.mdl")
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Rotate(Angle(0, 90, 90))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
end
|
||||
90
lua/entities/ent_mannable_ar3.lua
Normal file
90
lua/entities/ent_mannable_ar3.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "AR3"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
ENT.ShootDelay = 0.075
|
||||
|
||||
ENT._DoNetworking = true
|
||||
ENT._HideGunModel = false
|
||||
ENT._PitchOffset = 10
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.ShootDelay = 0.075
|
||||
|
||||
self._DoNetworking = true
|
||||
self._HideGunModel = false
|
||||
self._PitchOffset = 10
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "AR2Tracer",
|
||||
Damage = 26,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.02,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
if(_tr.Entity:IsPlayer() or _tr.Entity:IsVehicle()) then
|
||||
_dmg:SetDamage(8)
|
||||
end
|
||||
_dmg:SetDamageType(DMG_AIRBOAT)
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
self:EmitSound("Weapon_AR2.NPC_Single")
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(5)
|
||||
|
||||
util.Effect("MuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:OnActivateGun()
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnDeactivateGun()
|
||||
|
||||
end
|
||||
|
||||
local glow = Material("sprites/combine_cannon_glow")
|
||||
|
||||
function ENT:DoDraw()
|
||||
if(self._Active) then
|
||||
render.SetMaterial(glow)
|
||||
render.DrawSprite(self:GetAttachment(1).Pos, 40, 32)
|
||||
end
|
||||
end
|
||||
end
|
||||
730
lua/entities/ent_mannable_bakubase.lua
Normal file
730
lua/entities/ent_mannable_bakubase.lua
Normal file
@@ -0,0 +1,730 @@
|
||||
--[[
|
||||
| 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()
|
||||
AddCSLuaFile("includes/jakubbaku_utils.lua")
|
||||
include("includes/jakubbaku_utils.lua")
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.PrintName = "Emplacement Base"
|
||||
ENT.Category = "Jakub Baku"
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
|
||||
/*
|
||||
--------- DEV HELP README ---------
|
||||
|
||||
Mannable sentry/turret/whatever-you-gonna-call-it base, made by me - Jakub Baku / Geiger 21 / AwesomeGraczGie21 / karolek471 (I go by many names :P)
|
||||
It's purpose is to facilitate the creation of new "mannables" for my addon, but I thought I can share my work with you.
|
||||
|
||||
How to use?
|
||||
- Put the ent_mannable_bakubase.lua file in lua/entities
|
||||
- Put the jakubbaku_utils.lua in lua/includes
|
||||
- You can also put effects in lua/effects
|
||||
- Create a new LUA file called along the lines of "entity_NAME" (make it unique) in lua/entities folder
|
||||
- Add this "boiler plate" code:
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "ent_mannable_bakubase" //important!
|
||||
ENT.PrintName = "Your gun name"
|
||||
ENT.Category = "Your category"
|
||||
ENT.Spawnable = true //true if it's spawnable in the spawn menu
|
||||
ENT.AdminOnly = false //true if it should be spawnable only for admins
|
||||
|
||||
Since we're working with a base we don't want to override default hooks like ENT:Initialize(), so please,
|
||||
use only the ones provided by the base unless you know what you're doing.
|
||||
|
||||
(SHARED - accessible both on client and server
|
||||
SERVER - serverside only
|
||||
CLIENT - clientside only)
|
||||
|
||||
--------------- Hooks provided by the base (SIDE, name, return type): ---------------
|
||||
SHARED ENT:DoInit() void
|
||||
Called when the entity is spawned
|
||||
|
||||
SHARED ENT:DoRemove() void
|
||||
Called when the entity is about to get removed
|
||||
|
||||
SHARED ENT:OnActivateGun() void
|
||||
Called when the user starts using the gun or enters the vehicle on which the gun is mounted
|
||||
|
||||
SHARED ENT:OnDeactivateGun() void
|
||||
Called when the user dies, gets too far from the gun, exits the vehicle etc.
|
||||
|
||||
SERVER ENT:OnStartShooting() void
|
||||
Called when the user starts firing
|
||||
|
||||
SERVER ENT:OnStopShooting() void
|
||||
Called when the user stops firing
|
||||
|
||||
SERVER ENT:DoShootThink() boolean
|
||||
Called everytime the user fires. Return true to override the default firing function
|
||||
|
||||
SERVER ENT:OnStartAttack() void
|
||||
Called when the user clicks the Left mouse button. Most of the time it's
|
||||
identical to OnStartShooting, but using this function you can delay the firing,
|
||||
for example in case of charging the gun or something
|
||||
|
||||
SERVER ENT:OnStopAttack() void
|
||||
Called when the user lets go of the left mouse button. Most of the time it's
|
||||
identical to OnStopShooting
|
||||
|
||||
SERVER ENT:DoShoot(direction) void
|
||||
Called when the user fires the gun, use the direction argument to direct your bullets, projectiles.
|
||||
direction is a normalized direction vector pointing in the aim direction
|
||||
|
||||
CLIENT ENT:DoNotification() void
|
||||
Called when the user starts using the gun. It's purpose is to
|
||||
display the help notification (ENT._Notification)
|
||||
|
||||
CLIENT ENT:DoDraw() void
|
||||
Called every frame. Used for drawing effects, models etc.
|
||||
|
||||
CLIENT ENT:DoThink() void
|
||||
Called every frame
|
||||
|
||||
--------------- Methods provided by the base ---------------
|
||||
SERVER ENT:BakuRegisterMannable() void
|
||||
Registers the gun for use in vehicles. If you want your gun to be
|
||||
able to be mounted on the vehicle call this function, preferably in ENT:DoInit() hook.
|
||||
|
||||
SERVER ENT:BakuManned(manned (boolean)) void
|
||||
INTERNAL, DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING
|
||||
Use this method to mark the user as "not manning the gun" (manned = false) or "manning the gun" (manned = true)
|
||||
|
||||
SERVER ENT:BakuIsManned(user) boolean
|
||||
INTERNAL, DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING
|
||||
Tells whether the user is manning a gun
|
||||
|
||||
CLIENT ENT:SetupCustomModel(mdl (string), bone (number), rendergroup (RENDERGROUP_ enum)) CSEnt
|
||||
Facilitates the creation of ENT._CustomGunModel. Mdl is a path to model like "models/weapons/something.mdl",
|
||||
bone is a boneID of the bone used for positioning the model, rendergroup by default is RENDERGROUP_TRANSLUCENT
|
||||
|
||||
--------------- Important variables (type, name) ---------------
|
||||
Please do not modify other base-specific variables than those specified there
|
||||
|
||||
number ENT.ShootDelay
|
||||
Used by default shooting code. Basically a delay between shots
|
||||
|
||||
number ENT._ShootTimer
|
||||
Internal, used for timing the shots. It's handy for charged attack, here's example
|
||||
|
||||
function ENT:OnStartAttack()
|
||||
//when the user starts attacking
|
||||
|
||||
local somechargetime = 1 //1 second charge time
|
||||
|
||||
self:EmitSound("some/sound.wav") //we emit some sound
|
||||
self._ShootTimer = CurTime() + somechargetime
|
||||
|
||||
//the CurTime() is really important here, because it's not a simple delay, it's a timestamp
|
||||
//of the next fire
|
||||
end
|
||||
|
||||
number ENT._Ammo
|
||||
If set to less than 0 (-1 for example) the gun has unlimited ammo.
|
||||
|
||||
boolean ENT._DoNetworking
|
||||
true by default. If set to false many shared hooks won't be called clientside
|
||||
|
||||
boolean ENT._IsShooting
|
||||
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||||
Handy for determining whether the gun is firing or not
|
||||
|
||||
boolean ENT._Active
|
||||
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||||
Tells whether the gun is actively manned / used
|
||||
|
||||
boolean ENT._DriveMode
|
||||
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||||
Tells whether the gun is in drive mode (mounted to a vehicle)
|
||||
|
||||
boolean ENT._HideGunModel
|
||||
Set it in ENT:DoInit() to true to hide the original
|
||||
gun model
|
||||
|
||||
CSEnt ENT._CustomGunModel CLIENTSIDE ONLY
|
||||
A ClientsideModel representing the custom gun model.
|
||||
Set it in clientside ENT:DoInit() hook like that:
|
||||
self._CustomGunModel = ClientsideModel("path/to/model.mdl")
|
||||
Preferably use ENT:SetupCustomModel method
|
||||
|
||||
number ENT._CModelBone CLIENTSIDE ONLY
|
||||
Bone ID of a _CustomGunModel's bone used to change the position.
|
||||
Most of the times you should not touch it (it's 0 - ROOT_BONE by default)
|
||||
|
||||
VMatrix ENT._GunModelMatrix CLIENTSIDE ONLY
|
||||
Transformation matrix of a gun model. Used for positioning, changing
|
||||
the angles of a custom gun model. If not touched it's identity matrix,
|
||||
so no changes to the pos/ang/scale
|
||||
|
||||
|
||||
Why don't I make accessor funcs for all those obscure variables? Well... I don't need them.
|
||||
Real programming is when you can break all your code with just one missplaced variable ;)
|
||||
This is base for smart people, cautious programmers. But no, seriously, it's because
|
||||
I don't need it
|
||||
|
||||
--------/ DEV HELP README \--------
|
||||
*/
|
||||
|
||||
hook.Add("InitPostEntity", "MannableBakuBaseDuplicator", function()
|
||||
local _base = scripted_ents.Get("ent_mannable_bakubase")
|
||||
|
||||
local _regents = scripted_ents.GetList()
|
||||
for k, v in pairs(_regents) do
|
||||
if(v.Base == "ent_mannable_bakubase") then
|
||||
duplicator.RegisterEntityClass(v.t.ClassName, _base.BaseDupeFunction, "Data")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function ENT:DoInit() end
|
||||
function ENT:DoRemove() end
|
||||
function ENT:DoSetupDataTables() end
|
||||
function ENT.DupeFunction(ply, data) end
|
||||
|
||||
function ENT:RegisterDuplicator()
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
if(self._CanAIControlled) then
|
||||
self:NetworkVar("Bool", 31, "_AIControlled", {KeyName = "aicontrolled", Edit = {title = "AI Controlled", category = "AI", type = "Boolean", order = 0}})
|
||||
|
||||
if(SERVER) then
|
||||
self:Set_AIControlled(false)
|
||||
end
|
||||
|
||||
self:NetworkVarNotify("_AIControlled", self.HandleAIVarChange)
|
||||
end
|
||||
|
||||
self:DoSetupDataTables()
|
||||
end
|
||||
|
||||
if (SERVER) then
|
||||
function ENT.BaseDupeFunction(ply, data)
|
||||
data._User = NULL
|
||||
data._Active = false
|
||||
data._ShootTimer = 0
|
||||
data._UseTimer = 0
|
||||
data._SequenceTimer = 0
|
||||
data._IsShooting = false
|
||||
|
||||
local _func = scripted_ents.Get(data.Class).DupeFunction
|
||||
|
||||
if(isfunction(_func)) then
|
||||
_func(ply, data)
|
||||
end
|
||||
|
||||
return duplicator.GenericDuplicatorFunction(ply, data)
|
||||
end
|
||||
|
||||
ENT._User = NULL
|
||||
ENT._UserPrevWeapon = NULL
|
||||
ENT._Active = false
|
||||
ENT._DriveMode = false
|
||||
ENT._Vehicle = NULL
|
||||
ENT.ShootDelay = 0.075
|
||||
ENT._Ammo = -1
|
||||
|
||||
ENT._OldAim = Vector(0, 0, 0)
|
||||
|
||||
ENT._ShootTimer = 0
|
||||
ENT._UseTimer = 0
|
||||
ENT._SequenceTimer = 0
|
||||
ENT._IsShooting = false
|
||||
ENT._HideGunModel = false
|
||||
ENT._Automatic = true
|
||||
ENT._DoNetworking = true
|
||||
ENT._PitchOffset = 0
|
||||
|
||||
//AI
|
||||
ENT._AIControlled = false
|
||||
ENT._AIShooting = false
|
||||
ENT._AIAimPoint = Vector(0, 0, 0)
|
||||
ENT._AIEnemy = NULL
|
||||
|
||||
local _varhandlers = {
|
||||
["_AIControlled"] = function(self, old, new)
|
||||
self:InitAIControll()
|
||||
end,
|
||||
}
|
||||
|
||||
function ENT:HandleAIVarChange(name, old, new)
|
||||
if(isfunction(_varhandlers[name])) then
|
||||
if(old != new) then
|
||||
_varhandlers[name](self, old, new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting() end
|
||||
function ENT:OnStopShooting() end
|
||||
function ENT:DoShootThink() return false end
|
||||
function ENT:OnStartAttack() end
|
||||
function ENT:OnStopAttack() end
|
||||
function ENT:OnDeactivateGun() end
|
||||
function ENT:OnActivateGun() end
|
||||
|
||||
function ENT:BakuRegisterMannable()
|
||||
__BakuRegisteredMannableClasses = __BakuRegisteredMannableClasses or {}
|
||||
__BakuRegisteredMannableClasses[self:GetClass()] = true
|
||||
end
|
||||
|
||||
function ENT:BakuManned(bool)
|
||||
if(bool) then
|
||||
__BakuManTableAR3[self._User:EntIndex()] = self
|
||||
else
|
||||
__BakuManTableAR3[self._User:EntIndex()] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:BakuIsManned(user)
|
||||
return IsValid(__BakuManTableAR3[user:EntIndex()])
|
||||
end
|
||||
|
||||
function ENT:BakuRemoveFromVehicle()
|
||||
__BakuVehicleTableAR3[self._Vehicle:EntIndex()] = nil
|
||||
end
|
||||
|
||||
function ENT:InitAIControll()
|
||||
self:AR3Deactivate()
|
||||
|
||||
self._AIControlled = true
|
||||
self._User = NULL
|
||||
self._Active = false
|
||||
end
|
||||
|
||||
function ENT:DoAIThink()
|
||||
if(!IsValid(self._AIEnemy)) then
|
||||
local enemy = player.GetAll()[1]
|
||||
|
||||
self._AIEnemy = enemy
|
||||
|
||||
if(IsValid(enemy) && enemy:Alive() && !self._Active) then
|
||||
self:AR3Activate()
|
||||
end
|
||||
else
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetAttachment(1).Pos,
|
||||
endpos = self._AIEnemy:GetPos() + self._AIEnemy:OBBCenter(),
|
||||
filter = self
|
||||
})
|
||||
|
||||
if(tr.Entity == self._AIEnemy) then
|
||||
self._AIAimPoint = tr.HitPos
|
||||
self._AIShooting = true
|
||||
end
|
||||
|
||||
if(IsValid(self._AIEnemy) || !self._AIEnemy:Alive()) then
|
||||
//self:AR3Deactivate()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self._User = NULL
|
||||
self._UserPrevWeapon = NULL
|
||||
self._Active = false
|
||||
self._DriveMode = false
|
||||
self._Vehicle = NULL
|
||||
self.ShootDelay = 0.075
|
||||
self._Ammo = -1
|
||||
|
||||
self._OldAim = Vector(0, 0, 0)
|
||||
|
||||
self._ShootTimer = 0
|
||||
self._UseTimer = 0
|
||||
self._SequenceTimer = 0
|
||||
self._IsShooting = false
|
||||
self._HideGunModel = false
|
||||
self._Automatic = true
|
||||
self._DoNetworking = true
|
||||
self._PitchOffset = 0
|
||||
|
||||
//AI
|
||||
self._AIControlled = false
|
||||
self._AIShooting = false
|
||||
self._AIAimPoint = Vector(0, 0, 0)
|
||||
self._AIEnemy = NULL
|
||||
|
||||
self:DoInit()
|
||||
|
||||
if(self._HideGunModel) then
|
||||
self:SetModel("models/props_combine/bunker_gun01_nogun.mdl")
|
||||
else
|
||||
self:SetModel("models/props_combine/bunker_gun01.mdl")
|
||||
end
|
||||
|
||||
self:PhysicsInitBox(-Vector(8,8,0), Vector(8,8,8))
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if(IsValid(phys)) then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self:SetUseType(USE_TOGGLE)
|
||||
end
|
||||
|
||||
local usetime = 0.5
|
||||
|
||||
function ENT:AR3Activate()
|
||||
self:ResetSequence(1)
|
||||
self._SequenceTimer = CurTime() + 0.5
|
||||
|
||||
if(IsValid(self._User) && !self._AIControlled) then
|
||||
if(!self._DriveMode) then
|
||||
self._UserPrevWeapon = self._User:GetActiveWeapon()
|
||||
self._User:SetActiveWeapon(NULL)
|
||||
end
|
||||
|
||||
self:BakuManned(true)
|
||||
|
||||
self:EmitSound("weapons/shotgun/shotgun_cock.wav")
|
||||
end
|
||||
self._Active = true
|
||||
|
||||
self._OldAim = self:GetForward()
|
||||
self:OnActivateGun()
|
||||
|
||||
if(self._DoNetworking) then
|
||||
self:SetNWBool("_active", true)
|
||||
self:SetNWBool("_drive", self._DriveMode)
|
||||
self:SetNWEntity("_user", self._User)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:AR3Deactivate()
|
||||
self:ResetSequence(3)
|
||||
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||||
|
||||
if(self._IsShooting) then
|
||||
self:OnStopShooting()
|
||||
end
|
||||
|
||||
if(self._IsKeyDown) then
|
||||
self:OnStopAttack()
|
||||
end
|
||||
|
||||
self._IsShooting = false
|
||||
self._IsKeyDown = false
|
||||
|
||||
if(IsValid(self._User) && !self._AIControlled) then
|
||||
if(!self._DriveMode && IsValid(self._UserPrevWeapon)) then
|
||||
self._User:SelectWeapon(self._UserPrevWeapon:GetClass() or "weapon_crowbar")
|
||||
end
|
||||
|
||||
self:BakuManned(false)
|
||||
self._Active = false
|
||||
|
||||
self:EmitSound("weapons/shotgun/shotgun_cock.wav")
|
||||
self:OnDeactivateGun()
|
||||
end
|
||||
|
||||
self._User = NULL
|
||||
|
||||
if(self._DoNetworking) then
|
||||
self:SetNWBool("_active", false)
|
||||
self:SetNWBool("_drive", self._DriveMode)
|
||||
self:SetNWEntity("_user", self._User)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Use(act, caller, _type, _val)
|
||||
if(self._UseTimer > CurTime() || act:EyePos():DistToSqr(self:GetPos()) > 64 * 64 || self._AIControlled) then return end
|
||||
|
||||
if(self._DriveMode) then
|
||||
if(IsValid(self._Vehicle) && IsValid(JBUFindTheEntInConstraints(self._Vehicle, "Weld", self:GetClass()))) then return
|
||||
else
|
||||
self:BakuRemoveFromVehicle()
|
||||
self._Vehicle = NULL
|
||||
self._DriveMode = false
|
||||
end
|
||||
end
|
||||
|
||||
if(!IsValid(self._User) && !self:BakuIsManned(act)) then
|
||||
self._User = act
|
||||
|
||||
self:AR3Activate()
|
||||
elseif(self._User == act) then
|
||||
self:AR3Deactivate()
|
||||
end
|
||||
|
||||
self._UseTimer = CurTime() + usetime
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:AR3Deactivate()
|
||||
self:DoRemove()
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
|
||||
end
|
||||
|
||||
function ENT:IsGunShooting()
|
||||
return (!self._AIControlled && IsValid(self._User) && self._User:KeyDown(IN_ATTACK)) || (self._AIControlled && self._AIShooting)
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if(self._Active && (!self._AIControlled && IsValid(self._User))) then
|
||||
local aimpoint
|
||||
|
||||
if(self._AIControlled) then
|
||||
aimpoint = self._AIAimPoint
|
||||
else
|
||||
if(IsValid(self._User)) then
|
||||
local ply = self._User
|
||||
|
||||
if(ply:EyePos():DistToSqr(self:GetPos()) > 64 * 64 && !self._DriveMode || !ply:Alive()) then
|
||||
self:AR3Deactivate()
|
||||
end
|
||||
|
||||
local _filter_ = {self, ply}
|
||||
|
||||
if(ply:InVehicle()) then
|
||||
table.insert(_filter_, ply:GetVehicle())
|
||||
end
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = ply:EyePos(),
|
||||
endpos = ply:EyePos() + ply:GetAimVector() * 65535,
|
||||
filter = _filter_ or self
|
||||
})
|
||||
|
||||
aimpoint = tr.HitPos
|
||||
end
|
||||
end
|
||||
|
||||
local transposed1 = JBUmatTranspose3x3(self:GetWorldTransformMatrix())
|
||||
local look = (aimpoint - self:GetBonePosition(4))
|
||||
local __dist = look:LengthSqr()
|
||||
look:Normalize()
|
||||
local mydestlook = JBUApproachVector(self._OldAim, look, 2 * FrameTime())
|
||||
|
||||
self._OldAim = mydestlook
|
||||
local transformed = transposed1 * look
|
||||
local relang = transformed:Angle()
|
||||
|
||||
if(relang.yaw > 180) then
|
||||
relang.yaw = relang.yaw - 360
|
||||
end
|
||||
|
||||
if(relang.pitch > 180) then
|
||||
relang.pitch = relang.pitch - 360
|
||||
end
|
||||
|
||||
if(__dist > 2000) then
|
||||
self:ClearPoseParameters()
|
||||
self:SetPoseParameter("aim_yaw", relang.yaw)
|
||||
self:SetPoseParameter("aim_pitch", relang.pitch + self._PitchOffset)
|
||||
end
|
||||
|
||||
if(self:IsGunShooting()) then
|
||||
if(!self._IsKeyDown) then
|
||||
self:OnStartAttack()
|
||||
self._IsKeyDown = true
|
||||
end
|
||||
|
||||
if(self._ShootTimer < CurTime() && (self._Automatic || !self._IsShooting)) then
|
||||
if(self._Ammo > 0 || self._Ammo < 0) then
|
||||
if(!self._IsShooting) then
|
||||
self._IsShooting = true
|
||||
self:OnStartShooting()
|
||||
end
|
||||
local dest = mydestlook
|
||||
|
||||
if(math.abs(relang.yaw) > 60 || relang.pitch < -35 || relang.pitch > 60) then
|
||||
dest = self:GetAttachment(1).Ang:Forward()
|
||||
end
|
||||
|
||||
if(!self:DoShootThink()) then
|
||||
self:DoShoot(dest)
|
||||
self._ShootTimer = CurTime() + self.ShootDelay
|
||||
|
||||
self:ResetSequence(2)
|
||||
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||||
|
||||
if(self._Ammo > 0) then
|
||||
self._Ammo = self._Ammo - 1
|
||||
end
|
||||
end
|
||||
elseif(self._IsShooting) then
|
||||
self:OnStopShooting()
|
||||
self._IsShooting = false
|
||||
end
|
||||
end
|
||||
else
|
||||
if(self._IsShooting) then
|
||||
self:OnStopShooting()
|
||||
self._IsShooting = false
|
||||
end
|
||||
|
||||
if(self._IsKeyDown) then
|
||||
self._IsKeyDown = false
|
||||
self:OnStopAttack()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(self._AIControlled) then
|
||||
self:DoAIThink()
|
||||
end
|
||||
|
||||
if(self._SequenceTimer < CurTime() && self._Active) then
|
||||
self:ResetSequence(0)
|
||||
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||||
end
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
else
|
||||
function ENT.BaseDupeFunction(ply, data)
|
||||
data._User = NULL
|
||||
data._Active = false
|
||||
|
||||
scripted_ents.Get(data.Class).DupeFunction(ply, data)
|
||||
|
||||
return duplicator.GenericDuplicatorFunction(ply, data)
|
||||
end
|
||||
|
||||
function ENT:DoNotification()
|
||||
if(!IsValid(self._User) or self._User != LocalPlayer()) then return end
|
||||
|
||||
local cookiename = self:GetClass() .. "_notifycookie"
|
||||
if(self._Notification && cookie.GetNumber(cookiename, 0) < os.time()) then
|
||||
cookie.Set(cookiename, tostring(os.time() + 7200))
|
||||
|
||||
local notif = {}
|
||||
if(isstring(self._Notification)) then
|
||||
notif[1] = self._Notification
|
||||
elseif(istable(self._Notification)) then
|
||||
notif = self._Notification
|
||||
end
|
||||
|
||||
local __i = 0
|
||||
for k, v in pairs(notif) do
|
||||
timer.Simple(__i * 0.6, function()
|
||||
notification.AddLegacy( v, NOTIFY_HINT, 5 )
|
||||
surface.PlaySound( "buttons/button15.wav" )
|
||||
end)
|
||||
|
||||
__i = __i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetupCustomModel(mdl, bone, rendergroup)
|
||||
if(IsValid(self._CustomGunModel)) then
|
||||
self._CustomGunModel:SetModel(mdl)
|
||||
else
|
||||
rendergroup = rendergroup or RENDERGROUP_OPAQUE
|
||||
self._CustomGunModel = ClientsideModel(mdl, rendergroup)
|
||||
self._CustomGunModel:SetNoDraw(true)
|
||||
end
|
||||
self._CModelBone = bone or self._CModelBone or 0
|
||||
|
||||
return self._CustomGunModel
|
||||
end
|
||||
|
||||
function ENT:OnDeactivateGun() end
|
||||
function ENT:OnActivateGun() end
|
||||
function ENT:DoDraw() end
|
||||
function ENT:DoThink() end
|
||||
|
||||
function ENT:Initialize()
|
||||
local mins, maxs = self:GetModelBounds()
|
||||
self:SetRenderBounds(mins, maxs, Vector(1, 1, 1) * 30)
|
||||
|
||||
self._CModelBone = 0
|
||||
self._Active = false
|
||||
self._User = NULL
|
||||
self._DriveMode = false
|
||||
|
||||
self:DoInit()
|
||||
|
||||
if(IsValid(self._CustomGunModel)) then
|
||||
self._GunModelMatrix = self._GunModelMatrix or Matrix()
|
||||
|
||||
self._CustomGunModel:SetNoDraw(true)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if(self._Active && !self:GetNWBool("_active")) then
|
||||
self:OnDeactivateGun()
|
||||
self._Active = false
|
||||
|
||||
if(self._DriveMode && LocalPlayer() == self._User) then
|
||||
local mins, maxs = self:GetModelBounds()
|
||||
self:SetRenderBounds(mins, maxs, Vector(1, 1, 1) * 30)
|
||||
end
|
||||
|
||||
self._User = NULL
|
||||
self._DriveMode = false
|
||||
elseif(!self._Active && self:GetNWBool("_active")) then
|
||||
self._User = self:GetNWEntity("_user")
|
||||
self._DriveMode = self:GetNWBool("_drive")
|
||||
self._Active = true
|
||||
self:OnActivateGun()
|
||||
self:DoNotification()
|
||||
|
||||
if(self._DriveMode && LocalPlayer() == self._User) then
|
||||
local _x_y_z = Vector(65535, 65535, 65535)
|
||||
self:SetRenderBounds(-_x_y_z, _x_y_z)
|
||||
end
|
||||
end
|
||||
|
||||
self:DoThink()
|
||||
end
|
||||
|
||||
local chair = Material("sprites/hud/v_crosshair1")
|
||||
local flashlight = Material("sprites/glow03")
|
||||
local glow = Material("sprites/glow_test02")
|
||||
|
||||
function ENT:DrawCustomGunModel()
|
||||
self._CustomGunModel:SetupBones()
|
||||
|
||||
local mat2 = self:GetBoneMatrix(4) * self._GunModelMatrix
|
||||
|
||||
self._CustomGunModel:SetPos(self:GetPos())
|
||||
self._CustomGunModel:SetBoneMatrix(self._CModelBone, mat2)
|
||||
self._CustomGunModel:DrawModel()
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
self:DoDraw()
|
||||
|
||||
if(IsValid(self._CustomGunModel)) then
|
||||
self:DrawCustomGunModel()
|
||||
end
|
||||
|
||||
local ply = self._User
|
||||
|
||||
if(self._DriveMode && ply == LocalPlayer()) then
|
||||
render.SetMaterial(chair)
|
||||
render.DrawSprite(ply:EyePos() + ply:GetAimVector() * 200, 8, 8, Color(255,255,0,255))
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if(IsValid(self._CustomGunModel)) then
|
||||
self._CustomGunModel:Remove()
|
||||
end
|
||||
|
||||
self:OnDeactivateGun()
|
||||
self:DoRemove()
|
||||
end
|
||||
end
|
||||
107
lua/entities/ent_mannable_choppergun.lua
Normal file
107
lua/entities/ent_mannable_choppergun.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Chopper gun"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT.DupeFunction(ply, data)
|
||||
data.__PreFireTimer = 0
|
||||
end
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.__ShootSound = nil
|
||||
self.__PreFireTimer = 0
|
||||
self.ShootDelay = 0.075
|
||||
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
local __dur = SoundDuration("NPC_AttackHelicopter.ChargeGun")
|
||||
|
||||
function ENT:OnStartAttack()
|
||||
if(self.__PreFireTimer < CurTime()) then
|
||||
self:EmitSound("NPC_AttackHelicopter.ChargeGun")
|
||||
self.__PreFireTimer = CurTime() + __dur
|
||||
end
|
||||
|
||||
self._ShootTimer = CurTime() + __dur
|
||||
self._Ammo = 40
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
self.__ShootSound = CreateSound(self, "NPC_AttackHelicopter.FireGun")
|
||||
self.__ShootSound:Play()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:FadeOut(0.5)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "AirboatGunTracer",
|
||||
Damage = 10,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.04,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Num = 3,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
_dmg:SetDamageType(DMG_AIRBOAT)
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
|
||||
util.Effect("ChopperMuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
self:SetupCustomModel("models/airboatgun.mdl")
|
||||
|
||||
self._Notification = "Hold left mouse, let it charge and FIRE!"
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Scale(Vector(1,1,1) * 1.2)
|
||||
mat:Rotate(Angle(0, 90, 90))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
end
|
||||
105
lua/entities/ent_mannable_combinecannon.lua
Normal file
105
lua/entities/ent_mannable_combinecannon.lua
Normal file
@@ -0,0 +1,105 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Combine cannon"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = IsMounted("ep2")
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.ShootDelay = 0.5
|
||||
self._Automatic = false
|
||||
|
||||
self._DoNetworking = true
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "eff_baku_combinecannon_tracer",
|
||||
Damage = 26,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Num = 1,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
_dmg:SetDamageType(bit.bor(DMG_BLAST, DMG_BURN))
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(_tr.HitPos + _tr.HitNormal * 3)
|
||||
ef:SetNormal(_tr.HitNormal)
|
||||
ef:SetRadius(40)
|
||||
|
||||
util.Effect("cball_explode", ef)
|
||||
|
||||
if(_tr.HitWorld) then
|
||||
util.Effect("AR2Explosion", ef)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
self:EmitSound("NPC_Combine_Cannon.FireBullet")
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(5)
|
||||
|
||||
util.Effect("MuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
local mdl = self:SetupCustomModel("models/combine_turrets/combine_cannon_gun.mdl", 3)
|
||||
|
||||
mdl:ManipulateBoneScale(4, Vector(0, 0, 0))
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Rotate(Angle(0, 90, 90))
|
||||
mat:Translate(Vector(0, -12, 3))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
|
||||
local glow = Material("sprites/combine_cannon_glow")
|
||||
|
||||
function ENT:DoDraw()
|
||||
if(self._Active) then
|
||||
render.SetMaterial(glow)
|
||||
render.DrawSprite(self:GetAttachment(1).Pos, 40, 32)
|
||||
end
|
||||
end
|
||||
end
|
||||
115
lua/entities/ent_mannable_combinesniper.lua
Normal file
115
lua/entities/ent_mannable_combinesniper.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Combine Sniper rifle"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
ENT._HideGunModel = true
|
||||
ENT._Automatic = false
|
||||
ENT._DoNetworking = true
|
||||
ENT.ShootDelay = 1
|
||||
|
||||
function ENT:DoInit()
|
||||
self._HideGunModel = true
|
||||
self._Automatic = false
|
||||
self._DoNetworking = true
|
||||
self.ShootDelay = 1
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnActivateGun()
|
||||
if(!IsValid(self._User) || !self._User:IsPlayer()) then return end
|
||||
self._User:SetFOV(20)
|
||||
end
|
||||
|
||||
function ENT:OnDeactivateGun()
|
||||
if(!IsValid(self._User) || !self._User:IsPlayer()) then return end
|
||||
self._User:SetFOV(0)
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "AR2Tracer",
|
||||
Damage = 40,
|
||||
Force = 10,
|
||||
Spread = Vector(0, 0, 0),
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
if(_tr.HitGroup == HITGROUP_HEAD) then
|
||||
_dmg:SetDamage(1000)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
self:EmitSound("NPC_Sniper.FireBullet")
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(5)
|
||||
|
||||
util.Effect("MuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
local mat = Matrix()
|
||||
if(IsMounted("ep2")) then
|
||||
self:SetupCustomModel("models/weapons/w_combine_sniper.mdl")
|
||||
mat:Rotate(Angle(0, 180, 0))
|
||||
else
|
||||
self:SetupCustomModel("models/weapons/w_snip_scout.mdl")
|
||||
mat:Rotate(Angle(12, 0, 180))
|
||||
end
|
||||
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
|
||||
local overlay = Material("effects/combine_binocoverlay")
|
||||
|
||||
function ENT:OnActivateGun()
|
||||
if(self._User == LocalPlayer()) then
|
||||
hook.Add("HUDPaint", "MannableSniperOverlay", function()
|
||||
render.SetMaterial(overlay)
|
||||
render.DrawScreenQuad()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnDeactivateGun()
|
||||
if(self._User == LocalPlayer()) then
|
||||
hook.Remove("HUDPaint", "MannableSniperOverlay")
|
||||
end
|
||||
end
|
||||
|
||||
local _beam = Material("sprites/bluelaser1")
|
||||
end
|
||||
393
lua/entities/ent_mannable_editable.lua
Normal file
393
lua/entities/ent_mannable_editable.lua
Normal file
@@ -0,0 +1,393 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Editable Gun"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.Editable = true
|
||||
|
||||
local __muzzles = {
|
||||
{effect = "GunshipMuzzleFlash"},
|
||||
{effect = "ChopperMuzzleFlash"},
|
||||
{effect = "AirboatMuzzleFlash"},
|
||||
{effect = "MuzzleFlash", flags = 7},
|
||||
{effect = "CS_MuzzleFlash"},
|
||||
{effect = "CS_MuzzleFlash_X"},
|
||||
{effect = "StriderMuzzleFlash"},
|
||||
{effect = "MuzzleFlash", flags = 5}
|
||||
}
|
||||
|
||||
local __tracers = {
|
||||
"AR2Tracer",
|
||||
"HelicopterTracer",
|
||||
"AirboatGunTracer",
|
||||
"Tracer",
|
||||
"ToolTracer",
|
||||
"eff_baku_combinecannon_tracer",
|
||||
"eff_baku_jeeptracer",
|
||||
}
|
||||
|
||||
local __impacts = {
|
||||
"StunstickImpact",
|
||||
"BoltImpact",
|
||||
"ManhackSparks",
|
||||
"HelicopterMegaBomb",
|
||||
"AR2Impact",
|
||||
}
|
||||
|
||||
local __shells = {
|
||||
"ShellEject",
|
||||
"RifleShellEject",
|
||||
"ShotgunShellEject"
|
||||
}
|
||||
|
||||
function ENT:DoSetupDataTables()
|
||||
self:NetworkVar("Int", 0, "ProjectileType", {KeyName = "projtype", Edit = { title = "Projectile type", category = "Projectile", type = "Combo", order = 10, values = {
|
||||
["Bullet"] = 1,
|
||||
["Flechette"] = 2,
|
||||
["SMG Grenade"] = 3,
|
||||
["Rocket"] = 4,
|
||||
}}})
|
||||
|
||||
self:NetworkVar("Float", 0, "PhysProjVel", {KeyName = "physvel", Edit = {title = "Phys projectile velocity", category = "Projectile", type = "Float", order = 20,
|
||||
min = 0, max = 8000}})
|
||||
|
||||
self:NetworkVar("Float", 3, "Spread", {KeyName = "spread", Edit = {title = "Spread", category = "Projectile", type = "Float", order = 26,
|
||||
min = 0, max = 10}})
|
||||
|
||||
self:NetworkVar("Float", 1, "FireDelay", {KeyName = "firedelay", Edit = {title = "Fire delay", category = "Projectile", type = "Float", order = 25,
|
||||
min = 0.05, max = 10}})
|
||||
|
||||
self:NetworkVar("Int", 1, "ProjDamage", {KeyName = "damage", Edit = {title = "Damage", category = "Projectile", type = "Int", order = 30,
|
||||
min = 0, max = 100}})
|
||||
|
||||
self:NetworkVar("Int", 2, "NumProjectiles", {KeyName = "numprojectiles", Edit = {title = "Bullets per shot", category = "Projectile", type = "Int", order = 40,
|
||||
min = 0, max = 20}})
|
||||
|
||||
self:NetworkVar("String", 0, "ShootSound", {KeyName = "shootsound", Edit = {title = "Shoot sound", category = "Sound", type = "Generic", order = 50}})
|
||||
self:NetworkVar("Bool", 0, "__LoopSound", {KeyName = "loopsound", Edit = {title = "Loop fire sound", category = "Sound", type = "Boolean", order = 55}})
|
||||
self:NetworkVar("String", 1, "ChargeSound", {KeyName = "chargesound", Edit = {title = "Charge sound", category = "Sound", type = "Generic", order = 60}})
|
||||
self:NetworkVar("Float", 2, "ChargeTime", {KeyName = "chargetime", Edit = {title = "Charge time", category = "Sound", type = "Float", order = 70, min = 0, max = 10}})
|
||||
self:NetworkVar("String", 3, "EndFireSound", {KeyName = "endfiresound", Edit = {title = "Last fire Sound", category = "Sound", type = "Generic", order = 75}})
|
||||
|
||||
self:NetworkVar("Int", 3, "MuzzleEffect", {KeyName = "muzzleeffect", Edit = { title = "Muzzle flash", category = "Effects", type = "Combo", order = 80, values = {
|
||||
["Airboat Gun"] = 3,
|
||||
["Chopper"] = 2,
|
||||
["Gunship"] = 1,
|
||||
["Counter Strike X"] = 6,
|
||||
["HL2 Default"] = 4,
|
||||
["Counter Strike"] = 5,
|
||||
["Strider"] = 7,
|
||||
["Combine"] = 8
|
||||
}}})
|
||||
|
||||
self:NetworkVar("Int", 4, "TracerEffect", {KeyName = "tracereffect", Edit = { title = "Tracer", category = "Effects", type = "Combo", order = 90, values = {
|
||||
["AR2"] = 1,
|
||||
["Chopper"] = 2,
|
||||
["Airboat Gun"] = 3,
|
||||
["HL2 Default"] = 4,
|
||||
["Toolgun"] = 5,
|
||||
["Combine cannon"] = 6,
|
||||
["Gauss gun"] = 7,
|
||||
}}})
|
||||
|
||||
self:NetworkVar("Int", 5, "ShellEject", {KeyName = "shelleject", Edit = { title = "Shells", category = "Effects", type = "Combo", order = 100, values = {
|
||||
["None"] = 0,
|
||||
["Default"] = 1,
|
||||
["Rifle"] = 2,
|
||||
["Buckshot"] = 3,
|
||||
}}})
|
||||
|
||||
if(SERVER) then
|
||||
self:NetworkVarNotify("ChargeSound", self.HandleVarChange)
|
||||
self:NetworkVarNotify("ChargeTime", self.HandleVarChange)
|
||||
self:NetworkVarNotify("FireDelay", self.HandleVarChange)
|
||||
self:NetworkVarNotify("__LoopSound", self.HandleVarChange)
|
||||
self:NetworkVarNotify("ShootSound", self.HandleVarChange)
|
||||
self:NetworkVarNotify("TracerEffect", self.HandleVarChange)
|
||||
self:NetworkVarNotify("MuzzleEffect", self.HandleVarChange)
|
||||
end
|
||||
|
||||
self:SetShootSound("Weapon_AR2.NPC_Single")
|
||||
self:SetChargeSound("Jeep.GaussCharge")
|
||||
self:Set__LoopSound(false)
|
||||
self:SetProjectileType(1)
|
||||
self:SetFireDelay(0.075)
|
||||
self:SetProjDamage(13)
|
||||
self:SetNumProjectiles(1)
|
||||
self:SetPhysProjVel(1000)
|
||||
self:SetSpread(3)
|
||||
self:SetMuzzleEffect(8)
|
||||
self:SetTracerEffect(1)
|
||||
self:SetShellEject(0)
|
||||
end
|
||||
|
||||
if(SERVER) then
|
||||
function ENT.DupeFunction(ply, data)
|
||||
data.__PreFireTimer = 0
|
||||
end
|
||||
|
||||
ENT.ShootDelay = 0.075
|
||||
ENT.__PreFireTimer = 0
|
||||
ENT.__IsLoopSound = false
|
||||
ENT.__ShootSound = false
|
||||
ENT.__TracerEffect = "Tracer"
|
||||
ENT.__MuzzleEffect = {effect = "MuzzleFlash", flags = 5}
|
||||
ENT._PitchOffset = 10
|
||||
|
||||
ENT.__ChargeSound = nil
|
||||
ENT.__DoCharge = false
|
||||
|
||||
ENT._HideGunModel = false
|
||||
|
||||
local _varhandlers = {
|
||||
["ChargeSound"] = function(self, old, new)
|
||||
local cleared = string.Trim(new)
|
||||
|
||||
if(cleared != "") then
|
||||
self.__ChargeSoundName = cleared
|
||||
else
|
||||
self.__ChargeSoundName = nil
|
||||
end
|
||||
end,
|
||||
|
||||
["ChargeTime"] = function(self, old, new)
|
||||
self.__DoCharge = new > 0.001
|
||||
end,
|
||||
|
||||
["FireDelay"] = function(self, old, new)
|
||||
self.ShootDelay = new
|
||||
end,
|
||||
|
||||
["__LoopSound"] = function(self, old, new)
|
||||
self.__IsLoopSound = new
|
||||
end,
|
||||
|
||||
["ShootSound"] = function(self, old, new)
|
||||
local cleared = string.Trim(new)
|
||||
|
||||
if(cleared != "") then
|
||||
self.__ShootSoundName = cleared
|
||||
else
|
||||
self.__ShootSoundName = nil
|
||||
end
|
||||
end,
|
||||
["TracerEffect"] = function(self, old, new)
|
||||
if(__tracers[new]) then
|
||||
self.__TracerEffect = __tracers[new]
|
||||
end
|
||||
end,
|
||||
["MuzzleEffect"] = function(self, old, new)
|
||||
if(__muzzles[new]) then
|
||||
self.__MuzzleEffect = __muzzles[new]
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
function ENT:HandleVarChange(name, old, new)
|
||||
if(isfunction(_varhandlers[name])) then
|
||||
if(old != new) then
|
||||
_varhandlers[name](self, old, new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
|
||||
self.ShootDelay = 0.075
|
||||
self.__ShootSoundName = self.__ShootSoundName or "Airboat.FireGunLoop"
|
||||
self.__ChargeSound = self.__ChargeSound or "Airboat.FireGunLoop"
|
||||
self.__PreFireTimer = 0
|
||||
self.__IsLoopSound = self.__IsLoopSound or false
|
||||
self.__ShootSound = self.__ShootSound or false
|
||||
self.__TracerEffect = self.__TracerEffect or "Tracer"
|
||||
self.__MuzzleEffect = self.__MuzzleEffect or {effect = "MuzzleFlash", flags = 5}
|
||||
self._PitchOffset = 10
|
||||
|
||||
self.__ChargeSound = nil
|
||||
self.__DoCharge = false
|
||||
|
||||
self._HideGunModel = false
|
||||
end
|
||||
|
||||
function ENT:OnStartAttack()
|
||||
if(self.__PreFireTimer < CurTime() && self.__DoCharge) then
|
||||
local delay = CurTime() + self:GetChargeTime()
|
||||
self.__PreFireTimer = delay
|
||||
self._ShootTimer = delay
|
||||
|
||||
if(self.__DoCharge) then
|
||||
self.__ChargeSound = CreateSound(self, self.__ChargeSoundName)
|
||||
self.__ChargeSound:Play()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
if(self.__DoCharge && self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
|
||||
if(self.__IsLoopSound) then
|
||||
self.__ShootSound = CreateSound(self, self.__ShootSoundName)
|
||||
self.__ShootSound:Play()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnStopAttack()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
|
||||
if(self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
|
||||
self:EmitSound(self:GetEndFireSound())
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
local function createphysprojectile(self, dest, class, damagefunc)
|
||||
local num = self:GetNumProjectiles()
|
||||
|
||||
for i = 1, num do
|
||||
local proj = ents.Create(class)
|
||||
proj:SetPos(self:GetAttachment(1).Pos + dest * 10)
|
||||
proj:SetAngles(dest:Angle())
|
||||
|
||||
if(isfunction(damagefunc)) then
|
||||
damagefunc(self:GetProjDamage(), proj)
|
||||
end
|
||||
|
||||
proj:SetOwner(self._User)
|
||||
proj:Spawn()
|
||||
|
||||
local phys = proj:GetPhysicsObject()
|
||||
|
||||
if(IsValid(phys)) then
|
||||
phys:SetVelocity((dest + VectorRand() * self:GetSpread() * 0.01):GetNormalized() * self:GetPhysProjVel())
|
||||
else
|
||||
proj:SetVelocity((dest + VectorRand() * self:GetSpread() * 0.01):GetNormalized() * self:GetPhysProjVel())
|
||||
end
|
||||
|
||||
/*local tbl = proj:GetSaveTable(true)
|
||||
|
||||
print("-------------------------")
|
||||
for k, v in pairs(tbl) do
|
||||
if(!istable(v) && ( string.find(string.lower(k), "vel") )) then
|
||||
print(k, v)
|
||||
end
|
||||
end*/
|
||||
end
|
||||
end
|
||||
|
||||
local function setrocketdamage(dmg, proj)
|
||||
proj:SetSaveValue("m_flDamage", math.max(dmg, 40))
|
||||
end
|
||||
|
||||
local function setboltdamage(dmg, proj)
|
||||
//-N-O---W-O-R-K---S-H-I-T-
|
||||
end
|
||||
|
||||
local projectiles = {
|
||||
[1] = function(self, dest)
|
||||
//bullet
|
||||
local bullet = {
|
||||
TracerName = self.__TracerEffect,
|
||||
Damage = self:GetProjDamage(),
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * self:GetSpread() * 0.01,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Num = self:GetNumProjectiles(),
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
end,
|
||||
|
||||
[2] = function(self, dest)
|
||||
createphysprojectile(self, dest, "hunter_flechette")
|
||||
end,
|
||||
|
||||
[3] = function(self, dest)
|
||||
createphysprojectile(self, dest, "grenade_ar2")
|
||||
end,
|
||||
|
||||
[4] = function(self, dest)
|
||||
createphysprojectile(self, dest, "rpg_missile", setrocketdamage)
|
||||
end,
|
||||
|
||||
[5] = function(self, dest)
|
||||
//createphysprojectile(self, dest, "rpg_missile", setrocketdamage)
|
||||
end,
|
||||
|
||||
[6] = function(self, dest)
|
||||
createphysprojectile(self, dest, "crossbow_bolt", setboltdamage)
|
||||
end,
|
||||
}
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local func = projectiles[self:GetProjectileType()]
|
||||
|
||||
if(isfunction(func)) then
|
||||
func(self, dest)
|
||||
else
|
||||
projectiles[1](self, dest)
|
||||
end
|
||||
|
||||
if(!self.__IsLoopSound) then
|
||||
self:EmitSound(self:GetShootSound())
|
||||
end
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(self.__MuzzleEffect.flags or 0)
|
||||
|
||||
util.Effect(self.__MuzzleEffect.effect, ef)
|
||||
|
||||
if(self:GetShellEject() > 0) then
|
||||
ef = EffectData()
|
||||
ef:SetOrigin(self:GetBonePosition(4))
|
||||
ef:SetAngles(self:GetRight():Angle())
|
||||
|
||||
util.Effect(__shells[self:GetShellEject()], ef)
|
||||
end
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
/*self:SetupCustomModel("models/weapons/w_hmg1.mdl")
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Translate(Vector(5, 0, -1))
|
||||
mat:Rotate(Angle(0, 90, 3))
|
||||
self._GunModelMatrix = mat*/
|
||||
end
|
||||
|
||||
function ENT:DoThink()
|
||||
|
||||
end
|
||||
end
|
||||
110
lua/entities/ent_mannable_fiery.lua
Normal file
110
lua/entities/ent_mannable_fiery.lua
Normal file
@@ -0,0 +1,110 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Incendiary gun (geneva no like)"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
ENT.ShootDelay = 0.075
|
||||
|
||||
ENT._DoNetworking = true
|
||||
ENT._HideGunModel = false
|
||||
ENT._PitchOffset = 10
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.ShootDelay = 0.05
|
||||
|
||||
self._DoNetworking = true
|
||||
self._HideGunModel = false
|
||||
self._PitchOffset = 10
|
||||
self.__ShootSound = nil
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("eff_baku_impactor", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
self.__ShootSound = CreateSound(self, "poopass/fireloop.wav")
|
||||
self.__ShootSound:Play()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
self:EmitSound("poopass/winddown.wav")
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "eff_baku_burntcer",
|
||||
Damage = 10,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.02,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
local ent = _tr.Entity
|
||||
|
||||
if(!ent:IsPlayer()) then
|
||||
ent:Ignite(2)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
//self:EmitSound("Weapon_AR2.NPC_Single")
|
||||
|
||||
local eff = EffectData()
|
||||
eff:SetEntity(self)
|
||||
eff:SetAttachment(1)
|
||||
eff:SetScale(2)
|
||||
|
||||
util.Effect("eff_baku_burnzzle", eff)
|
||||
end
|
||||
else
|
||||
function ENT:OnActivateGun()
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnDeactivateGun()
|
||||
|
||||
end
|
||||
|
||||
local glow = Material("sprites/combine_cannon_glow")
|
||||
|
||||
function ENT:DoDraw()
|
||||
/*if(self._Active) then
|
||||
render.SetMaterial(glow)
|
||||
render.DrawSprite(self:GetAttachment(1).Pos, 40, 32)
|
||||
end*/
|
||||
end
|
||||
end
|
||||
193
lua/entities/ent_mannable_gauss.lua
Normal file
193
lua/entities/ent_mannable_gauss.lua
Normal file
@@ -0,0 +1,193 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Gauss Gun"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT.DupeFunction(ply, data)
|
||||
data.__PreFireTimer = 0
|
||||
end
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.__ChargeSound = nil
|
||||
self.__PreFireTimer = 0
|
||||
self.ShootDelay = 0.075
|
||||
self._Automatic = false
|
||||
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
function ENT:OnStartAttack()
|
||||
if(self.__PreFireTimer < CurTime()) then
|
||||
self.__ChargeSound = CreateSound(self, "Jeep.GaussCharge")
|
||||
self.__ChargeSound:Play()
|
||||
self.__PreFireTimer = CurTime() + 0.4
|
||||
|
||||
if(math.random(1, 4) == 2) then
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(self:GetBonePosition(4))
|
||||
ef:SetMagnitude(2)
|
||||
|
||||
util.Effect("ElectricSpark", ef)
|
||||
end
|
||||
|
||||
self._ShootTimer = CurTime() + 0.4
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnStopAttack()
|
||||
if(self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
if(self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ChargeSound) then
|
||||
self.__ChargeSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local lastpos = self:GetAttachment(1).Pos
|
||||
local lastdir = dest
|
||||
local lasthitpos = lastpos
|
||||
local lastent = self
|
||||
|
||||
local bounces = math.random(3, 8)
|
||||
|
||||
local __kika02aa = self._User
|
||||
|
||||
local hitentities = {[__kika02aa:EntIndex()] = true}
|
||||
|
||||
for i = 1, bounces do
|
||||
local tr = util.TraceLine({
|
||||
start = lastpos,
|
||||
endpos = lastpos + lastdir * 65535,
|
||||
filter = lastent
|
||||
})
|
||||
|
||||
local __i = ((bounces - i + 1) / bounces)
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos)
|
||||
ef:SetStart(lastpos)
|
||||
ef:SetEntity(NULL)
|
||||
ef:SetScale(__i)
|
||||
ef:SetFlags(0)
|
||||
|
||||
util.Effect("eff_baku_jeeptracer",ef)
|
||||
|
||||
lastpos = tr.HitPos
|
||||
lastdir = ((lastdir - 2 * lastdir:Dot(tr.HitNormal) * tr.HitNormal) + VectorRand() * 0.01):GetNormalized()
|
||||
lasthitpos = tr.HitPos
|
||||
|
||||
if(IsValid(tr.Entity)) then
|
||||
hitentities[tr.Entity:EntIndex()] = true
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetDamage( __i * 40 )
|
||||
dmg:SetDamageType(bit.bor(DMG_SHOCK, DMG_BULLET, DMG_ENERGYBEAM))
|
||||
dmg:SetAttacker(__kika02aa)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamagePosition(tr.HitPos)
|
||||
|
||||
tr.Entity:TakeDamageInfo(dmg)
|
||||
|
||||
if(math.random(1,4) > 1 && tr.Entity:IsNPC()) then
|
||||
lastent = tr.Entity
|
||||
local entsnear = ents.FindInSphere(tr.HitPos, 512)
|
||||
local ent = nil
|
||||
|
||||
local lasthealth = 65535
|
||||
|
||||
for k, v in pairs(entsnear) do
|
||||
if(v:IsNPC() && !hitentities[v:EntIndex()] && v:Health() < lasthealth) then
|
||||
ent = v
|
||||
lasthealth = v:Health()
|
||||
end
|
||||
end
|
||||
|
||||
if(IsValid(ent)) then
|
||||
hitentities[ent:EntIndex()] = true
|
||||
lastdir = (ent:GetPos() + ent:OBBCenter() - tr.HitPos):GetNormalized()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if(tr.HitSky) then break end
|
||||
|
||||
sound.Play("weapons/fx/rics/ric" .. math.random(1, 5) .. ".wav", tr.HitPos, 75, 100 + math.random(-20, 20), 10)
|
||||
end
|
||||
|
||||
self:EmitSound("PropJeep.FireCannon")
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(7)
|
||||
|
||||
util.Effect("MuzzleFlash", ef)
|
||||
|
||||
ef = EffectData()
|
||||
ef:SetOrigin(lasthitpos)
|
||||
|
||||
util.Effect("cball_explode", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
self:SetupCustomModel("models/weapons/jakubbaku/w_gauss.mdl", 1)
|
||||
|
||||
self._Notification = {"Hold left mouse, let it charge.", "Watch out for ricochetes!"}
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Translate(Vector(-3, 0, 0))
|
||||
mat:Rotate(Angle(0, 90, 94))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
|
||||
function ENT:DoThink()
|
||||
|
||||
end
|
||||
|
||||
local glow = Material("sprites/bakuglow")
|
||||
|
||||
function ENT:DoDraw()
|
||||
if(self._Active) then
|
||||
local pos = self:GetAttachment(1).Pos
|
||||
render.SetMaterial(glow)
|
||||
render.DrawSprite(pos, 40, 32, Color(255, 180, 40))
|
||||
|
||||
local dlight = DynamicLight( self:EntIndex() )
|
||||
if ( dlight ) then
|
||||
dlight.pos = pos
|
||||
dlight.r = 255
|
||||
dlight.g = 180
|
||||
dlight.b = 40
|
||||
dlight.brightness = 1
|
||||
dlight.Decay = 100
|
||||
dlight.Size = 64
|
||||
dlight.DieTime = CurTime() + 0.1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
112
lua/entities/ent_mannable_gunship.lua
Normal file
112
lua/entities/ent_mannable_gunship.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
--[[
|
||||
| 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 = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Gunship cannon"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT.DupeFunction(ply, data)
|
||||
data.__PreFireTimer = 0
|
||||
end
|
||||
|
||||
ENT.__ShootSound = nil
|
||||
ENT.__PreFireTimer = 0
|
||||
ENT.ShootDelay = 0.09
|
||||
|
||||
ENT._HideGunModel = true
|
||||
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.__ShootSound = nil
|
||||
self.__PreFireTimer = 0
|
||||
self.ShootDelay = 0.09
|
||||
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
function ENT:OnStartAttack()
|
||||
if(self.__PreFireTimer < CurTime()) then
|
||||
self:EmitSound("NPC_CombineGunship.CannonStartSound")
|
||||
self.__PreFireTimer = CurTime() + 0.4
|
||||
end
|
||||
|
||||
self._ShootTimer = CurTime() + 0.4
|
||||
self._Ammo = 20
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
self.__ShootSound = CreateSound(self, "NPC_CombineGunship.CannonSound")
|
||||
self.__ShootSound:Play()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
self:EmitSound("NPC_CombineGunship.CannonStopSound")
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
if(self.__ShootSound) then
|
||||
self.__ShootSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoImpactEffect(tr, _dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("AR2Impact", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "AirboatGunTracer",
|
||||
Damage = 12,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.01,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
Callback = function(_att, _tr, _dmg)
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
|
||||
util.Effect("GunshipMuzzleFlash", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
self:SetupCustomModel("models/gibs/gunship_gibs_nosegun.mdl")
|
||||
|
||||
self._Notification = "Hold left mouse, charge and fire."
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Scale(Vector(1,1,1) * 0.4)
|
||||
mat:Rotate(Angle(-3, 0, 0))
|
||||
mat:Translate(Vector(0, 5, 10))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
end
|
||||
79
lua/entities/ent_mannable_hmg.lua
Normal file
79
lua/entities/ent_mannable_hmg.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Base = "ent_mannable_bakubase"
|
||||
ENT.PrintName = "Heavy machine gun"
|
||||
ENT.Category = "Jakub Baku Emplacements"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if(SERVER) then
|
||||
function ENT:DoInit()
|
||||
self:BakuRegisterMannable()
|
||||
self.ShootDelay = 0.075
|
||||
|
||||
self._HideGunModel = true
|
||||
end
|
||||
|
||||
function ENT:OnStartShooting()
|
||||
end
|
||||
|
||||
function ENT:OnStopShooting()
|
||||
end
|
||||
|
||||
function ENT:DoRemove()
|
||||
end
|
||||
|
||||
function ENT:DoShoot(dest)
|
||||
local bullet = {
|
||||
TracerName = "Tracer",
|
||||
Damage = 13,
|
||||
Force = 5,
|
||||
Spread = Vector(1, 1, 0) * 0.02,
|
||||
Src = self:GetAttachment(1).Pos,
|
||||
Dir = dest,
|
||||
Num = 1,
|
||||
Attacker = self._User,
|
||||
Inflictor = self,
|
||||
}
|
||||
|
||||
self:FireBullets(bullet)
|
||||
self:EmitSound("weapons/hmg1/shot.wav")
|
||||
//self:EmitSound("weapons/hmg1/shot.wav")
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetEntity(self)
|
||||
ef:SetAttachment(1)
|
||||
ef:SetFlags(7)
|
||||
|
||||
util.Effect("MuzzleFlash", ef)
|
||||
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(self:GetBonePosition(4))
|
||||
ef:SetAngles(self:GetRight():Angle())
|
||||
|
||||
util.Effect("RifleShellEject", ef)
|
||||
end
|
||||
else
|
||||
function ENT:DoInit()
|
||||
self:SetupCustomModel("models/weapons/jakubbaku/w_hmg1.mdl")
|
||||
|
||||
local mat = Matrix()
|
||||
mat:Translate(Vector(5, 0, -1))
|
||||
mat:Rotate(Angle(0, 90, 3))
|
||||
self._GunModelMatrix = mat
|
||||
end
|
||||
|
||||
function ENT:DoThink()
|
||||
|
||||
end
|
||||
end
|
||||
94
lua/entities/ent_musical_keyboard/cl_init.lua
Normal file
94
lua/entities/ent_musical_keyboard/cl_init.lua
Normal file
@@ -0,0 +1,94 @@
|
||||
--[[
|
||||
| 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" )
|
||||
|
||||
local blackKeys = {
|
||||
[1] = true, [3] = true, [6] = true, [8] = true, [10] = true
|
||||
}
|
||||
|
||||
local keyColors = {
|
||||
default = Color( 255, 148, 77 ),
|
||||
automated = Color( 171, 0, 197 )
|
||||
}
|
||||
|
||||
local keyOffsets = {
|
||||
[2] = 0.2,
|
||||
[4] = 0.4,
|
||||
[5] = -0.1,
|
||||
[7] = 0.1,
|
||||
[9] = 0.4,
|
||||
[11] = 0.6
|
||||
}
|
||||
|
||||
local Remap = math.Remap
|
||||
local RealTime = RealTime
|
||||
|
||||
function ENT:Initialize()
|
||||
self.drawNotes = {}
|
||||
end
|
||||
|
||||
function ENT:EmitNote( note, velocity, instrument, automated )
|
||||
local data = MKeyboard.instruments[instrument]
|
||||
|
||||
if not data then return end
|
||||
if note < data.noteMin or note > data.noteMax then return end
|
||||
|
||||
sound.Play( string.format( data.path, note ), self:GetPos(), 80, 100, velocity / 127 )
|
||||
|
||||
local idx = note % 12
|
||||
local len = 8
|
||||
local height = -0.2
|
||||
local width = 1.6
|
||||
local x = -1.1
|
||||
|
||||
if blackKeys[idx] then
|
||||
len = 5
|
||||
height = 0.1
|
||||
width = 1
|
||||
x = -0.6
|
||||
end
|
||||
|
||||
if keyOffsets[idx] then
|
||||
x = x + keyOffsets[idx]
|
||||
end
|
||||
|
||||
self.drawNotes[note] = {
|
||||
x = Remap( note, 21, 108, -37, 36.7 ),
|
||||
t = RealTime() + 0.2,
|
||||
min = Vector( x, -1.5, -1 ),
|
||||
max = Vector( x + width, len, height ),
|
||||
color = keyColors[automated and "automated" or "default"]
|
||||
}
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
local t = RealTime()
|
||||
local ang = self:GetAngles()
|
||||
|
||||
render.SetColorMaterial()
|
||||
|
||||
for note, p in pairs( self.drawNotes ) do
|
||||
if t > p.t then
|
||||
self.drawNotes[note] = nil
|
||||
else
|
||||
local color = p.color
|
||||
local alpha = 255 * ( ( p.t - t ) / 0.2 )
|
||||
|
||||
render.DrawBox(
|
||||
self:LocalToWorld( Vector( -p.x, 0, 0 ) ),
|
||||
ang, p.min, p.max,
|
||||
Color( color.r, color.g, color.b, alpha )
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
197
lua/entities/ent_musical_keyboard/init.lua
Normal file
197
lua/entities/ent_musical_keyboard/init.lua
Normal file
@@ -0,0 +1,197 @@
|
||||
--[[
|
||||
| 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" )
|
||||
|
||||
local MAX_USE_DISTANCE = 300 * 300
|
||||
|
||||
local function MakeKeyboardSpawner( ply, data )
|
||||
if IsValid( ply ) and not ply:CheckLimit( "musical_keyboards" ) then return end
|
||||
|
||||
local ent = ents.Create( data.Class )
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent:SetPos( data.Pos )
|
||||
ent:SetAngles( data.Angle )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
ply:AddCount( "musical_keyboards", ent )
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "ent_musical_keyboard", MakeKeyboardSpawner, "Data" )
|
||||
|
||||
function ENT:SpawnFunction( ply, tr )
|
||||
if tr.Hit then
|
||||
return MakeKeyboardSpawner( ply, {
|
||||
Pos = tr.HitPos,
|
||||
Angle = Angle( 0, ply:EyeAngles().y + 90, 0 ),
|
||||
Class = self.ClassName
|
||||
} )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel( "models/styledstrike/musical_keyboard.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
self:DrawShadow( true )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid( phys ) then phys:Wake() end
|
||||
|
||||
if WireLib then
|
||||
WireLib.CreateSpecialOutputs( self, { "NotePlayed" }, { "ARRAY" }, {
|
||||
[[Triggered when the user played a note.
|
||||
This array contains:
|
||||
[1] Note number,
|
||||
[2] Note velocity
|
||||
[3] Instrument index (The number near each name on the instruments list)]]
|
||||
} )
|
||||
|
||||
WireLib.CreateSpecialInputs( self, { "PlayNote" }, { "ARRAY" }, {
|
||||
[[Changing this input will play a note.
|
||||
The array should contain:
|
||||
[1] Note number (1-127)
|
||||
[2] Note velocity (1-127)
|
||||
[3] Instrument index (The number near each name on the instruments list)]]
|
||||
} )
|
||||
|
||||
self.reproduceQueue = {}
|
||||
self.transmitQueue = {}
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Use( ply )
|
||||
self:SetPlayer( ply )
|
||||
end
|
||||
|
||||
function ENT:SetPlayer( ply )
|
||||
if IsValid( self.Ply ) and not self.Ply:Alive() then
|
||||
self.Ply = nil
|
||||
end
|
||||
|
||||
if not IsValid( self.Ply ) and ply:Alive() then
|
||||
net.Start( "mkeyboard.set_current_keyboard", false )
|
||||
net.WriteEntity( self )
|
||||
net.Send( ply )
|
||||
|
||||
self.Ply = ply
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:RemovePlayer()
|
||||
if IsValid( self.Ply ) then
|
||||
net.Start( "mkeyboard.set_current_keyboard", false )
|
||||
net.WriteEntity( nil )
|
||||
net.Send( self.Ply )
|
||||
end
|
||||
|
||||
self.Ply = nil
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
self:NextThink( CurTime() )
|
||||
self:UpdateNotes()
|
||||
|
||||
if IsValid( self.Ply ) and (
|
||||
not self.Ply:Alive() or
|
||||
self.Ply:GetPos():DistToSqr( self:GetPos() ) > MAX_USE_DISTANCE
|
||||
) then
|
||||
self:RemovePlayer()
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
if not WireLib then
|
||||
function ENT:UpdateNotes() end
|
||||
function ENT:OnReceiveNotes() end
|
||||
return
|
||||
end
|
||||
|
||||
local function ValidateNumber( v, default, min, max )
|
||||
return math.Clamp( math.Round( tonumber( v ) or default ), min, max )
|
||||
end
|
||||
|
||||
function ENT:TriggerInput( name, value )
|
||||
if name ~= "PlayNote" then return end
|
||||
if not isnumber( value[1] ) then return end
|
||||
|
||||
local note = ValidateNumber( value[1], 0, 0, 127 )
|
||||
if note == 0 then return end
|
||||
|
||||
local velocity = ValidateNumber( value[2], 127, 1, 127 )
|
||||
local instrument = ValidateNumber( value[3], 1, 1, 127 ) -- Max. value is based on net.WriteUInt( 7 )
|
||||
|
||||
local queue = self.transmitQueue
|
||||
|
||||
-- Remember when we started putting notes
|
||||
-- on the queue, and when we should send them
|
||||
local t = SysTime()
|
||||
|
||||
if not self.queueTimer then
|
||||
self.queueTimer = t + 0.4
|
||||
self.queueStart = t
|
||||
end
|
||||
|
||||
-- Add notes to the queue unless the limit was reached
|
||||
local noteCount = #queue
|
||||
|
||||
if noteCount < MKeyboard.NET_MAX_NOTES then
|
||||
queue[noteCount + 1] = {
|
||||
note, velocity, instrument, t - self.queueStart
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
local SysTime = SysTime
|
||||
|
||||
function ENT:OnReceiveNotes( notes )
|
||||
local t = SysTime()
|
||||
local queue = self.reproduceQueue
|
||||
|
||||
for i, n in ipairs( notes ) do
|
||||
-- i * 0.01 to prevent overriding stuff already on the queue
|
||||
queue[t + n[4] + ( i * 0.01 )] = { n[1], n[2], n[3] }
|
||||
end
|
||||
end
|
||||
|
||||
local GetKeys = table.GetKeys
|
||||
|
||||
function ENT:UpdateNotes()
|
||||
local now = SysTime()
|
||||
|
||||
-- If the queued notes are ready to be sent...
|
||||
if self.queueTimer and now > self.queueTimer then
|
||||
MKeyboard.BroadcastNotes( self.transmitQueue, self, true )
|
||||
|
||||
table.Empty( self.transmitQueue )
|
||||
self.queueTimer = nil
|
||||
end
|
||||
|
||||
-- Trigger the wire outputs while taking the time offsets into account
|
||||
local queue = self.reproduceQueue
|
||||
local timestamps = GetKeys( queue )
|
||||
|
||||
for _, t in ipairs( timestamps ) do
|
||||
if now > t then
|
||||
local n = queue[t]
|
||||
WireLib.TriggerOutput( self, "NotePlayed", { n[1], n[2], n[3] } )
|
||||
queue[t] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
22
lua/entities/ent_musical_keyboard/shared.lua
Normal file
22
lua/entities/ent_musical_keyboard/shared.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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_anim"
|
||||
ENT.Type = "anim"
|
||||
|
||||
ENT.PrintName = "Musical Keyboard"
|
||||
ENT.Author = "StyledStrike"
|
||||
ENT.Contact = "StyledStrike#8032"
|
||||
ENT.Purpose = "Replacement for Playable Piano, with improvements"
|
||||
ENT.Instructions = "Press E to use the instrument, use the keyboard or a MIDI device (if available) to play."
|
||||
|
||||
ENT.Category = "Fun + Games"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
154
lua/entities/env_atmosphere.lua
Normal file
154
lua/entities/env_atmosphere.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Changes the weather for players near it.
|
||||
---------------------------------------------------------------------------]]
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS( "base_anim" )
|
||||
|
||||
ENT.PrintName = "SF Atmo-Sphere"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Changes the weather for players near it."
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = true
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = true
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
function ENT:Initialize()
|
||||
if SERVER then
|
||||
self:SetModel( "models/maxofs2d/hover_basic.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
self:SetUseType( ONOFF_USE )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
local weathers = {}
|
||||
if CLIENT then
|
||||
local s = language.GetPhrase("#none")
|
||||
weathers[string.upper(s[1]) .. string.sub(s, 2)] = "none"
|
||||
else
|
||||
weathers["None"] = "one"
|
||||
end
|
||||
for _, str in ipairs( StormFox2.Weather.GetAll() ) do
|
||||
if str == "BlueMoon" then continue end -- Shhh
|
||||
weathers[StormFox2.Weather.Get(str).Name] = str
|
||||
end
|
||||
self:NetworkVar( "String", 0, "WeatherName", { KeyName = "Weather", Edit = { type = "Combo", order = 1, values = weathers } } )
|
||||
self:NetworkVar( "Float", 0, "Percent", { KeyName = "Percent", Edit = { type = "Float", order = 2, min = 0, max = 1 } } )
|
||||
self:NetworkVar( "Float", 1, "Temperature", { KeyName = "Temperature(C)", Edit = { type = "Int", order = 3, min = -20, max = 30 } } )
|
||||
self:NetworkVar( "Int", 0, "Range", { KeyName = "Range", Edit = { type = "Int", order = 4, min = 250, max = 5000 } } )
|
||||
if SERVER then
|
||||
self:SetRange( 250 )
|
||||
self:SetPercent( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:CanProperty(_, str)
|
||||
if str == "skin" then return false
|
||||
elseif str == "drive" then return false
|
||||
elseif str == "collision" then return false
|
||||
elseif str == "persist" then return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:UpdateTransmitState()
|
||||
return TRANSMIT_ALWAYS
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Think()
|
||||
self:AddEFlags( EFL_FORCE_CHECK_TRANSMIT )
|
||||
end
|
||||
function ENT:SetWeather( str, amount, range, temp )
|
||||
self:SetWeatherName( str )
|
||||
self:SetPercent( amount )
|
||||
if range then
|
||||
self:SetRange( range )
|
||||
end
|
||||
if temp then
|
||||
self:SetTemperature( temp )
|
||||
end
|
||||
end
|
||||
else
|
||||
local function HasToolgun()
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if not wep or not IsValid(wep) then return false end
|
||||
if wep:GetClass() ~= "sf2_tool" then return false end
|
||||
return true
|
||||
end
|
||||
local hasTool = false
|
||||
local v1 = Vector(1,1,1)
|
||||
local col1, col2 = Color(255,0,0,55),Color(0,255,0,255)
|
||||
function ENT:Draw()
|
||||
local w,p = self:GetWeatherName(),self:GetPercent()
|
||||
local r = self:GetRange()
|
||||
local we = StormFox2.Weather.Get(w)
|
||||
if IsValid( we ) then
|
||||
local c = CurTime()
|
||||
local p = self:GetPos()
|
||||
local np = p + Vector(0,0,math.sin( 3 * c))
|
||||
local in_v = StormFox2.util.RenderPos():Distance( p ) < r
|
||||
self:SetRenderBounds( v1 * -r, v1 )
|
||||
self:SetRenderOrigin( np )
|
||||
render.MaterialOverrideByIndex(0,Material("stormfox2/entities/env_weatherball_on"))
|
||||
render.MaterialOverrideByIndex(1,Material("stormfox2/entities/env_weatherball_sphere"))
|
||||
self:DrawModel()
|
||||
render.MaterialOverrideByIndex()
|
||||
self:SetRenderOrigin( )
|
||||
-- (nTime, nTemp, nWind, bThunder,nFraction)
|
||||
local symbol = we.GetIcon( StormFox2.Time.Get(), self:GetTemperature() or StormFox2.Temperature.Get(), StormFox2.Wind.GetForce(), StormFox2.Thunder.IsThundering(), self:GetPercent() )
|
||||
render.SetMaterial( symbol )
|
||||
render.DrawSprite( np , 8, 8, color_white)
|
||||
self:SetRenderAngles( Angle(0,c * 40 % 360,0) )
|
||||
else
|
||||
self:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("Think", "StormFox2.Weather.EController", function()
|
||||
if not StormFox2 or StormFox2.Version < 2 then return end
|
||||
if not StormFox2.Weather or not StormFox2.Weather.RemoveLocal then return end
|
||||
hasTool = HasToolgun()
|
||||
local t = {}
|
||||
for _, ent in ipairs( ents.FindByClass("env_atmosphere") ) do
|
||||
local p = ent:GetPos()
|
||||
local r = ent:GetRange()
|
||||
local dis = StormFox2.util.RenderPos():Distance( p )
|
||||
local in_v = StormFox2.util.RenderPos():Distance( p ) < r
|
||||
if in_v and IsValid(StormFox2.Weather.Get(ent:GetWeatherName() or "")) then table.insert(t, {ent, dis}) end
|
||||
end
|
||||
if #t < 1 then
|
||||
StormFox2.Weather.RemoveLocal()
|
||||
return
|
||||
end
|
||||
table.sort(t,function(a,b) return a[2] < b[2] end)
|
||||
local ent = t[1][1]
|
||||
if ent:GetPercent() <= 0 then
|
||||
StormFox2.Weather.RemoveLocal()
|
||||
else
|
||||
StormFox2.Weather.SetLocal( ent:GetWeatherName(), ent:GetPercent(), 4, ent:GetTemperature())
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add("PreDrawHalos", "StormFox2.Atmosphere.Halo", function()
|
||||
if not hasTool then return end
|
||||
local d_tab = ents.FindByClass("env_atmosphere")
|
||||
halo.Add( d_tab, color_white, 2, 2, 1, true,true )
|
||||
end)
|
||||
end
|
||||
31
lua/entities/env_stormfox2_materials.lua
Normal file
31
lua/entities/env_stormfox2_materials.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
--[[
|
||||
| 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 Material List
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
ENT.Base = "base_point"
|
||||
|
||||
ENT.PrintName = "env_stormfox2_materials"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Holds default material-types for the map"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
--[[
|
||||
We handle the listing in the mapscanner instead, since we search for this type of entity, and generate the textree there.
|
||||
]]
|
||||
27
lua/entities/env_stormfox2_settings.lua
Normal file
27
lua/entities/env_stormfox2_settings.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| 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 Setting Entity
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
ENT.Base = "base_point"
|
||||
|
||||
ENT.PrintName = "env_stormfox2_settings"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Holds default settings for the map"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
16
lua/entities/gmod_contr_spawner/cl_init.lua
Normal file
16
lua/entities/gmod_contr_spawner/cl_init.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
include( "shared.lua" )
|
||||
|
||||
function ENT:Draw()
|
||||
self.BaseClass.Draw(self)
|
||||
self.Entity:DrawModel()
|
||||
end
|
||||
310
lua/entities/gmod_contr_spawner/init.lua
Normal file
310
lua/entities/gmod_contr_spawner/init.lua
Normal file
@@ -0,0 +1,310 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
Title: Adv. Dupe 2 Contraption Spawner
|
||||
|
||||
Desc: A mobile duplicator
|
||||
|
||||
Author: TB
|
||||
|
||||
Version: 1.0
|
||||
]]
|
||||
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
if(WireLib)then
|
||||
include( "entities/base_wire_entity.lua" )
|
||||
end
|
||||
|
||||
include( "shared.lua" )
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
self.Entity:SetMoveType( MOVETYPE_NONE )
|
||||
self.Entity:PhysicsInit( SOLID_VPHYSICS )
|
||||
self.Entity:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
self.Entity:DrawShadow( false )
|
||||
|
||||
local phys = self.Entity:GetPhysicsObject()
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
end
|
||||
|
||||
self.UndoList = {}
|
||||
self.Ghosts = {}
|
||||
|
||||
self.SpawnLastValue = 0
|
||||
self.UndoLastValue = 0
|
||||
|
||||
self.LastSpawnTime = 0
|
||||
|
||||
self.CurrentPropCount = 0
|
||||
|
||||
if WireLib then
|
||||
self.Inputs = Wire_CreateInputs(self.Entity, {"Spawn", "Undo"})
|
||||
self.Outputs = WireLib.CreateSpecialOutputs(self.Entity, {"Out"}, { "NORMAL" })
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*
|
||||
* Sets options for this spawner
|
||||
*-----------------------------------------------------------------------*/
|
||||
function ENT:SetOptions(ply, delay, undo_delay, key, undo_key, disgrav, disdrag, addvel, hideprops )
|
||||
|
||||
self.delay = delay
|
||||
self.undo_delay = undo_delay
|
||||
|
||||
--Key bindings
|
||||
self.key = key
|
||||
self.undo_key = undo_key
|
||||
|
||||
numpad.Remove( self.CreateKey )
|
||||
numpad.Remove( self.UndoKey )
|
||||
self.CreateKey = numpad.OnDown( ply, self.key, "ContrSpawnerCreate", self.Entity, true )
|
||||
self.UndoKey = numpad.OnDown( ply, self.undo_key, "ContrSpawnerUndo", self.Entity, true )
|
||||
self.DisableGravity = disgrav
|
||||
self.DisableDrag = disdrag
|
||||
self.AddVelocity = addvel
|
||||
self.HideProps = hideprops
|
||||
|
||||
self:ShowOutput()
|
||||
end
|
||||
|
||||
function ENT:UpdateOptions( options )
|
||||
self:SetOptions( options["delay"], options["undo_delay"], options["key"], options["undo_key"])
|
||||
end
|
||||
|
||||
|
||||
function ENT:AddGhosts()
|
||||
if self.HideProps then return end
|
||||
local moveable = self:GetPhysicsObject():IsMoveable()
|
||||
self:GetPhysicsObject():EnableMotion(false)
|
||||
local EntTable
|
||||
local GhostEntity
|
||||
local Offset = self.DupeAngle - self.EntAngle
|
||||
local Phys
|
||||
for EntIndex,v in pairs(self.EntityTable)do
|
||||
if(EntIndex!=self.HeadEnt)then
|
||||
if(self.EntityTable[EntIndex].Class=="gmod_contr_spawner")then self.EntityTable[EntIndex] = nil continue end
|
||||
EntTable = table.Copy(self.EntityTable[EntIndex])
|
||||
if(EntTable.BuildDupeInfo && EntTable.BuildDupeInfo.PhysicsObjects)then
|
||||
Phys = EntTable.BuildDupeInfo.PhysicsObjects[0]
|
||||
else
|
||||
if(!v.BuildDupeInfo)then v.BuildDupeInfo = {} end
|
||||
v.BuildDupeInfo.PhysicsObjects = table.Copy(v.PhysicsObjects)
|
||||
Phys = EntTable.PhysicsObjects[0]
|
||||
end
|
||||
|
||||
GhostEntity = nil
|
||||
|
||||
if(EntTable.Model==nil || !util.IsValidModel(EntTable.Model)) then EntTable.Model="models/error.mdl" end
|
||||
|
||||
if ( EntTable.Model:sub( 1, 1 ) == "*" ) then
|
||||
GhostEntity = ents.Create( "func_physbox" )
|
||||
else
|
||||
GhostEntity = ents.Create( "gmod_ghost" )
|
||||
end
|
||||
|
||||
// If there are too many entities we might not spawn..
|
||||
if ( !GhostEntity || GhostEntity == NULL ) then return end
|
||||
|
||||
duplicator.DoGeneric( GhostEntity, EntTable )
|
||||
|
||||
GhostEntity:Spawn()
|
||||
|
||||
GhostEntity:DrawShadow( false )
|
||||
GhostEntity:SetMoveType( MOVETYPE_NONE )
|
||||
GhostEntity:SetSolid( SOLID_VPHYSICS );
|
||||
GhostEntity:SetNotSolid( true )
|
||||
GhostEntity:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
GhostEntity:SetColor( Color(255, 255, 255, 150) )
|
||||
|
||||
GhostEntity:SetAngles(Phys.Angle)
|
||||
GhostEntity:SetPos(self:GetPos() + Phys.Pos - self.Offset)
|
||||
self:SetAngles(self.EntAngle)
|
||||
GhostEntity:SetParent( self )
|
||||
self:SetAngles(self.DupeAngle)
|
||||
self.Ghosts[EntIndex] = GhostEntity
|
||||
end
|
||||
end
|
||||
self:SetAngles(self.DupeAngle)
|
||||
self:GetPhysicsObject():EnableMotion(moveable)
|
||||
end
|
||||
|
||||
function ENT:GetCreationDelay() return self.delay end
|
||||
function ENT:GetDeletionDelay() return self.undo_delay end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo ) self.Entity:TakePhysicsDamage( dmginfo ) end
|
||||
|
||||
function ENT:SetDupeInfo( HeadEnt, EntityTable, ConstraintTable )
|
||||
self.HeadEnt = HeadEnt
|
||||
self.EntityTable = EntityTable
|
||||
self.ConstraintTable = ConstraintTable
|
||||
if(!self.DupeAngle)then self.DupeAngle = self:GetAngles() end
|
||||
if(!self.EntAngle)then self.EntAngle = EntityTable[HeadEnt].PhysicsObjects[0].Angle end
|
||||
if(!self.Offset)then self.Offset = self.EntityTable[HeadEnt].PhysicsObjects[0].Pos end
|
||||
|
||||
local headpos, headang = EntityTable[HeadEnt].PhysicsObjects[0].Pos, EntityTable[HeadEnt].PhysicsObjects[0].Angle
|
||||
for k, v in pairs(EntityTable) do
|
||||
for o, p in pairs(v.PhysicsObjects) do
|
||||
p.LPos, p.LAngle = WorldToLocal(p.Pos, p.Angle, headpos, headang)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function ENT:DoSpawn( ply )
|
||||
-- Explicitly allow spawning if no player is provided, but an invalid player gets denied. This can happen when a player leaves the server.
|
||||
if not (ply and ply:IsValid()) then return end
|
||||
|
||||
for k, v in pairs(self.EntityTable) do
|
||||
for o, p in pairs(v.PhysicsObjects) do
|
||||
p.Pos, p.Angle = self:LocalToWorld(p.LPos), self:LocalToWorldAngles(p.LAngle)
|
||||
end
|
||||
end
|
||||
|
||||
/*local AngleOffset = self.EntAngle
|
||||
AngleOffset = self:GetAngles() - AngleOffset
|
||||
local AngleOffset2 = Angle(0,0,0)
|
||||
//AngleOffset2.y = AngleOffset.y
|
||||
AngleOffset2:RotateAroundAxis(self:GetUp(), AngleOffset.y)
|
||||
AngleOffset2:RotateAroundAxis(self:GetRight(),AngleOffset.p)
|
||||
AngleOffset2:RotateAroundAxis(self:GetForward(),AngleOffset.r)*/
|
||||
|
||||
local Ents, Constrs = AdvDupe2.duplicator.Paste(ply, self.EntityTable, self.ConstraintTable, nil, nil, Vector(0,0,0), true)
|
||||
local i = #self.UndoList+1
|
||||
self.UndoList[i] = Ents
|
||||
|
||||
undo.Create("contraption_spawns")
|
||||
local phys
|
||||
for k,ent in pairs(Ents)do
|
||||
phys = ent:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:Wake()
|
||||
if(self.DisableGravity==1)then phys:EnableGravity(false) end
|
||||
if(self.DisableDrag==1)then phys:EnableDrag(false) end
|
||||
phys:EnableMotion(true)
|
||||
if(ent.SetForce)then ent.SetForce(ent, ent.force, ent.mul) end
|
||||
if(self.AddVelocity==1)then
|
||||
phys:SetVelocity( self:GetVelocity() )
|
||||
phys:AddAngleVelocity( self:GetPhysicsObject():GetAngleVelocity() )
|
||||
end
|
||||
end
|
||||
|
||||
undo.AddEntity(ent)
|
||||
end
|
||||
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
if(self.undo_delay>0)then
|
||||
timer.Simple(self.undo_delay, function()
|
||||
if(self.UndoList && self.UndoList[i])then
|
||||
for k,ent in pairs(self.UndoList[i]) do
|
||||
if(IsValid(ent)) then
|
||||
ent:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function ENT:DoUndo( ply )
|
||||
|
||||
if(!self.UndoList || #self.UndoList == 0)then return end
|
||||
|
||||
local entities = self.UndoList[ #self.UndoList ]
|
||||
self.UndoList[ #self.UndoList ] = nil
|
||||
for _,ent in pairs(entities) do
|
||||
if (IsValid(ent)) then
|
||||
ent:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:TriggerInput(iname, value)
|
||||
local ply = self:GetPlayer()
|
||||
|
||||
if(iname == "Spawn")then
|
||||
if ((value > 0) == self.SpawnLastValue) then return end
|
||||
self.SpawnLastValue = (value > 0)
|
||||
|
||||
if(self.SpawnLastValue)then
|
||||
local delay = self:GetCreationDelay()
|
||||
if (delay == 0) then self:DoSpawn( ply ) return end
|
||||
if(CurTime() < self.LastSpawnTime)then return end
|
||||
self:DoSpawn( ply )
|
||||
self.LastSpawnTime=CurTime()+delay
|
||||
end
|
||||
elseif (iname == "Undo") then
|
||||
// Same here
|
||||
if((value > 0) == self.UndoLastValue)then return end
|
||||
self.UndoLastValue = (value > 0)
|
||||
|
||||
if(self.UndoLastValue)then self:DoUndo(ply) end
|
||||
end
|
||||
end
|
||||
|
||||
local text2 = {"Enabled", "Disabled"}
|
||||
function ENT:ShowOutput()
|
||||
local text = "\nGravity: "
|
||||
if(self.DisableGravity==1)then text=text.."Enabled" else text=text.."Disabled" end
|
||||
text=text.."\nDrag: "
|
||||
if(self.DisableDrag==1)then text=text.."Enabled" else text=text.."Disabled" end
|
||||
text=text.."\nVelocity: "
|
||||
if(self.AddVelocity==1)then text=text.."Enabled" else text=text.."Disabled" end
|
||||
|
||||
self.Entity:SetOverlayText(
|
||||
"Spawn Delay: " .. tostring(self:GetCreationDelay()) ..
|
||||
"\nUndo Delay: ".. tostring(self:GetDeletionDelay()) ..
|
||||
text
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*
|
||||
* Handler for spawn keypad input
|
||||
*-----------------------------------------------------------------------*/
|
||||
function SpawnContrSpawner( ply, ent )
|
||||
|
||||
if (!ent || !ent:IsValid()) then return end
|
||||
|
||||
local delay = ent:GetTable():GetCreationDelay()
|
||||
|
||||
if(delay == 0) then
|
||||
ent:DoSpawn( ply )
|
||||
return
|
||||
end
|
||||
|
||||
if(CurTime() < ent.LastSpawnTime)then return end
|
||||
ent:DoSpawn( ply )
|
||||
ent.LastSpawnTime=CurTime()+delay
|
||||
end
|
||||
|
||||
/*-----------------------------------------------------------------------*
|
||||
* Handler for undo keypad input
|
||||
*-----------------------------------------------------------------------*/
|
||||
function UndoContrSpawner( ply, ent )
|
||||
if (!ent || !ent:IsValid()) then return end
|
||||
ent:DoUndo( ply, true )
|
||||
end
|
||||
|
||||
numpad.Register( "ContrSpawnerCreate", SpawnContrSpawner )
|
||||
numpad.Register( "ContrSpawnerUndo", UndoContrSpawner )
|
||||
20
lua/entities/gmod_contr_spawner/shared.lua
Normal file
20
lua/entities/gmod_contr_spawner/shared.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = WireLib and "base_wire_entity" or "base_gmodentity"
|
||||
ENT.PrintName = "Contraption Spawner"
|
||||
ENT.Author = "TB"
|
||||
ENT.Contact = ""
|
||||
ENT.Purpose = ""
|
||||
ENT.Instructions = ""
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
75
lua/entities/gmod_item_vehicle_fphysics_wheel.lua
Normal file
75
lua/entities/gmod_item_vehicle_fphysics_wheel.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
|
||||
ENT.PrintName = "Tires"
|
||||
ENT.Author = "Luna"
|
||||
ENT.Information = "Fixes FakePhysics Wheels"
|
||||
ENT.Category = "[LVS]"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
|
||||
if SERVER then
|
||||
function ENT:SpawnFunction( ply, tr, ClassName )
|
||||
if not tr.Hit then return end
|
||||
|
||||
local ent = ents.Create( ClassName )
|
||||
ent:SetPos( tr.HitPos + tr.HitNormal * 10 )
|
||||
ent:SetAngles( Angle(90,0,0) )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel( "models/props_vehicles/tire001c_car.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:PhysWake()
|
||||
end
|
||||
|
||||
function ENT:Fix( entity )
|
||||
if self.AlreadyUsed or not IsValid( entity ) then return end
|
||||
|
||||
if entity:GetClass() ~= "gmod_sent_vehicle_fphysics_wheel" then return end
|
||||
|
||||
local Damaged = entity:GetDamaged()
|
||||
|
||||
if not Damaged then return end
|
||||
|
||||
entity:FixTire()
|
||||
entity:EmitSound("npc/dog/dog_servo1.wav")
|
||||
|
||||
self.AlreadyUsed = true
|
||||
|
||||
SafeRemoveEntityDelayed( self, 0 )
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
self:Fix( data.HitEntity )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function ENT:Draw( flags )
|
||||
self:DrawModel( flags )
|
||||
end
|
||||
43
lua/entities/gmod_sent_vehicle_fphysics_attachment.lua
Normal file
43
lua/entities/gmod_sent_vehicle_fphysics_attachment.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
function ENT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self:SetNotSolid( true )
|
||||
self.DoNotDuplicate = true
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
function ENT:Draw( flags )
|
||||
self:DrawModel( flags )
|
||||
end
|
||||
|
||||
function ENT:DrawTranslucent( flags )
|
||||
self:DrawModel( flags )
|
||||
end
|
||||
end
|
||||
677
lua/entities/gmod_sent_vehicle_fphysics_base/cl_init.lua
Normal file
677
lua/entities/gmod_sent_vehicle_fphysics_base/cl_init.lua
Normal file
@@ -0,0 +1,677 @@
|
||||
--[[
|
||||
| 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_tiresounds.lua")
|
||||
|
||||
function ENT:LVSHudPaint( X, Y, ply )
|
||||
local Pos2D = {
|
||||
visible = true,
|
||||
x = ScrW() * 0.5,
|
||||
y = ScrH() * 0.5,
|
||||
}
|
||||
|
||||
self:LVSPaintHitMarker( Pos2D )
|
||||
end
|
||||
|
||||
function ENT:GetViewOverride()
|
||||
return self.customview or vector_origin
|
||||
end
|
||||
|
||||
function ENT:LVSCalcView( ply, pos, angles, fov, pod )
|
||||
if pod:GetNWBool( "simfphys_SpecialCam" ) then return end
|
||||
|
||||
local IsDriverSeat = ply == self:GetDriver()
|
||||
|
||||
if IsDriverSeat and ply:lvsMouseAim() then
|
||||
angles = ply:EyeAngles()
|
||||
end
|
||||
|
||||
self.ZoomFov = fov
|
||||
|
||||
local view_origin = pos
|
||||
|
||||
if not pod:GetThirdPersonMode() then
|
||||
local viewoverride = self:GetViewOverride()
|
||||
|
||||
local X = viewoverride.X
|
||||
local Y = viewoverride.Y
|
||||
local Z = viewoverride.Z
|
||||
|
||||
view_origin = view_origin + (IsDriverSeat and pod:GetForward() * X + pod:GetRight() * Y + pod:GetUp() * Z or pod:GetUp() * 5)
|
||||
end
|
||||
|
||||
if not IsDriverSeat then return LVS:CalcView( self, ply, view_origin, angles, fov, pod ) end
|
||||
|
||||
return LVS:CalcView( self, ply, view_origin, angles, fov, pod )
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self.SmoothRPM = 0
|
||||
self.OldDist = 0
|
||||
self.PitchOffset = 0
|
||||
self.OldActive = false
|
||||
self.OldGear = 0
|
||||
self.OldThrottle = 0
|
||||
self.FadeThrottle = 0
|
||||
self.SoundMode = 0
|
||||
|
||||
self.DamageSnd = CreateSound(self, "simulated_vehicles/engine_damaged.wav")
|
||||
|
||||
self.EngineSounds = {}
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
local T = CurTime()
|
||||
|
||||
local Active = self:GetActive()
|
||||
local Throttle = self:GetThrottle()
|
||||
local LimitRPM = self:GetLimitRPM()
|
||||
|
||||
self:ManageSounds( Active, Throttle, LimitRPM )
|
||||
|
||||
self.RunNext = self.RunNext or 0
|
||||
if self.RunNext < T then
|
||||
self:ManageEffects( Active, Throttle, LimitRPM )
|
||||
self:CalcFlasher()
|
||||
|
||||
self.RunNext = T + 0.06
|
||||
end
|
||||
|
||||
self:SetPoseParameters( T )
|
||||
|
||||
self:TireSoundThink()
|
||||
end
|
||||
|
||||
function ENT:CalcFlasher()
|
||||
self.Flasher = self.Flasher or 0
|
||||
|
||||
local flashspeed = self.turnsignals_damaged and 0.06 or 0.0375
|
||||
|
||||
self.Flasher = self.Flasher and self.Flasher + flashspeed or 0
|
||||
if self.Flasher >= 1 then
|
||||
self.Flasher = self.Flasher - 1
|
||||
end
|
||||
|
||||
self.flashnum = math.min( math.abs( math.cos( math.rad( self.Flasher * 360 ) ) ^ 2 * 1.5 ) , 1)
|
||||
|
||||
if not self.signal_left and not self.signal_right then return end
|
||||
|
||||
if LocalPlayer() == self:GetDriver() then
|
||||
local fl_snd = self.flashnum > 0.9
|
||||
|
||||
if fl_snd ~= self.fl_snd then
|
||||
self.fl_snd = fl_snd
|
||||
if fl_snd then
|
||||
self:EmitSound( "simulated_vehicles/sfx/flasher_on.ogg" )
|
||||
else
|
||||
self:EmitSound( "simulated_vehicles/sfx/flasher_off.ogg" )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetFlasher()
|
||||
self.flashnum = self.flashnum or 0
|
||||
return self.flashnum
|
||||
end
|
||||
|
||||
function ENT:SetPoseParameters( curtime )
|
||||
self.sm_vSteer = self.sm_vSteer and self.sm_vSteer + (self:GetVehicleSteer() - self.sm_vSteer) * 0.3 or 0
|
||||
self:SetPoseParameter("vehicle_steer", self.sm_vSteer )
|
||||
|
||||
if not istable( self.pp_data ) then
|
||||
self.ppNextCheck = self.ppNextCheck or curtime + 0.5
|
||||
if self.ppNextCheck < curtime then
|
||||
self.ppNextCheck = curtime + 0.5
|
||||
|
||||
net.Start("simfphys_request_ppdata",true)
|
||||
net.WriteEntity( self )
|
||||
net.SendToServer()
|
||||
end
|
||||
else
|
||||
if not self.CustomWheels then
|
||||
for i = 1, table.Count( self.pp_data ) do
|
||||
local Wheel = self.pp_data[i].entity
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local addPos = Wheel:GetDamaged() and self.pp_data[i].dradius or 0
|
||||
|
||||
local Pose = (self.pp_data[i].pos - self:WorldToLocal( Wheel:GetPos()).z + addPos ) / self.pp_data[i].travel
|
||||
self:SetPoseParameter( self.pp_data[i].name, Pose )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:InvalidateBoneCache()
|
||||
end
|
||||
|
||||
function ENT:GetEnginePos()
|
||||
if isvector( self.EnginePos ) then return self:LocalToWorld( self.EnginePos ) end
|
||||
|
||||
local Attachment = self:GetAttachment( self:LookupAttachment( "vehicle_engine" ) )
|
||||
|
||||
if Attachment then return Attachment.Pos end
|
||||
|
||||
return self:GetPos()
|
||||
end
|
||||
|
||||
function ENT:GetRPM()
|
||||
local RPM = self.SmoothRPM and self.SmoothRPM or 0
|
||||
return RPM
|
||||
end
|
||||
|
||||
function ENT:DamageEffects()
|
||||
local Pos = self:GetEnginePos()
|
||||
local Scale = self:GetCurHealth() / self:GetMaxHealth()
|
||||
local smoke = self:OnSmoke() and Scale <= 0.5
|
||||
local fire = self:OnFire()
|
||||
|
||||
if self.wasSmoke ~= smoke then
|
||||
self.wasSmoke = smoke
|
||||
if smoke then
|
||||
self.smokesnd = CreateSound(self, "ambient/gas/steam2.wav")
|
||||
self.smokesnd:PlayEx(0.2,90)
|
||||
else
|
||||
if self.smokesnd then
|
||||
self.smokesnd:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.wasFire ~= fire then
|
||||
self.wasFire = fire
|
||||
if fire then
|
||||
self:EmitSound( "ambient/fire/mtov_flame2.wav" )
|
||||
|
||||
self.firesnd = CreateSound(self, "ambient/fire/fire_small1.wav")
|
||||
self.firesnd:Play()
|
||||
else
|
||||
if self.firesnd then
|
||||
self.firesnd:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if smoke then
|
||||
if Scale <= 0.5 then
|
||||
local HP = self:GetCurHealth()
|
||||
local MaxHP = self:GetMaxHealth()
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetMagnitude( math.max(HP - MaxHP * 0.25,0) / (MaxHP * 0.25) )
|
||||
util.Effect( "simfphys_engine_smoke", effectdata )
|
||||
end
|
||||
end
|
||||
|
||||
if fire then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_engine_fire", effectdata )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ManageEffects( Active, fThrottle, LimitRPM )
|
||||
self:DamageEffects()
|
||||
|
||||
Active = Active and (self:GetFlyWheelRPM() ~= 0)
|
||||
if not Active then return end
|
||||
if not self.ExhaustPositions then return end
|
||||
|
||||
local Scale = fThrottle * (0.2 + math.min(self:GetRPM() / LimitRPM,1) * 0.8) ^ 2
|
||||
|
||||
for i = 1, table.Count( self.ExhaustPositions ) do
|
||||
if self.ExhaustPositions[i].OnBodyGroups then
|
||||
if self:BodyGroupIsValid( self.ExhaustPositions[i].OnBodyGroups ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.ExhaustPositions[i].pos )
|
||||
effectdata:SetAngles( self.ExhaustPositions[i].ang )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_exhaust", effectdata )
|
||||
end
|
||||
else
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self.ExhaustPositions[i].pos )
|
||||
effectdata:SetAngles( self.ExhaustPositions[i].ang )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetEntity( self )
|
||||
util.Effect( "simfphys_exhaust", effectdata )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ManageSounds( Active, fThrottle, LimitRPM )
|
||||
local EngineVolume = LVS.EngineVolume
|
||||
|
||||
local FlyWheelRPM = self:GetFlyWheelRPM()
|
||||
local Active = Active and (FlyWheelRPM ~= 0)
|
||||
local IdleRPM = self:GetIdleRPM()
|
||||
|
||||
local IsCruise = self:GetIsCruiseModeOn()
|
||||
|
||||
local CurDist = (LocalPlayer():GetPos() - self:GetPos()):Length()
|
||||
local Throttle = IsCruise and math.Clamp(self:GetThrottle() ^ 3,0.01,0.7) or fThrottle
|
||||
local Gear = self:GetGear()
|
||||
local Clutch = self:GetClutch()
|
||||
local FadeRPM = LimitRPM * 0.5
|
||||
|
||||
local FT = FrameTime()
|
||||
local Rate = 3.33 * FT
|
||||
|
||||
self.FadeThrottle = self.FadeThrottle + math.Clamp(Throttle - self.FadeThrottle,-Rate,Rate)
|
||||
self.PitchOffset = self.PitchOffset + ((CurDist - self.OldDist) * 0.23 - self.PitchOffset) * 0.5
|
||||
self.OldDist = CurDist
|
||||
self.SmoothRPM = self.SmoothRPM + math.Clamp(FlyWheelRPM - self.SmoothRPM,-0.972 * FT * LimitRPM,1.66 * FT * LimitRPM)
|
||||
|
||||
self.OldThrottle2 = self.OldThrottle2 or 0
|
||||
if Throttle ~= self.OldThrottle2 then
|
||||
self.OldThrottle2 = Throttle
|
||||
if Throttle == 0 then
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
self:Backfire()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetRevlimiter() and LimitRPM > 2500 then
|
||||
if (self.SmoothRPM >= LimitRPM - 200) and self.FadeThrottle > 0 then
|
||||
self.SmoothRPM = self.SmoothRPM - 0.2 * LimitRPM
|
||||
self.FadeThrottle = 0.2
|
||||
self:Backfire()
|
||||
end
|
||||
end
|
||||
|
||||
if Active ~= self.OldActive then
|
||||
local preset = self:GetEngineSoundPreset()
|
||||
local UseGearResetter = self:SetSoundPreset( preset )
|
||||
|
||||
self.SoundMode = UseGearResetter and 2 or 1
|
||||
|
||||
self.OldActive = Active
|
||||
|
||||
if Active then
|
||||
local MaxHealth = self:GetMaxHealth()
|
||||
local Health = self:GetCurHealth()
|
||||
|
||||
if Health <= (MaxHealth * 0.6) then
|
||||
self.DamageSnd:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if self.SoundMode == 2 then
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "HighRPM" ] )
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "LowRPM" ])
|
||||
self.Idle = CreateSound(self, self.EngineSounds[ "Idle" ])
|
||||
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
self.Idle:PlayEx(0,0)
|
||||
else
|
||||
local IdleSound = self.EngineSounds[ "IdleSound" ]
|
||||
local LowSound = self.EngineSounds[ "LowSound" ]
|
||||
local HighSound = self.EngineSounds[ "HighSound" ]
|
||||
local ThrottleSound = self.EngineSounds[ "ThrottleSound" ]
|
||||
|
||||
if IdleSound then
|
||||
self.Idle = CreateSound(self, IdleSound)
|
||||
self.Idle:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if LowSound then
|
||||
self.LowRPM = CreateSound(self, LowSound)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if HighSound then
|
||||
self.HighRPM = CreateSound(self, HighSound)
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
end
|
||||
|
||||
if ThrottleSound then
|
||||
self.Valves = CreateSound(self, ThrottleSound)
|
||||
self.Valves:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:SaveStopSounds()
|
||||
end
|
||||
end
|
||||
|
||||
if Active then
|
||||
local Volume = 0.25 + 0.25 * ((self.SmoothRPM / LimitRPM) ^ 1.5) + self.FadeThrottle * 0.5
|
||||
local Pitch = math.Clamp( (20 + self.SmoothRPM / 50 - self.PitchOffset) * self.PitchMulAll,0,255)
|
||||
|
||||
if self.DamageSnd then
|
||||
self.DamageSnd:ChangeVolume( ((self.SmoothRPM / LimitRPM) * 0.6 ^ 1.5) * EngineVolume )
|
||||
self.DamageSnd:ChangePitch( 100 )
|
||||
end
|
||||
|
||||
if self.SoundMode == 2 then
|
||||
if self.FadeThrottle ~= self.OldThrottle then
|
||||
self.OldThrottle = self.FadeThrottle
|
||||
if self.FadeThrottle == 0 and Clutch == 0 then
|
||||
if self.SmoothRPM >= FadeRPM then
|
||||
if IsCruise ~= true then
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "RevDown" ] )
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Gear ~= self.OldGear then
|
||||
if self.SmoothRPM >= FadeRPM and Gear > 3 then
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear < Gear then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftUpToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
if math.random(0,4) >= 3 then
|
||||
timer.Simple(0.4, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:Backfire()
|
||||
end)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.FadeThrottle > 0 then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftDownToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear > Gear and self.FadeThrottle > 0 and Gear >= 3 then
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "ShiftDownToHigh" ] )
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
else
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
|
||||
self.HighRPM = CreateSound(self, self.EngineSounds[ "HighRPM" ] )
|
||||
self.LowRPM = CreateSound(self, self.EngineSounds[ "LowRPM" ])
|
||||
self.HighRPM:PlayEx(0,0)
|
||||
self.LowRPM:PlayEx(0,0)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.OldGear = Gear
|
||||
end
|
||||
|
||||
self.Idle:ChangeVolume( math.Clamp( math.min((self.SmoothRPM / IdleRPM) * 3,1.5 + self.FadeThrottle * 0.5) * 0.7 - self.SmoothRPM / 2000 ,0,1) * EngineVolume )
|
||||
self.Idle:ChangePitch( math.Clamp( Pitch * 3,0,255) )
|
||||
|
||||
self.LowRPM:ChangeVolume( math.Clamp(Volume - (self.SmoothRPM - 2000) / 2000 * self.FadeThrottle,0,1) * EngineVolume )
|
||||
self.LowRPM:ChangePitch( math.Clamp( Pitch * self.PitchMulLow,0,255) )
|
||||
|
||||
local hivol = math.max((self.SmoothRPM - 2000) / 2000,0) * Volume
|
||||
self.HighRPM:ChangeVolume( (self.FadeThrottle < 0.4 and hivol * self.FadeThrottle or hivol * self.FadeThrottle * 2.5) * EngineVolume )
|
||||
self.HighRPM:ChangePitch( math.Clamp( Pitch * self.PitchMulHigh,0,255) )
|
||||
else
|
||||
if Gear ~= self.OldGear then
|
||||
if self.SmoothRPM >= FadeRPM and Gear > 3 then
|
||||
if Clutch ~= 1 then
|
||||
if self.OldGear < Gear then
|
||||
if self.SmoothRPM > LimitRPM * 0.6 then
|
||||
if math.random(0,4) >= 3 then
|
||||
timer.Simple(0.4, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:Backfire()
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.OldGear = Gear
|
||||
end
|
||||
|
||||
|
||||
local IdlePitch = self.Idle_PitchMul
|
||||
self.Idle:ChangeVolume( math.Clamp( math.min((self.SmoothRPM / IdleRPM) * 3,1.5 + self.FadeThrottle * 0.5) * 0.7 - self.SmoothRPM / 2000,0,1) * EngineVolume )
|
||||
self.Idle:ChangePitch( math.Clamp( Pitch * 3 * IdlePitch,0,255) )
|
||||
|
||||
local LowPitch = self.Mid_PitchMul
|
||||
local LowVolume = self.Mid_VolumeMul
|
||||
local LowFadeOutRPM = LimitRPM * (self.Mid_FadeOutRPMpercent / 100)
|
||||
local LowFadeOutRate = LimitRPM * self.Mid_FadeOutRate
|
||||
self.LowRPM:ChangeVolume( math.Clamp( (Volume - math.Clamp((self.SmoothRPM - LowFadeOutRPM) / LowFadeOutRate,0,1)) * LowVolume,0,1) * EngineVolume )
|
||||
self.LowRPM:ChangePitch( math.Clamp(Pitch * LowPitch,0,255) )
|
||||
|
||||
local HighPitch = self.High_PitchMul
|
||||
local HighVolume = self.High_VolumeMul
|
||||
local HighFadeInRPM = LimitRPM * (self.High_FadeInRPMpercent / 100)
|
||||
local HighFadeInRate = LimitRPM * self.High_FadeInRate
|
||||
self.HighRPM:ChangeVolume( math.Clamp( math.Clamp((self.SmoothRPM - HighFadeInRPM) / HighFadeInRate,0,Volume) * HighVolume,0,1) * EngineVolume)
|
||||
self.HighRPM:ChangePitch( math.Clamp(Pitch * HighPitch,0,255) )
|
||||
|
||||
local ThrottlePitch = self.Throttle_PitchMul
|
||||
local ThrottleVolume = self.Throttle_VolumeMul
|
||||
self.Valves:ChangeVolume( math.Clamp((self.SmoothRPM - 2000) / 2000,0,Volume) * (0.2 + 0.15 * self.FadeThrottle) * ThrottleVolume * EngineVolume )
|
||||
self.Valves:ChangePitch( math.Clamp(Pitch * ThrottlePitch,0,255) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Backfire( damaged )
|
||||
if not self:GetBackFire() and not damaged then return end
|
||||
|
||||
if not self.ExhaustPositions then return end
|
||||
|
||||
local expos = self.ExhaustPositions
|
||||
|
||||
for i = 1, table.Count( expos ) do
|
||||
if math.random(1,3) >= 2 or damaged then
|
||||
local Pos = expos[i].pos
|
||||
local Ang = expos[i].ang - Angle(90,0,0)
|
||||
|
||||
if expos[i].OnBodyGroups then
|
||||
if self:BodyGroupIsValid( expos[i].OnBodyGroups ) then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetAngles( Ang )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetFlags( damaged and 1 or 0 )
|
||||
util.Effect( "simfphys_backfire", effectdata )
|
||||
end
|
||||
else
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetAngles( Ang )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetFlags( damaged and 1 or 0 )
|
||||
util.Effect( "simfphys_backfire", effectdata )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SetSoundPreset(index)
|
||||
if index == -1 then
|
||||
local soundoverride = self:GetSoundoverride()
|
||||
local data = string.Explode( ",", soundoverride)
|
||||
|
||||
if soundoverride ~= "" and data[1] == "1" then
|
||||
|
||||
self.EngineSounds[ "Idle" ] = data[4]
|
||||
self.EngineSounds[ "LowRPM" ] = data[6]
|
||||
self.EngineSounds[ "HighRPM" ] = data[2]
|
||||
self.EngineSounds[ "RevDown" ] = data[8]
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = data[10]
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = data[9]
|
||||
|
||||
self.PitchMulLow = data[7]
|
||||
self.PitchMulHigh = data[3]
|
||||
self.PitchMulAll = data[5]
|
||||
else
|
||||
local idle = self.snd_idle or ""
|
||||
local low = self.snd_low or ""
|
||||
local mid = self.snd_mid or ""
|
||||
local revdown = self.snd_low_revdown or ""
|
||||
local gearup = self.snd_mid_gearup or ""
|
||||
local geardown = self.snd_mid_geardown or ""
|
||||
|
||||
self.EngineSounds[ "Idle" ] = idle ~= "" and idle or false
|
||||
self.EngineSounds[ "LowRPM" ] = low ~= "" and low or false
|
||||
self.EngineSounds[ "HighRPM" ] = mid ~= "" and mid or false
|
||||
self.EngineSounds[ "RevDown" ] = revdown ~= "" and revdown or low
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = gearup ~= "" and gearup or mid
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = geardown ~= "" and geardown or gearup
|
||||
|
||||
self.PitchMulLow = self.snd_low_pitch or 1
|
||||
self.PitchMulHigh = self.snd_mid_pitch or 1
|
||||
self.PitchMulAll = self.snd_pitch or 1
|
||||
end
|
||||
|
||||
if self.EngineSounds[ "Idle" ] ~= false and self.EngineSounds[ "LowRPM" ] ~= false and self.EngineSounds[ "HighRPM" ] ~= false then
|
||||
return true
|
||||
else
|
||||
self:SetSoundPreset( 0 )
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if index == 0 then
|
||||
local soundoverride = self:GetSoundoverride()
|
||||
local data = string.Explode( ",", soundoverride)
|
||||
|
||||
if soundoverride ~= "" and data[1] ~= "1" then
|
||||
self.EngineSounds[ "IdleSound" ] = data[1]
|
||||
self.Idle_PitchMul = data[2]
|
||||
|
||||
self.EngineSounds[ "LowSound" ] = data[3]
|
||||
self.Mid_PitchMul = data[4]
|
||||
self.Mid_VolumeMul = data[5]
|
||||
self.Mid_FadeOutRPMpercent = data[6]
|
||||
self.Mid_FadeOutRate = data[7]
|
||||
|
||||
self.EngineSounds[ "HighSound" ] = data[8]
|
||||
self.High_PitchMul = data[9]
|
||||
self.High_VolumeMul = data[10]
|
||||
self.High_FadeInRPMpercent = data[11]
|
||||
self.High_FadeInRate = data[12]
|
||||
|
||||
self.EngineSounds[ "ThrottleSound" ] = data[13]
|
||||
self.Throttle_PitchMul = data[14]
|
||||
self.Throttle_VolumeMul = data[15]
|
||||
else
|
||||
self.EngineSounds[ "IdleSound" ] = self.Sound_Idle or "simulated_vehicles/misc/e49_idle.wav"
|
||||
self.Idle_PitchMul = self.Sound_IdlePitch or 1
|
||||
|
||||
self.EngineSounds[ "LowSound" ] = self.Sound_Mid or "simulated_vehicles/misc/gto_onlow.wav"
|
||||
self.Mid_PitchMul = self.Sound_MidPitch or 1
|
||||
self.Mid_VolumeMul = self.Sound_MidVolume or 0.75
|
||||
self.Mid_FadeOutRPMpercent = self.Sound_MidFadeOutRPMpercent or 68
|
||||
self.Mid_FadeOutRate = self.Sound_MidFadeOutRate or 0.4
|
||||
|
||||
self.EngineSounds[ "HighSound" ] = self.Sound_High or "simulated_vehicles/misc/nv2_onlow_ex.wav"
|
||||
self.High_PitchMul = self.Sound_HighPitch or 1
|
||||
self.High_VolumeMul = self.Sound_HighVolume or 1
|
||||
self.High_FadeInRPMpercent = self.Sound_HighFadeInRPMpercent or 26.6
|
||||
self.High_FadeInRate = self.Sound_HighFadeInRate or 0.266
|
||||
|
||||
self.EngineSounds[ "ThrottleSound" ] = self.Sound_Throttle or "simulated_vehicles/valve_noise.wav"
|
||||
self.Throttle_PitchMul = self.Sound_ThrottlePitch or 0.65
|
||||
self.Throttle_VolumeMul = self.Sound_ThrottleVolume or 1
|
||||
end
|
||||
|
||||
self.PitchMulLow = 1
|
||||
self.PitchMulHigh = 1
|
||||
self.PitchMulAll = 1
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if index > 0 then
|
||||
local clampindex = math.Clamp(index,1,table.Count(simfphys.SoundPresets))
|
||||
self.EngineSounds[ "Idle" ] = simfphys.SoundPresets[clampindex][1]
|
||||
self.EngineSounds[ "LowRPM" ] = simfphys.SoundPresets[clampindex][2]
|
||||
self.EngineSounds[ "HighRPM" ] = simfphys.SoundPresets[clampindex][3]
|
||||
self.EngineSounds[ "RevDown" ] = simfphys.SoundPresets[clampindex][4]
|
||||
self.EngineSounds[ "ShiftUpToHigh" ] = simfphys.SoundPresets[clampindex][5]
|
||||
self.EngineSounds[ "ShiftDownToHigh" ] = simfphys.SoundPresets[clampindex][6]
|
||||
|
||||
self.PitchMulLow = simfphys.SoundPresets[clampindex][7]
|
||||
self.PitchMulHigh = simfphys.SoundPresets[clampindex][8]
|
||||
self.PitchMulAll = simfphys.SoundPresets[clampindex][9]
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:GetVehicleInfo()
|
||||
return self.VehicleInfo
|
||||
end
|
||||
|
||||
function ENT:SaveStopSounds()
|
||||
if self.HighRPM then
|
||||
self.HighRPM:Stop()
|
||||
end
|
||||
|
||||
if self.LowRPM then
|
||||
self.LowRPM:Stop()
|
||||
end
|
||||
|
||||
if self.Idle then
|
||||
self.Idle:Stop()
|
||||
end
|
||||
|
||||
if self.Valves then
|
||||
self.Valves:Stop()
|
||||
end
|
||||
|
||||
if self.DamageSnd then
|
||||
self.DamageSnd:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:StopFireSound()
|
||||
if self.smokesnd then
|
||||
self.smokesnd:Stop()
|
||||
end
|
||||
|
||||
if self.firesnd then
|
||||
self.firesnd:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:SaveStopSounds()
|
||||
self:StopFireSound()
|
||||
self:TireSoundRemove()
|
||||
end
|
||||
@@ -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/
|
||||
--]]
|
||||
|
||||
|
||||
ENT.TireSoundFade = 0.15
|
||||
ENT.TireSoundTypes = {
|
||||
["roll"] = "simulated_vehicles/sfx/wheel_roll.wav",
|
||||
["roll_dirt"] = "simulated_vehicles/sfx/wheel_roll_dirt.wav",
|
||||
["roll_wet"] = "simulated_vehicles/sfx/wheel_roll_wet.wav",
|
||||
["roll_damaged"] = "simulated_vehicles/sfx/tire_damaged.wav",
|
||||
["skid"] = "simulated_vehicles/sfx/wheel_skid.wav",
|
||||
["skid_dirt"] = "simulated_vehicles/sfx/wheel_skid_dirt.wav",
|
||||
["skid_wet"] = "simulated_vehicles/sfx/wheel_skid_wet.wav",
|
||||
}
|
||||
ENT.TireSoundLevelSkid = 85
|
||||
ENT.TireSoundLevelRoll = 75
|
||||
|
||||
function ENT:TireSoundRemove()
|
||||
for snd, _ in pairs( self.TireSoundTypes ) do
|
||||
self:StopTireSound( snd )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:TireSoundThink()
|
||||
for snd, _ in pairs( self.TireSoundTypes ) do
|
||||
local T = self:GetTireSoundTime( snd )
|
||||
|
||||
if T > 0 then
|
||||
local speed = self:GetVelocity():Length()
|
||||
|
||||
local sound = self:StartTireSound( snd )
|
||||
|
||||
if string.StartsWith( snd, "skid" ) then
|
||||
local vel = speed
|
||||
speed = math.max( math.abs( self:GetWheelVelocity() ) - vel, 0 ) * 5 + vel
|
||||
end
|
||||
|
||||
local volume = math.min(speed / 1000,1) ^ 2 * T
|
||||
local pitch = 100 + math.Clamp((speed - 400) / 200,0,155)
|
||||
|
||||
sound:ChangeVolume( volume, 0 )
|
||||
sound:ChangePitch( pitch, 0.5 )
|
||||
else
|
||||
self:StopTireSound( snd )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:DoTireSound( snd )
|
||||
if not istable( self._TireSounds ) then
|
||||
self._TireSounds = {}
|
||||
end
|
||||
|
||||
self._TireSounds[ snd ] = CurTime() + self.TireSoundFade
|
||||
end
|
||||
|
||||
function ENT:GetTireSoundTime( snd )
|
||||
if not istable( self._TireSounds ) or not self._TireSounds[ snd ] then return 0 end
|
||||
|
||||
return math.max(self._TireSounds[ snd ] - CurTime(),0) / self.TireSoundFade
|
||||
end
|
||||
|
||||
function ENT:StartTireSound( snd )
|
||||
if not self.TireSoundTypes[ snd ] or not istable( self._ActiveTireSounds ) then
|
||||
self._ActiveTireSounds = {}
|
||||
end
|
||||
|
||||
if self._ActiveTireSounds[ snd ] then return self._ActiveTireSounds[ snd ] end
|
||||
|
||||
local sound = CreateSound( self, self.TireSoundTypes[ snd ] )
|
||||
sound:SetSoundLevel( string.StartsWith( snd, "skid" ) and self.TireSoundLevelSkid or self.TireSoundLevelRoll )
|
||||
sound:PlayEx(0,100)
|
||||
|
||||
self._ActiveTireSounds[ snd ] = sound
|
||||
|
||||
return sound
|
||||
end
|
||||
|
||||
function ENT:StopTireSound( snd )
|
||||
if not istable( self._ActiveTireSounds ) or not self._ActiveTireSounds[ snd ] then return end
|
||||
|
||||
self._ActiveTireSounds[ snd ]:Stop()
|
||||
self._ActiveTireSounds[ snd ] = nil
|
||||
end
|
||||
314
lua/entities/gmod_sent_vehicle_fphysics_base/damage.lua
Normal file
314
lua/entities/gmod_sent_vehicle_fphysics_base/damage.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
| 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.DSArmorDamageReduction = 1
|
||||
ENT.DSArmorDamageReductionType = DMG_GENERIC
|
||||
|
||||
ENT.DSArmorIgnoreDamageType = DMG_GENERIC
|
||||
|
||||
function ENT:ApplyDamage( damage, type )
|
||||
if type == DMG_BLAST then
|
||||
damage = damage * 10
|
||||
end
|
||||
|
||||
if type == DMG_BULLET then
|
||||
damage = damage * 2
|
||||
end
|
||||
|
||||
local MaxHealth = self:GetMaxHealth()
|
||||
local CurHealth = self:GetCurHealth()
|
||||
|
||||
local NewHealth = math.max( math.Round(CurHealth - damage,0) , 0 )
|
||||
|
||||
if NewHealth <= (MaxHealth * 0.6) then
|
||||
if NewHealth <= (MaxHealth * 0.3) then
|
||||
self:SetOnFire( true )
|
||||
self:SetOnSmoke( false )
|
||||
else
|
||||
self:SetOnSmoke( true )
|
||||
end
|
||||
end
|
||||
|
||||
if MaxHealth > 30 and NewHealth <= 31 then
|
||||
if self:EngineActive() then
|
||||
self:DamagedStall()
|
||||
end
|
||||
end
|
||||
|
||||
if NewHealth <= 0 then
|
||||
|
||||
self:ExplodeVehicle()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:SetCurHealth( NewHealth )
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
if not self:IsInitialized() then return end
|
||||
|
||||
if dmginfo:IsDamageType( self.DSArmorIgnoreDamageType ) then return end
|
||||
|
||||
if dmginfo:IsDamageType( self.DSArmorDamageReductionType ) then
|
||||
if dmginfo:GetDamage() ~= 0 then
|
||||
dmginfo:ScaleDamage( self.DSArmorDamageReduction )
|
||||
|
||||
dmginfo:SetDamage( math.max(dmginfo:GetDamage(),1) )
|
||||
end
|
||||
end
|
||||
|
||||
if dmginfo:IsDamageType( DMG_BLAST ) then
|
||||
local Inflictor = dmginfo:GetInflictor()
|
||||
|
||||
if IsValid( Inflictor ) and isfunction( Inflictor.GetEntityFilter ) then
|
||||
for ents, _ in pairs( Inflictor:GetEntityFilter() ) do
|
||||
if ents == self then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dmgPartsTableOK = true
|
||||
|
||||
if istable( self._dmgParts ) then
|
||||
for _, part in pairs( self._dmgParts ) do
|
||||
if isvector( part.mins ) and isvector( part.maxs ) and isvector( part.pos ) and isangle( part.ang ) then continue end
|
||||
|
||||
dmgPartsTableOK = false
|
||||
|
||||
break
|
||||
end
|
||||
else
|
||||
dmgPartsTableOK = false
|
||||
end
|
||||
|
||||
local CriticalHit = false
|
||||
|
||||
if dmgPartsTableOK then
|
||||
CriticalHit = self:CalcComponentDamage( dmginfo )
|
||||
else
|
||||
print("[LVS] - "..self:GetSpawn_List().." is doing something it shouldn't! DS part has been detected but was registered incorrectly!")
|
||||
end
|
||||
|
||||
if hook.Run( "simfphysOnTakeDamage", self, dmginfo ) then return end
|
||||
|
||||
local Damage = dmginfo:GetDamage()
|
||||
local DamagePos = dmginfo:GetDamagePosition()
|
||||
local Type = dmginfo:GetDamageType()
|
||||
local Driver = self:GetDriver()
|
||||
|
||||
self.LastAttacker = dmginfo:GetAttacker()
|
||||
self.LastInflictor = dmginfo:GetInflictor()
|
||||
|
||||
if simfphys.DamageEnabled then
|
||||
net.Start( "simfphys_spritedamage" )
|
||||
net.WriteEntity( self )
|
||||
net.WriteVector( self:WorldToLocal( DamagePos ) )
|
||||
net.WriteBool( false )
|
||||
net.Broadcast()
|
||||
|
||||
if Type == DMG_AIRBOAT then
|
||||
Type = DMG_DIRECT
|
||||
Damage = Damage * 6
|
||||
end
|
||||
|
||||
local oldHP = self:GetCurHealth()
|
||||
|
||||
self:ApplyDamage( Damage, Type )
|
||||
|
||||
local newHP = self:GetCurHealth()
|
||||
|
||||
if oldHP ~= newHP then
|
||||
local IsFireDamage = dmginfo:IsDamageType( DMG_BURN )
|
||||
|
||||
if IsValid( self.LastAttacker ) and self.LastAttacker:IsPlayer() and not IsFireDamage then
|
||||
net.Start( "lvs_hitmarker" )
|
||||
net.WriteBool( CriticalHit )
|
||||
net.Send( self.LastAttacker )
|
||||
end
|
||||
|
||||
if Damage > 1 and not IsFireDamage then
|
||||
net.Start( "lvs_hurtmarker" )
|
||||
net.WriteFloat( math.min( Damage / 50, 1 ) )
|
||||
net.Send( self:GetEveryone() )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ExplodeVehicle()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
if self.destroyed then return end
|
||||
|
||||
self.destroyed = true
|
||||
|
||||
local Attacker = self.LastAttacker
|
||||
|
||||
if IsValid( Attacker ) and Attacker:IsPlayer() then
|
||||
net.Start( "lvs_killmarker" )
|
||||
net.Send( Attacker )
|
||||
end
|
||||
|
||||
local GibMDL = self.GibModels
|
||||
self.GibModels = nil
|
||||
|
||||
self:OnFinishExplosion()
|
||||
|
||||
self.GibModels = GibMDL
|
||||
GibMDL = nil
|
||||
|
||||
local ply = self.EntityOwner
|
||||
local skin = self:GetSkin()
|
||||
local Col = self:GetColor()
|
||||
Col.r = Col.r * 0.8
|
||||
Col.g = Col.g * 0.8
|
||||
Col.b = Col.b * 0.8
|
||||
|
||||
local Driver = self:GetDriver()
|
||||
if IsValid( Driver ) then
|
||||
if self.RemoteDriver ~= Driver then
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage( Driver:Health() + Driver:Armor() )
|
||||
dmginfo:SetAttacker( self.LastAttacker or game.GetWorld() )
|
||||
dmginfo:SetInflictor( self.LastInflictor or game.GetWorld() )
|
||||
dmginfo:SetDamageType( DMG_DIRECT )
|
||||
|
||||
Driver:TakeDamageInfo( dmginfo )
|
||||
end
|
||||
end
|
||||
|
||||
if self.PassengerSeats then
|
||||
for i = 1, table.Count( self.PassengerSeats ) do
|
||||
local Passenger = self.pSeat[i]:GetDriver()
|
||||
if IsValid( Passenger ) then
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage( Passenger:Health() + Passenger:Armor() )
|
||||
dmginfo:SetAttacker( self.LastAttacker or game.GetWorld() )
|
||||
dmginfo:SetInflictor( self.LastInflictor or game.GetWorld() )
|
||||
dmginfo:SetDamageType( DMG_DIRECT )
|
||||
|
||||
Passenger:TakeDamageInfo( dmginfo )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.GibModels then
|
||||
local bprop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
bprop:SetModel( self.GibModels[1] )
|
||||
bprop:SetPos( self:GetPos() )
|
||||
bprop:SetAngles( self:GetAngles() )
|
||||
bprop.MakeSound = true
|
||||
bprop:Spawn()
|
||||
bprop:Activate()
|
||||
bprop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(150,250)) )
|
||||
bprop:GetPhysicsObject():SetMass( self.Mass * 0.75 )
|
||||
bprop.DoNotDuplicate = true
|
||||
bprop:SetColor( Col )
|
||||
bprop:SetSkin( skin )
|
||||
|
||||
self.Gib = bprop
|
||||
|
||||
simfphys.SetOwner( ply , bprop )
|
||||
|
||||
if IsValid( ply ) then
|
||||
undo.Create( "Gib" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( bprop )
|
||||
undo.SetCustomUndoText( "Undone Gib" )
|
||||
undo.Finish( "Gib" )
|
||||
ply:AddCleanup( "Gibs", bprop )
|
||||
end
|
||||
|
||||
bprop.Gibs = {}
|
||||
for i = 2, table.Count( self.GibModels ) do
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
prop:SetModel( self.GibModels[i] )
|
||||
prop:SetPos( self:GetPos() )
|
||||
prop:SetAngles( self:GetAngles() )
|
||||
prop:SetOwner( bprop )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop.DoNotDuplicate = true
|
||||
bprop:DeleteOnRemove( prop )
|
||||
bprop.Gibs[i-1] = prop
|
||||
|
||||
local PhysObj = prop:GetPhysicsObject()
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:SetVelocityInstantaneous( VectorRand() * 500 + self:GetVelocity() + Vector(0,0,math.random(150,250)) )
|
||||
PhysObj:AddAngleVelocity( VectorRand() )
|
||||
end
|
||||
|
||||
|
||||
simfphys.SetOwner( ply , prop )
|
||||
end
|
||||
else
|
||||
|
||||
local bprop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
bprop:SetModel( self:GetModel() )
|
||||
bprop:SetPos( self:GetPos() )
|
||||
bprop:SetAngles( self:GetAngles() )
|
||||
bprop.MakeSound = true
|
||||
bprop:Spawn()
|
||||
bprop:Activate()
|
||||
bprop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(150,250)) )
|
||||
bprop:GetPhysicsObject():SetMass( self.Mass * 0.75 )
|
||||
bprop.DoNotDuplicate = true
|
||||
bprop:SetColor( Col )
|
||||
bprop:SetSkin( skin )
|
||||
for i = 0, self:GetNumBodyGroups() do
|
||||
bprop:SetBodygroup(i, self:GetBodygroup(i))
|
||||
end
|
||||
|
||||
self.Gib = bprop
|
||||
|
||||
simfphys.SetOwner( ply , bprop )
|
||||
|
||||
if IsValid( ply ) then
|
||||
undo.Create( "Gib" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( bprop )
|
||||
undo.SetCustomUndoText( "Undone Gib" )
|
||||
undo.Finish( "Gib" )
|
||||
ply:AddCleanup( "Gibs", bprop )
|
||||
end
|
||||
|
||||
if self.CustomWheels == true and not self.NoWheelGibs then
|
||||
bprop.Wheels = {}
|
||||
for i = 1, table.Count( self.GhostWheels ) do
|
||||
local Wheel = self.GhostWheels[i]
|
||||
if IsValid(Wheel) then
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_gib" )
|
||||
prop:SetModel( Wheel:GetModel() )
|
||||
prop:SetPos( Wheel:LocalToWorld( Vector(0,0,0) ) )
|
||||
prop:SetAngles( Wheel:LocalToWorldAngles( Angle(0,0,0) ) )
|
||||
prop:SetOwner( bprop )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop:GetPhysicsObject():SetVelocity( self:GetVelocity() + Vector(math.random(-5,5),math.random(-5,5),math.random(0,25)) )
|
||||
prop:GetPhysicsObject():SetMass( 20 )
|
||||
prop.DoNotDuplicate = true
|
||||
bprop:DeleteOnRemove( prop )
|
||||
bprop.Wheels[i] = prop
|
||||
|
||||
simfphys.SetOwner( ply , prop )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:Extinguish()
|
||||
|
||||
self:OnDestroyed()
|
||||
|
||||
hook.Run( "simfphysOnDestroyed", self, self.Gib )
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
1428
lua/entities/gmod_sent_vehicle_fphysics_base/init.lua
Normal file
1428
lua/entities/gmod_sent_vehicle_fphysics_base/init.lua
Normal file
File diff suppressed because it is too large
Load Diff
317
lua/entities/gmod_sent_vehicle_fphysics_base/numpads.lua
Normal file
317
lua/entities/gmod_sent_vehicle_fphysics_base/numpads.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
numpad.Register( "k_forward", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["W"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_reverse", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["S"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_left", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["A"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_right", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["D"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_forward", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aW"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_reverse", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aS"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_left", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if (ent.PressedKeys) then
|
||||
ent.PressedKeys["aA"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_a_right", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["aD"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_gup", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
if not pl:lvsGetInputEnabled() then keydown = false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["M1"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_gdn", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
if not pl:lvsGetInputEnabled() then keydown = false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["M2"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_wot", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Shift"] = keydown
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_clutch", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Alt"] = keydown
|
||||
end
|
||||
end )
|
||||
numpad.Register( "k_hbrk", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if ent.PressedKeys then
|
||||
ent.PressedKeys["Space"] = keydown
|
||||
end
|
||||
|
||||
if keydown and ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_ccon", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if keydown then
|
||||
if ent:GetIsCruiseModeOn() then
|
||||
ent:SetIsCruiseModeOn( false )
|
||||
else
|
||||
ent:SetIsCruiseModeOn( true )
|
||||
ent.cc_speed = math.Round(ent:GetVelocity():Length(),0)
|
||||
end
|
||||
end
|
||||
end )
|
||||
|
||||
numpad.Register( "k_hrn", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
ent.KeyPressedTime = isnumber( ent.KeyPressedTime ) and ent.KeyPressedTime or 0
|
||||
|
||||
local v_list = list.Get( "simfphys_lights" )[ent.LightsTable] or false
|
||||
|
||||
if keydown then
|
||||
ent.HornKeyIsDown = true
|
||||
|
||||
if v_list and v_list.ems_sounds then
|
||||
if not ent.emson then
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid(ent) or not ent.HornKeyIsDown then return end
|
||||
|
||||
if not ent.horn then
|
||||
ent.horn = CreateSound(ent, ent.snd_horn or "simulated_vehicles/horn_1.wav")
|
||||
ent.horn:PlayEx(0,100)
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
if not ent.horn then
|
||||
ent.horn = CreateSound(ent, ent.snd_horn or "simulated_vehicles/horn_1.wav")
|
||||
ent.horn:PlayEx(0,100)
|
||||
end
|
||||
end
|
||||
else
|
||||
ent.HornKeyIsDown = false
|
||||
end
|
||||
|
||||
if not v_list then return end
|
||||
|
||||
if v_list.ems_sounds then
|
||||
|
||||
local Time = CurTime()
|
||||
|
||||
if keydown then
|
||||
ent.KeyPressedTime = Time
|
||||
else
|
||||
if (Time - ent.KeyPressedTime) < 0.15 then
|
||||
if not ent.emson then
|
||||
ent.emson = true
|
||||
ent.cursound = 0
|
||||
end
|
||||
end
|
||||
|
||||
if (Time - ent.KeyPressedTime) >= 0.22 then
|
||||
if ent.emson then
|
||||
ent.emson = false
|
||||
if ent.ems then
|
||||
ent.ems:Stop()
|
||||
end
|
||||
end
|
||||
else
|
||||
if ent.emson then
|
||||
if ent.ems then ent.ems:Stop() end
|
||||
local sounds = v_list.ems_sounds
|
||||
local numsounds = table.Count( sounds )
|
||||
|
||||
if numsounds <= 1 and ent.ems then
|
||||
ent.emson = false
|
||||
ent.ems = nil
|
||||
ent:SetEMSEnabled( false )
|
||||
return
|
||||
end
|
||||
|
||||
ent.cursound = ent.cursound + 1
|
||||
if ent.cursound > table.Count( sounds ) then
|
||||
ent.cursound = 1
|
||||
end
|
||||
|
||||
ent.ems = CreateSound(ent, sounds[ent.cursound])
|
||||
ent.ems:Play()
|
||||
end
|
||||
end
|
||||
ent:SetEMSEnabled( ent.emson )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_eng", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) then return false end
|
||||
|
||||
if keydown then
|
||||
if ent:EngineActive() then
|
||||
ent:StopEngine()
|
||||
else
|
||||
ent:StartEngine( true )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_flgts", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) or not ent.LightsTable then return false end
|
||||
|
||||
if keydown then
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
|
||||
if ent:GetFogLightsEnabled() then
|
||||
ent:SetFogLightsEnabled( false )
|
||||
else
|
||||
ent:SetFogLightsEnabled( true )
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
numpad.Register( "k_lgts", function( pl, ent, keydown )
|
||||
if not IsValid(pl) or not IsValid(ent) or not ent.LightsTable then return false end
|
||||
|
||||
local Time = CurTime()
|
||||
|
||||
if keydown then
|
||||
ent.KeyPressedTime = Time
|
||||
else
|
||||
if ent.KeyPressedTime and (Time - ent.KeyPressedTime) >= (ent.LightsActivated and 0.22 or 0) then
|
||||
if (ent.NextLightCheck or 0) > Time then return end
|
||||
|
||||
local vehiclelist = list.Get( "simfphys_lights" )[ent.LightsTable] or false
|
||||
if not vehiclelist then return end
|
||||
|
||||
if ent.LightsActivated then
|
||||
ent.NextLightCheck = Time + (vehiclelist.DelayOff or 0)
|
||||
ent.LightsActivated = false
|
||||
ent:SetLightsEnabled(false)
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
ent.LampsActivated = false
|
||||
ent:SetLampsEnabled( ent.LampsActivated )
|
||||
else
|
||||
ent.NextLightCheck = Time + (vehiclelist.DelayOn or 0)
|
||||
ent.LightsActivated = true
|
||||
ent:EmitSound( "buttons/lightswitch2.wav" )
|
||||
end
|
||||
|
||||
if ent.LightsActivated then
|
||||
if vehiclelist.BodyGroups then
|
||||
ent:SetBodygroup(vehiclelist.BodyGroups.On[1], vehiclelist.BodyGroups.On[2] )
|
||||
end
|
||||
if vehiclelist.Animation then
|
||||
ent:PlayAnimation( vehiclelist.Animation.On )
|
||||
end
|
||||
if ent.LightsPP then
|
||||
ent:PlayPP(ent.LightsActivated)
|
||||
end
|
||||
else
|
||||
if vehiclelist.BodyGroups then
|
||||
ent:SetBodygroup(vehiclelist.BodyGroups.Off[1], vehiclelist.BodyGroups.Off[2] )
|
||||
end
|
||||
if vehiclelist.Animation then
|
||||
ent:PlayAnimation( vehiclelist.Animation.Off )
|
||||
end
|
||||
if ent.LightsPP then
|
||||
ent:PlayPP(ent.LightsActivated)
|
||||
end
|
||||
end
|
||||
else
|
||||
if (ent.NextLightCheck or 0) > Time then return end
|
||||
|
||||
if ent.LampsActivated then
|
||||
ent.LampsActivated = false
|
||||
else
|
||||
ent.LampsActivated = true
|
||||
end
|
||||
|
||||
ent:SetLampsEnabled( ent.LampsActivated )
|
||||
|
||||
ent:EmitSound( "items/flashlight1.wav" )
|
||||
end
|
||||
end
|
||||
end )
|
||||
314
lua/entities/gmod_sent_vehicle_fphysics_base/shared.lua
Normal file
314
lua/entities/gmod_sent_vehicle_fphysics_base/shared.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
| 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 = "lvs_base"
|
||||
|
||||
ENT.PrintName = "Comedy Effect"
|
||||
ENT.Author = "Blu"
|
||||
ENT.Information = ""
|
||||
ENT.Category = "Fun + Games"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminSpawnable = false
|
||||
|
||||
ENT.AutomaticFrameAdvance = true
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
ENT.Editable = true
|
||||
|
||||
-- this needs to be here for some addons
|
||||
ENT.IsSimfphyscar = true
|
||||
|
||||
ENT.LVSsimfphys = true
|
||||
|
||||
ENT.MaxHealth = -1
|
||||
|
||||
ENT.MouseSteerAngle = 20
|
||||
ENT.MouseSteerExponent = 2
|
||||
|
||||
ENT.lvsDisableZoom = false
|
||||
|
||||
ENT.DoNotDuplicate = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:AddDT( "Int", "AITEAM", { KeyName = "aiteam", Edit = { type = "Int", order = 0,min = 0, max = 3, category = "AI"} } )
|
||||
|
||||
self:AddDT( "Float", "SteerSpeed", { KeyName = "steerspeed", Edit = { type = "Float", order = 1,min = 1, max = 16, category = "Steering"} } )
|
||||
self:AddDT( "Float", "FastSteerConeFadeSpeed", { KeyName = "faststeerconefadespeed", Edit = { type = "Float", order = 2,min = 1, max = 5000, category = "Steering"} } )
|
||||
self:AddDT( "Float", "FastSteerAngle", { KeyName = "faststeerangle", Edit = { type = "Float", order = 3,min = 0, max = 1, category = "Steering"} } )
|
||||
|
||||
self:AddDT( "Float", "FrontSuspensionHeight", { KeyName = "frontsuspensionheight", Edit = { type = "Float", order = 4,min = -1, max = 1, category = "Suspension" } } )
|
||||
self:AddDT( "Float", "RearSuspensionHeight", { KeyName = "rearsuspensionheight", Edit = { type = "Float", order = 5,min = -1, max = 1, category = "Suspension" } } )
|
||||
|
||||
self:AddDT( "Int", "EngineSoundPreset", { KeyName = "enginesoundpreset", Edit = { type = "Int", order = 6,min = -1, max = 23, category = "Engine"} } )
|
||||
self:AddDT( "Int", "IdleRPM", { KeyName = "idlerpm", Edit = { type = "Int", order = 7,min = 1, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "LimitRPM", { KeyName = "limitrpm", Edit = { type = "Int", order = 8,min = 4, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "PowerBandStart", { KeyName = "powerbandstart", Edit = { type = "Int", order = 9,min = 2, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Int", "PowerBandEnd", { KeyName = "powerbandend", Edit = { type = "Int", order = 10,min = 3, max = 25000, category = "Engine"} } )
|
||||
self:AddDT( "Float", "MaxTorque", { KeyName = "maxtorque", Edit = { type = "Float", order = 11,min = 20, max = 1000, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "Revlimiter", { KeyName = "revlimiter", Edit = { type = "Boolean", order = 12, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "TurboCharged", { KeyName = "turbocharged", Edit = { type = "Boolean", order = 13, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "SuperCharged", { KeyName = "supercharged", Edit = { type = "Boolean", order = 14, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "BackFire", { KeyName = "backfire", Edit = { type = "Boolean", order = 15, category = "Engine"} } )
|
||||
self:AddDT( "Bool", "DoNotStall", { KeyName = "donotstall", Edit = { type = "Boolean", order = 16, category = "Engine"} } )
|
||||
|
||||
self:AddDT( "Float", "DifferentialGear", { KeyName = "differentialgear", Edit = { type = "Float", order = 17,min = 0.2, max = 6, category = "Transmission"} } )
|
||||
|
||||
self:AddDT( "Float", "BrakePower", { KeyName = "brakepower", Edit = { type = "Float", order = 18,min = 0.1, max = 500, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "PowerDistribution", { KeyName = "powerdistribution", Edit = { type = "Float", order = 19,min = -1, max = 1, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "Efficiency", { KeyName = "efficiency", Edit = { type = "Float", order = 20,min = 0.2, max = 4, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "MaxTraction", { KeyName = "maxtraction", Edit = { type = "Float", order = 21,min = 5, max = 1000, category = "Wheels"} } )
|
||||
self:AddDT( "Float", "TractionBias", { KeyName = "tractionbias", Edit = { type = "Float", order = 22,min = -0.99, max = 0.99, category = "Wheels"} } )
|
||||
self:AddDT( "Bool", "BulletProofTires", { KeyName = "bulletprooftires", Edit = { type = "Boolean", order = 23, category = "Wheels"} } )
|
||||
self:AddDT( "Vector", "TireSmokeColor", { KeyName = "tiresmokecolor", Edit = { type = "VectorColor", order = 24, category = "Wheels"} } )
|
||||
|
||||
self:AddDT( "Float", "FlyWheelRPM" )
|
||||
self:AddDT( "Float", "Throttle" )
|
||||
self:AddDT( "Float", "WheelVelocity" )
|
||||
self:AddDT( "Int", "Gear" )
|
||||
self:AddDT( "Int", "Clutch" )
|
||||
self:AddDT( "Bool", "IsCruiseModeOn" )
|
||||
self:AddDT( "Bool", "IsBraking" )
|
||||
self:AddDT( "Bool", "LightsEnabled" )
|
||||
self:AddDT( "Bool", "LampsEnabled" )
|
||||
self:AddDT( "Bool", "EMSEnabled" )
|
||||
self:AddDT( "Bool", "FogLightsEnabled" )
|
||||
self:AddDT( "Bool", "HandBrakeEnabled" )
|
||||
|
||||
self:AddDT( "Bool", "lvsLockedStatus" )
|
||||
self:AddDT( "Bool", "lvsReady" )
|
||||
|
||||
self:AddDT( "Float", "VehicleSteer" )
|
||||
|
||||
self:AddDT( "Float", "CurHealth" )
|
||||
|
||||
self:AddDT( "Entity", "Driver" )
|
||||
self:AddDT( "Entity", "DriverSeat" )
|
||||
self:AddDT( "Entity", "FuelTank" )
|
||||
self:AddDT( "Bool", "Active" )
|
||||
|
||||
self:AddDT( "String", "Spawn_List")
|
||||
self:AddDT( "String", "Lights_List")
|
||||
self:AddDT( "String", "Soundoverride")
|
||||
|
||||
self:AddDT( "Vector", "FuelPortPosition" )
|
||||
|
||||
if SERVER then
|
||||
self:SetCurHealth( 1 )
|
||||
|
||||
self:NetworkVarNotify( "FrontSuspensionHeight", self.OnFrontSuspensionHeightChanged )
|
||||
self:NetworkVarNotify( "RearSuspensionHeight", self.OnRearSuspensionHeightChanged )
|
||||
self:NetworkVarNotify( "TurboCharged", self.OnTurboCharged )
|
||||
self:NetworkVarNotify( "SuperCharged", self.OnSuperCharged )
|
||||
self:NetworkVarNotify( "Active", self.OnActiveChanged )
|
||||
self:NetworkVarNotify( "Throttle", self.OnThrottleChanged )
|
||||
self:NetworkVarNotify( "CurHealth", self.OnHealthChanged )
|
||||
end
|
||||
|
||||
self:AddDataTables()
|
||||
end
|
||||
|
||||
function ENT:AddDataTables()
|
||||
end
|
||||
|
||||
local VehicleMeta = FindMetaTable("Entity")
|
||||
local OldIsVehicle = VehicleMeta.IsVehicle
|
||||
function VehicleMeta:IsVehicle()
|
||||
|
||||
if self.LVSsimfphys then
|
||||
return true
|
||||
end
|
||||
|
||||
return OldIsVehicle( self )
|
||||
end
|
||||
|
||||
function ENT:GetSelectedWeapon()
|
||||
return 0
|
||||
end
|
||||
|
||||
function ENT:GetAI()
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:SetHP( nHealth )
|
||||
self:SetCurHealth( nHealth )
|
||||
end
|
||||
|
||||
function ENT:GetShield()
|
||||
return 0
|
||||
end
|
||||
|
||||
function ENT:SetShield()
|
||||
end
|
||||
|
||||
function ENT:GetHP()
|
||||
return self:GetCurHealth()
|
||||
end
|
||||
|
||||
function ENT:GetMaxHP()
|
||||
return self:GetMaxHealth()
|
||||
end
|
||||
|
||||
function ENT:GetMaxHealth()
|
||||
return self:GetNWFloat( "MaxHealth", 2000 )
|
||||
end
|
||||
|
||||
function ENT:GetMaxFuel()
|
||||
return self:GetNWFloat( "MaxFuel", 60 )
|
||||
end
|
||||
|
||||
function ENT:GetFuel()
|
||||
return self:GetNWFloat( "Fuel", self:GetMaxFuel() )
|
||||
end
|
||||
|
||||
function ENT:GetFuelUse()
|
||||
return self:GetNWFloat( "FuelUse", 0 )
|
||||
end
|
||||
|
||||
function ENT:GetFuelType()
|
||||
return self:GetNWInt( "FuelType", 1 )
|
||||
end
|
||||
|
||||
function ENT:GetFuelPos()
|
||||
return self:LocalToWorld( self:GetFuelPortPosition() )
|
||||
end
|
||||
|
||||
function ENT:OnSmoke()
|
||||
return self:GetNWBool( "OnSmoke", false )
|
||||
end
|
||||
|
||||
function ENT:OnFire()
|
||||
return self:GetNWBool( "OnFire", false )
|
||||
end
|
||||
|
||||
function ENT:GetIsVehicleLocked()
|
||||
return self:GetlvsLockedStatus()
|
||||
end
|
||||
|
||||
function ENT:SetIsVehicleLocked( lock )
|
||||
self:SetlvsLockedStatus( lock )
|
||||
end
|
||||
|
||||
function ENT:GetBackfireSound()
|
||||
return self:GetNWString( "backfiresound" )
|
||||
end
|
||||
|
||||
function ENT:SetBackfireSound( the_sound )
|
||||
self:SetNWString( "backfiresound", the_sound )
|
||||
end
|
||||
|
||||
function ENT:BodyGroupIsValid( bodygroups )
|
||||
for index, groups in pairs( bodygroups ) do
|
||||
local mygroup = self:GetBodygroup( index )
|
||||
for g_index = 1, table.Count( groups ) do
|
||||
if mygroup == groups[g_index] then return true end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:GetVehicleClass()
|
||||
return self:GetSpawn_List()
|
||||
end
|
||||
|
||||
function ENT:CalcMainActivityPassenger( ply )
|
||||
if not istable( self.PassengerSeats ) then
|
||||
|
||||
if not self.HasCheckedpSeats then
|
||||
self.HasCheckedpSeats = true
|
||||
|
||||
self.PassengerSeats = list.Get( "simfphys_vehicles" )[ self:GetSpawn_List() ].Members.PassengerSeats
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local Pod = ply:GetVehicle()
|
||||
|
||||
local pSeatTBL = self.PassengerSeats[ Pod:GetNWInt( "pPodIndex", -1 ) - 1 ]
|
||||
|
||||
if not istable( pSeatTBL ) then return end
|
||||
|
||||
local seq = pSeatTBL.anim
|
||||
|
||||
if not isstring( seq ) then return end
|
||||
|
||||
if ply.m_bWasNoclipping then
|
||||
ply.m_bWasNoclipping = nil
|
||||
ply:AnimResetGestureSlot( GESTURE_SLOT_CUSTOM )
|
||||
|
||||
if CLIENT then
|
||||
ply:SetIK( true )
|
||||
end
|
||||
end
|
||||
|
||||
ply.CalcIdeal = ACT_STAND
|
||||
ply.CalcSeqOverride = ply:LookupSequence( seq )
|
||||
|
||||
return ply.CalcIdeal, ply.CalcSeqOverride
|
||||
end
|
||||
|
||||
function ENT:CalcMainActivity( ply )
|
||||
if ply ~= self:GetDriver() then return self:CalcMainActivityPassenger( ply ) end
|
||||
|
||||
if ply.m_bWasNoclipping then
|
||||
ply.m_bWasNoclipping = nil
|
||||
ply:AnimResetGestureSlot( GESTURE_SLOT_CUSTOM )
|
||||
|
||||
if CLIENT then
|
||||
ply:SetIK( true )
|
||||
end
|
||||
end
|
||||
|
||||
ply.CalcIdeal = ACT_STAND
|
||||
|
||||
if isstring( self.SeatAnim ) then
|
||||
ply.CalcSeqOverride = ply:LookupSequence( self.SeatAnim )
|
||||
else
|
||||
if not self.HasCheckedSeat then
|
||||
self.HasCheckedSeat = true
|
||||
|
||||
self.SeatAnim = list.Get( "simfphys_vehicles" )[ self:GetSpawn_List() ].Members.SeatAnim
|
||||
end
|
||||
|
||||
ply.CalcSeqOverride = ply:LookupSequence( "drive_jeep" )
|
||||
end
|
||||
|
||||
return ply.CalcIdeal, ply.CalcSeqOverride
|
||||
end
|
||||
|
||||
function ENT:UpdateAnimation( ply, velocity, maxseqgroundspeed )
|
||||
ply:SetPlaybackRate( 1 )
|
||||
|
||||
if CLIENT then
|
||||
if ply == self:GetDriver() then
|
||||
ply:SetPoseParameter( "vehicle_steer", self:GetVehicleSteer() )
|
||||
ply:InvalidateBoneCache()
|
||||
end
|
||||
|
||||
GAMEMODE:GrabEarAnimation( ply )
|
||||
GAMEMODE:MouthMoveAnimation( ply )
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:StartCommand( ply, cmd )
|
||||
if self:GetDriver() ~= ply then return end
|
||||
|
||||
if SERVER then
|
||||
self:SetRoadkillAttacker( ply )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetVehicleType()
|
||||
return "car"
|
||||
end
|
||||
522
lua/entities/gmod_sent_vehicle_fphysics_base/simfunc.lua
Normal file
522
lua/entities/gmod_sent_vehicle_fphysics_base/simfunc.lua
Normal file
@@ -0,0 +1,522 @@
|
||||
--[[
|
||||
| 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 ENT:WheelOnGround()
|
||||
self.FrontWheelPowered = self:GetPowerDistribution() ~= 1
|
||||
self.RearWheelPowered = self:GetPowerDistribution() ~= -1
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Wheel = self.Wheels[i]
|
||||
|
||||
if not IsValid( Wheel ) then continue end
|
||||
|
||||
local dmgMul = Wheel:GetDamaged() and 0.5 or 1
|
||||
local surfacemul = simfphys.TractionData[Wheel:GetSurfaceMaterial():lower()]
|
||||
|
||||
self.VehicleData[ "SurfaceMul_" .. i ] = (surfacemul and math.max(surfacemul,0.001) or 1) * dmgMul
|
||||
|
||||
local WheelPos = self:LogicWheelPos( i )
|
||||
|
||||
local WheelRadius = WheelPos.IsFrontWheel and self.FrontWheelRadius or self.RearWheelRadius
|
||||
local startpos = Wheel:GetPos()
|
||||
local dir = -self.Up
|
||||
local len = WheelRadius + math.Clamp(-self.Vel.z / 50,2.5,6)
|
||||
local HullSize = Vector(WheelRadius,WheelRadius,0)
|
||||
local tr = util.TraceHull( {
|
||||
start = startpos,
|
||||
endpos = startpos + dir * len,
|
||||
maxs = HullSize,
|
||||
mins = -HullSize,
|
||||
filter = self.VehicleData["filter"]
|
||||
} )
|
||||
|
||||
if tr.Hit then
|
||||
self.VehicleData[ "onGround_" .. i ] = 1
|
||||
Wheel:SetSpeed( Wheel.FX )
|
||||
Wheel:SetSkidSound( Wheel.skid )
|
||||
Wheel:SetSurfaceMaterial( util.GetSurfacePropName( tr.SurfaceProps ) )
|
||||
Wheel:SetOnGround(1)
|
||||
else
|
||||
self.VehicleData[ "onGround_" .. i ] = 0
|
||||
Wheel:SetOnGround(0)
|
||||
end
|
||||
end
|
||||
|
||||
local FrontOnGround = math.max(self.VehicleData[ "onGround_1" ],self.VehicleData[ "onGround_2" ])
|
||||
local RearOnGround = math.max(self.VehicleData[ "onGround_3" ],self.VehicleData[ "onGround_4" ],self.VehicleData[ "onGround_5" ],self.VehicleData[ "onGround_6" ])
|
||||
|
||||
self.DriveWheelsOnGround = math.max(self.FrontWheelPowered and FrontOnGround or 0,self.RearWheelPowered and RearOnGround or 0)
|
||||
end
|
||||
|
||||
function ENT:SimulateAirControls(tilt_forward,tilt_back,tilt_left,tilt_right)
|
||||
if self:IsDriveWheelsOnGround() then return end
|
||||
|
||||
if hook.Run( "simfphysAirControl", self, tilt_forward, tilt_back, tilt_left, tilt_right) then return end
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
local TiltForce = ((self.Right * (tilt_right - tilt_left) * 1.8) + (self.Forward * (tilt_forward - tilt_back) * 6)) * math.acos( math.Clamp( self.Up:Dot(Vector(0,0,1)) ,-1,1) ) * (180 / math.pi) * self.Mass
|
||||
PObj:ApplyForceOffset( TiltForce, PObj:GetMassCenter() + self.Up )
|
||||
PObj:ApplyForceOffset( -TiltForce, PObj:GetMassCenter() - self.Up )
|
||||
end
|
||||
|
||||
function ENT:SimulateEngine(IdleRPM,LimitRPM,Powerbandstart,Powerbandend,c_time)
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
local IsRunning = self:EngineActive()
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
if not self:IsDriveWheelsOnGround() then
|
||||
self.Clutch = 1
|
||||
end
|
||||
|
||||
if self.Gears[self.CurrentGear] == 0 then
|
||||
self.GearRatio = 1
|
||||
self.Clutch = 1
|
||||
self.HandBrake = self.HandBrake + (self.HandBrakePower - self.HandBrake) * 0.2
|
||||
else
|
||||
self.GearRatio = self.Gears[self.CurrentGear] * self:GetDiffGear()
|
||||
end
|
||||
|
||||
self:SetClutch( self.Clutch )
|
||||
local InvClutch = 1 - self.Clutch
|
||||
|
||||
local GearedRPM = self.WheelRPM / math.abs(self.GearRatio)
|
||||
|
||||
local MaxTorque = self:GetMaxTorque()
|
||||
|
||||
local DesRPM = Lerp(InvClutch, math.max(IdleRPM + (LimitRPM - IdleRPM) * Throttle,0), GearedRPM )
|
||||
local Drag = (MaxTorque * (math.max( self.EngineRPM - IdleRPM, 0) / Powerbandend) * ( 1 - Throttle) / 0.15) * InvClutch
|
||||
|
||||
local TurboCharged = self:GetTurboCharged()
|
||||
local SuperCharged = self:GetSuperCharged()
|
||||
local boost = (TurboCharged and self:SimulateTurbo(Powerbandend) or 0) * 0.3 + (SuperCharged and self:SimulateBlower(Powerbandend) or 0)
|
||||
|
||||
if self:GetCurHealth() <= self:GetMaxHealth() * 0.3 then
|
||||
MaxTorque = MaxTorque * (self:GetCurHealth() / (self:GetMaxHealth() * 0.3))
|
||||
end
|
||||
|
||||
self.EngineRPM = math.Clamp(self.EngineRPM + math.Clamp(DesRPM - self.EngineRPM,-math.max(self.EngineRPM / 15, 1 ),math.max(-self.RpmDiff / 1.5 * InvClutch + (self.Torque * 5) / 0.15 * self.Clutch, 1)) + self.RPM_DIFFERENCE * Throttle,0,LimitRPM) * self.EngineIsOn
|
||||
self.Torque = (Throttle + boost) * math.max(MaxTorque * math.min(self.EngineRPM / Powerbandstart, (LimitRPM - self.EngineRPM) / (LimitRPM - Powerbandend),1), 0)
|
||||
self:SetFlyWheelRPM( math.min(self.EngineRPM + self.exprpmdiff * 2 * InvClutch,LimitRPM) )
|
||||
|
||||
self.RpmDiff = self.EngineRPM - GearedRPM
|
||||
|
||||
local signGearRatio = ((self.GearRatio > 0) and 1 or 0) + ((self.GearRatio < 0) and -1 or 0)
|
||||
local signThrottle = (Throttle > 0) and 1 or 0
|
||||
local signSpeed = ((self.ForwardSpeed > 0) and 1 or 0) + ((self.ForwardSpeed < 0) and -1 or 0)
|
||||
|
||||
local TorqueDiff = (self.RpmDiff / LimitRPM) * 0.15 * self.Torque
|
||||
local EngineBrake = (signThrottle == 0) and math.min( self.EngineRPM * (self.EngineRPM / LimitRPM) ^ 2 / 60 * signSpeed, 100 ) or 0
|
||||
|
||||
local GearedPower = ((self.ThrottleDelay <= c_time and (self.Torque + TorqueDiff) * signThrottle * signGearRatio or 0) - EngineBrake) / math.abs(self.GearRatio) / 50
|
||||
|
||||
self.EngineTorque = IsRunning and GearedPower * InvClutch or 0
|
||||
|
||||
if not self:GetDoNotStall() then
|
||||
if IsRunning then
|
||||
if self.EngineRPM <= IdleRPM * 0.2 then
|
||||
self.CurrentGear = 2
|
||||
self:StallAndRestart()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if simfphys.Fuel then
|
||||
local FuelUse = (Throttle * 0.3 + 0.7) * ((self.EngineRPM / LimitRPM) * MaxTorque + self.Torque) / 1500000
|
||||
local Fuel = self:GetFuel()
|
||||
self:SetFuel( Fuel - FuelUse * (1 / simfphys.FuelMul) )
|
||||
|
||||
self.UsedFuel = self.UsedFuel and (self.UsedFuel + FuelUse) or 0
|
||||
self.CheckUse = self.CheckUse or 0
|
||||
if self.CheckUse < CurTime() then
|
||||
self.CheckUse = CurTime() + 1
|
||||
self:SetFuelUse( self.UsedFuel * 60 )
|
||||
self.UsedFuel = 0
|
||||
end
|
||||
|
||||
if Fuel <= 0 and IsRunning then
|
||||
self:StopEngine()
|
||||
end
|
||||
else
|
||||
self:SetFuelUse( -1 )
|
||||
end
|
||||
|
||||
local ReactionForce = (self.EngineTorque * 2 - math.Clamp(self.ForwardSpeed,-self.Brake,self.Brake)) * self.DriveWheelsOnGround
|
||||
local BaseMassCenter = PObj:GetMassCenter()
|
||||
local dt_mul = math.max( math.min(self:GetPowerDistribution() + 0.5,1),0)
|
||||
|
||||
PObj:ApplyForceOffset( -self.Forward * self.Mass * ReactionForce, BaseMassCenter + self.Up * dt_mul )
|
||||
PObj:ApplyForceOffset( self.Forward * self.Mass * ReactionForce, BaseMassCenter - self.Up * dt_mul )
|
||||
end
|
||||
|
||||
function ENT:SimulateTransmission(k_throttle,k_brake,k_fullthrottle,k_clutch,k_handbrake,k_gearup,k_geardown,isauto,IdleRPM,Powerbandstart,Powerbandend,shiftmode,cruisecontrol,curtime)
|
||||
local GearsCount = table.Count( self.Gears )
|
||||
local cruiseThrottle = math.min( math.max(self.cc_speed - math.abs(self.ForwardSpeed),0) / 10 ^ 2, 1)
|
||||
|
||||
if isnumber(self.ForceTransmission) then
|
||||
isauto = self.ForceTransmission <= 1
|
||||
end
|
||||
|
||||
if not isauto then
|
||||
self.Brake = self:GetBrakePower() * math.max( k_brake, self.PressedKeys["joystick_brake"] )
|
||||
self.HandBrake = self.HandBrakePower * k_handbrake
|
||||
self.Clutch = math.max( k_clutch, k_handbrake, self.PressedKeys["joystick_clutch"] )
|
||||
|
||||
local AutoThrottle = self:EngineActive() and ((self.EngineRPM < IdleRPM) and (IdleRPM - self.EngineRPM) / IdleRPM or 0) or 0
|
||||
local Throttle = cruisecontrol and cruiseThrottle or ( math.max( (0.5 + 0.5 * k_fullthrottle) * k_throttle, self.PressedKeys["joystick_throttle"] ) + AutoThrottle)
|
||||
self:SetThrottle( Throttle )
|
||||
|
||||
if k_gearup ~= self.GearUpPressed then
|
||||
self.GearUpPressed = k_gearup
|
||||
|
||||
if k_gearup == 1 then
|
||||
|
||||
if self.CurrentGear ~= GearsCount then
|
||||
self.ThrottleDelay = curtime + 0.4 - 0.4 * k_clutch
|
||||
end
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear + 1,1,GearsCount)
|
||||
end
|
||||
end
|
||||
|
||||
if k_geardown ~= self.GearDownPressed then
|
||||
self.GearDownPressed = k_geardown
|
||||
|
||||
if k_geardown == 1 then
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear - 1,1,GearsCount)
|
||||
|
||||
if self.CurrentGear == 1 then
|
||||
self.ThrottleDelay = curtime + 0.25
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
local throttleMod = 0.5 + 0.5 * k_fullthrottle
|
||||
local throttleForward = math.max( k_throttle * throttleMod, self.PressedKeys["joystick_throttle"] )
|
||||
local throttleReverse = math.max( k_brake * throttleMod, self.PressedKeys["joystick_brake"] )
|
||||
local throttleStanding = math.max( k_throttle * throttleMod, k_brake * throttleMod, self.PressedKeys["joystick_brake"], self.PressedKeys["joystick_throttle"] )
|
||||
local inputThrottle = self.ForwardSpeed >= 50 and throttleForward or ((self.ForwardSpeed < 50 and self.ForwardSpeed > -350) and throttleStanding or throttleReverse)
|
||||
|
||||
local Throttle = cruisecontrol and cruiseThrottle or inputThrottle
|
||||
local CalcRPM = self.EngineRPM - self.RPM_DIFFERENCE * Throttle
|
||||
self:SetThrottle( Throttle )
|
||||
|
||||
if self.CurrentGear <= 3 and Throttle > 0 and self.CurrentGear ~= 2 then
|
||||
if Throttle < 1 and not cruisecontrol then
|
||||
local autoclutch = math.Clamp((Powerbandstart / self.EngineRPM) - 0.5,0,1)
|
||||
|
||||
self.sm_autoclutch = self.sm_autoclutch and (self.sm_autoclutch + math.Clamp(autoclutch - self.sm_autoclutch,-0.2,0.1) ) or 0
|
||||
else
|
||||
self.sm_autoclutch = (self.EngineRPM < IdleRPM + (Powerbandstart - IdleRPM)) and 1 or 0
|
||||
end
|
||||
else
|
||||
self.sm_autoclutch = 0
|
||||
end
|
||||
|
||||
self.Clutch = math.max(self.sm_autoclutch,k_handbrake)
|
||||
|
||||
self.HandBrake = self.HandBrakePower * k_handbrake
|
||||
|
||||
self.Brake = self:GetBrakePower() * (self.ForwardSpeed >= 0 and math.max(k_brake,self.PressedKeys["joystick_brake"]) or math.max(k_throttle,self.PressedKeys["joystick_throttle"]))
|
||||
|
||||
if self:IsDriveWheelsOnGround() then
|
||||
if self.ForwardSpeed >= 50 then
|
||||
if self.Clutch == 0 then
|
||||
local NextGear = self.CurrentGear + 1 <= GearsCount and math.min(self.CurrentGear + 1,GearsCount) or self.CurrentGear
|
||||
local NextGearRatio = self.Gears[NextGear] * self:GetDiffGear()
|
||||
local NextGearRPM = self.WheelRPM / math.abs(NextGearRatio)
|
||||
|
||||
local PrevGear = self.CurrentGear - 1 <= GearsCount and math.max(self.CurrentGear - 1,3) or self.CurrentGear
|
||||
local PrevGearRatio = self.Gears[PrevGear] * self:GetDiffGear()
|
||||
local PrevGearRPM = self.WheelRPM / math.abs(PrevGearRatio)
|
||||
|
||||
local minThrottle = shiftmode == 1 and 1 or math.max(Throttle,0.5)
|
||||
|
||||
local ShiftUpRPM = Powerbandstart + (Powerbandend - Powerbandstart) * minThrottle
|
||||
local ShiftDownRPM = IdleRPM + (Powerbandend - Powerbandstart) * minThrottle
|
||||
|
||||
local CanShiftUp = NextGearRPM > math.max(Powerbandstart * minThrottle,Powerbandstart - IdleRPM) and CalcRPM >= ShiftUpRPM and self.CurrentGear < GearsCount
|
||||
local CanShiftDown = CalcRPM <= ShiftDownRPM and PrevGearRPM < ShiftDownRPM and self.CurrentGear > 3
|
||||
|
||||
if CanShiftUp and self.NextShift < curtime then
|
||||
self.CurrentGear = self.CurrentGear + 1
|
||||
self.NextShift = curtime + 0.5
|
||||
self.ThrottleDelay = curtime + 0.25
|
||||
end
|
||||
|
||||
if CanShiftDown and self.NextShift < curtime then
|
||||
self.CurrentGear = self.CurrentGear - 1
|
||||
self.NextShift = curtime + 0.35
|
||||
end
|
||||
|
||||
self.CurrentGear = math.Clamp(self.CurrentGear,3,GearsCount)
|
||||
end
|
||||
|
||||
elseif (self.ForwardSpeed < 50 and self.ForwardSpeed > -350) then
|
||||
|
||||
self.CurrentGear = (k_throttle == 1 and 3 or k_brake == 1 and 1 or self.PressedKeys["joystick_throttle"] > 0 and 3 or self.PressedKeys["joystick_brake"] > 0 and 1) or 3
|
||||
self.Brake = self:GetBrakePower() * math.max(k_throttle * k_brake,self.PressedKeys["joystick_throttle"] * self.PressedKeys["joystick_brake"])
|
||||
|
||||
elseif (self.ForwardSpeed >= -350) then
|
||||
|
||||
if (Throttle > 0) then
|
||||
self.Brake = 0
|
||||
end
|
||||
|
||||
self.CurrentGear = 1
|
||||
end
|
||||
|
||||
if (Throttle == 0 and math.abs(self.ForwardSpeed) <= 80) then
|
||||
self.CurrentGear = 2
|
||||
self.Brake = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
self:SetIsBraking( self.Brake > 0 )
|
||||
self:SetGear( self.CurrentGear )
|
||||
self:SetHandBrakeEnabled( self.HandBrake > 0 or self.CurrentGear == 2 )
|
||||
|
||||
if self.Clutch == 1 or self.CurrentGear == 2 then
|
||||
if math.abs(self.ForwardSpeed) <= 20 then
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
local TiltForce = self.Torque * (-1 + self:GetThrottle() * 2)
|
||||
|
||||
PObj:ApplyForceOffset( self.Up * TiltForce, PObj:GetMassCenter() + self.Right * 1000 )
|
||||
PObj:ApplyForceOffset( -self.Up * TiltForce, PObj:GetMassCenter() - self.Right * 1000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetTransformedDirection()
|
||||
local SteerAngForward = self.Forward:Angle()
|
||||
local SteerAngRight = self.Right:Angle()
|
||||
local SteerAngForward2 = self.Forward:Angle()
|
||||
local SteerAngRight2 = self.Right:Angle()
|
||||
|
||||
SteerAngForward:RotateAroundAxis(-self.Up, self.VehicleData[ "Steer" ])
|
||||
SteerAngRight:RotateAroundAxis(-self.Up, self.VehicleData[ "Steer" ])
|
||||
SteerAngForward2:RotateAroundAxis(-self.Up, -self.VehicleData[ "Steer" ])
|
||||
SteerAngRight2:RotateAroundAxis(-self.Up, -self.VehicleData[ "Steer" ])
|
||||
|
||||
local SteerForward = SteerAngForward:Forward()
|
||||
local SteerRight = SteerAngRight:Forward()
|
||||
local SteerForward2 = SteerAngForward2:Forward()
|
||||
local SteerRight2 = SteerAngRight2:Forward()
|
||||
|
||||
return {Forward = SteerForward,Right = SteerRight,Forward2 = SteerForward2, Right2 = SteerRight2}
|
||||
end
|
||||
|
||||
function ENT:LogicWheelPos( index )
|
||||
local IsFront = index == 1 or index == 2
|
||||
local IsRight = index == 2 or index == 4 or index == 6
|
||||
|
||||
return {IsFrontWheel = IsFront, IsRightWheel = IsRight}
|
||||
end
|
||||
|
||||
function ENT:SimulateWheels(k_clutch,LimitRPM)
|
||||
local Steer = self:GetTransformedDirection()
|
||||
local MaxGrip = self:GetMaxTraction()
|
||||
local Efficiency = self:GetEfficiency()
|
||||
local GripOffset = self:GetTractionBias() * MaxGrip
|
||||
local wVel = 0
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Wheel = self.Wheels[i]
|
||||
|
||||
if IsValid( Wheel ) then
|
||||
local WheelPos = self:LogicWheelPos( i )
|
||||
local WheelRadius = WheelPos.IsFrontWheel and self.FrontWheelRadius or self.RearWheelRadius
|
||||
local WheelDiameter = WheelRadius * 2
|
||||
local SurfaceMultiplicator = self.VehicleData[ "SurfaceMul_" .. i ]
|
||||
local MaxTraction = (WheelPos.IsFrontWheel and (MaxGrip + GripOffset) or (MaxGrip - GripOffset)) * SurfaceMultiplicator
|
||||
|
||||
local IsPoweredWheel = (WheelPos.IsFrontWheel and self.FrontWheelPowered or not WheelPos.IsFrontWheel and self.RearWheelPowered) and 1 or 0
|
||||
|
||||
local Velocity = Wheel:GetVelocity()
|
||||
local VelForward = Velocity:GetNormalized()
|
||||
local OnGround = self.VehicleData[ "onGround_" .. i ]
|
||||
|
||||
local Forward = WheelPos.IsFrontWheel and Steer.Forward or self.Forward
|
||||
local Right = WheelPos.IsFrontWheel and Steer.Right or self.Right
|
||||
|
||||
if self.CustomWheels then
|
||||
if WheelPos.IsFrontWheel then
|
||||
Forward = IsValid(self.SteerMaster) and Steer.Forward or self.Forward
|
||||
Right = IsValid(self.SteerMaster) and Steer.Right or self.Right
|
||||
else
|
||||
if IsValid( self.SteerMaster2 ) then
|
||||
Forward = Steer.Forward2
|
||||
Right = Steer.Right2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local Ax = math.deg( math.acos( math.Clamp( Forward:Dot(VelForward) ,-1,1) ) )
|
||||
local Ay = math.deg( math.asin( math.Clamp( Right:Dot(VelForward) ,-1,1) ) )
|
||||
|
||||
local Fx = math.cos( math.rad( Ax ) ) * Velocity:Length()
|
||||
local Fy = math.sin( math.rad( Ay ) ) * Velocity:Length()
|
||||
|
||||
local absFy = math.abs(Fy)
|
||||
local absFx = math.abs(Fx)
|
||||
|
||||
local PowerBiasMul = WheelPos.IsFrontWheel and (1 - self:GetPowerDistribution()) * 0.5 or (1 + self:GetPowerDistribution()) * 0.5
|
||||
local BrakeForce = math.Clamp(-Fx,-self.Brake,self.Brake) * SurfaceMultiplicator
|
||||
|
||||
local TorqueConv = self.EngineTorque * PowerBiasMul * IsPoweredWheel
|
||||
local ForwardForce = TorqueConv + (not WheelPos.IsFrontWheel and math.Clamp(-Fx,-self.HandBrake,self.HandBrake) or 0) + BrakeForce * 0.5
|
||||
|
||||
local TractionCycle = Vector(math.min(absFy,MaxTraction),ForwardForce,0):Length()
|
||||
|
||||
local GripLoss = math.max(TractionCycle - MaxTraction,0)
|
||||
local GripRemaining = math.max(MaxTraction - GripLoss,math.min(absFy / 25,MaxTraction))
|
||||
--local GripRemaining = math.max(MaxTraction - GripLoss,math.min(absFy / 25,MaxTraction / 2))
|
||||
|
||||
local signForwardForce = ((ForwardForce > 0) and 1 or 0) + ((ForwardForce < 0) and -1 or 0)
|
||||
local signEngineTorque = ((self.EngineTorque > 0) and 1 or 0) + ((self.EngineTorque < 0) and -1 or 0)
|
||||
|
||||
local Power = ForwardForce * Efficiency - GripLoss * signForwardForce + math.Clamp(BrakeForce * 0.5,-MaxTraction,MaxTraction)
|
||||
|
||||
local Force = -Right * math.Clamp(Fy,-GripRemaining,GripRemaining) + Forward * Power
|
||||
|
||||
local wRad = Wheel:GetDamaged() and Wheel.dRadius or WheelRadius
|
||||
local wFX = (Fx + GripLoss * 35 * signEngineTorque * IsPoweredWheel)
|
||||
local TurnWheel = (wFX / wRad * 1.85) + self.EngineRPM / 80 * (1 - OnGround) * IsPoweredWheel * (1 - k_clutch)
|
||||
|
||||
Wheel.FX = Fx
|
||||
Wheel.skid = ((MaxTraction - (MaxTraction - Vector(absFy,math.abs(ForwardForce * 10),0):Length())) / MaxTraction) - 10
|
||||
|
||||
local RPM = Wheel:VelToRPM( absFx ) * OnGround
|
||||
local GripLossFaktor = math.Clamp(GripLoss,0,MaxTraction) / MaxTraction
|
||||
|
||||
local abswFX = math.abs( wFX )
|
||||
Wheel:SetRPM( Wheel:VelToRPM( wFX ) )
|
||||
if IsPoweredWheel then
|
||||
if abswFX > wVel then
|
||||
wVel = abswFX
|
||||
end
|
||||
end
|
||||
|
||||
self.VehicleData[ "WheelRPM_".. i ] = RPM
|
||||
self.VehicleData[ "GripLossFaktor_".. i ] = GripLossFaktor
|
||||
self.VehicleData[ "Exp_GLF_".. i ] = GripLossFaktor ^ 2
|
||||
|
||||
Wheel:SetGripLoss( GripLossFaktor )
|
||||
|
||||
local WheelOPow = math.abs( self.CurrentGear == 1 and math.min( TorqueConv, 0 ) or math.max( TorqueConv, 0 ) ) > 0
|
||||
local FrontWheelCanTurn = (WheelOPow and 0 or self.Brake) < MaxTraction * 1.75
|
||||
local RearWheelCanTurn = (self.HandBrake < MaxTraction) and (WheelOPow and 0 or self.Brake) < MaxTraction * 2
|
||||
|
||||
if WheelPos.IsFrontWheel then
|
||||
if FrontWheelCanTurn then
|
||||
self.VehicleData[ "spin_" .. i ] = self.VehicleData[ "spin_" .. i ] + TurnWheel
|
||||
end
|
||||
else
|
||||
if RearWheelCanTurn then
|
||||
self.VehicleData[ "spin_" .. i ] = self.VehicleData[ "spin_" .. i ] + TurnWheel
|
||||
end
|
||||
end
|
||||
|
||||
if self.CustomWheels then
|
||||
local GhostEnt = self.GhostWheels[i]
|
||||
|
||||
if IsValid( GhostEnt ) then
|
||||
local Angle = GhostEnt:GetAngles()
|
||||
local offsetang = WheelPos.IsFrontWheel and self.CustomWheelAngleOffset or (self.CustomWheelAngleOffset_R or self.CustomWheelAngleOffset)
|
||||
local Direction = GhostEnt:LocalToWorldAngles( offsetang ):Forward()
|
||||
local TFront = FrontWheelCanTurn and TurnWheel or 0
|
||||
local TBack = RearWheelCanTurn and TurnWheel or 0
|
||||
|
||||
local AngleStep = WheelPos.IsFrontWheel and TFront or TBack
|
||||
Angle:RotateAroundAxis(Direction, WheelPos.IsRightWheel and AngleStep or -AngleStep)
|
||||
|
||||
self.GhostWheels[i]:SetAngles( Angle )
|
||||
end
|
||||
else
|
||||
self:SetPoseParameter(self.VehicleData[ "pp_spin_" .. i ],self.VehicleData[ "spin_" .. i ])
|
||||
end
|
||||
|
||||
if not self.PhysicsEnabled then
|
||||
Wheel:GetPhysicsObject():ApplyForceCenter( Force * 185 * OnGround )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:SetWheelVelocity( wVel )
|
||||
|
||||
local target_diff = math.max(LimitRPM * 0.95 - self.EngineRPM,0)
|
||||
|
||||
if self.FrontWheelPowered and self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_1" ] or 0,self.VehicleData[ "WheelRPM_2" ] or 0,self.VehicleData[ "WheelRPM_3" ] or 0,self.VehicleData[ "WheelRPM_4" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_1" ] or 0,self.VehicleData[ "GripLossFaktor_2" ] or 0,self.VehicleData[ "GripLossFaktor_3" ] or 0,self.VehicleData[ "GripLossFaktor_4" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_1" ] or 0,self.VehicleData[ "Exp_GLF_2" ] or 0,self.VehicleData[ "Exp_GLF_3" ] or 0,self.VehicleData[ "Exp_GLF_4" ] or 0)
|
||||
|
||||
elseif not self.FrontWheelPowered and self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_3" ] or 0,self.VehicleData[ "WheelRPM_4" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_3" ] or 0,self.VehicleData[ "GripLossFaktor_4" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_3" ] or 0,self.VehicleData[ "Exp_GLF_4" ] or 0)
|
||||
|
||||
elseif self.FrontWheelPowered and not self.RearWheelPowered then
|
||||
self.WheelRPM = math.max(self.VehicleData[ "WheelRPM_1" ] or 0,self.VehicleData[ "WheelRPM_2" ] or 0)
|
||||
self.RPM_DIFFERENCE = target_diff * math.max(self.VehicleData[ "GripLossFaktor_1" ] or 0,self.VehicleData[ "GripLossFaktor_2" ] or 0)
|
||||
self.exprpmdiff = target_diff * math.max(self.VehicleData[ "Exp_GLF_1" ] or 0,self.VehicleData[ "Exp_GLF_2" ] or 0)
|
||||
|
||||
else
|
||||
self.WheelRPM = 0
|
||||
self.RPM_DIFFERENCE = 0
|
||||
self.exprpmdiff = 0
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SimulateTurbo(LimitRPM)
|
||||
if not self.Turbo then return end
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
self.SmoothTurbo = self.SmoothTurbo + math.Clamp(math.min(self.EngineRPM / LimitRPM,1) * 600 * (0.75 + 0.25 * Throttle) - self.SmoothTurbo,-15,15)
|
||||
|
||||
local Volume = math.Clamp( ((self.SmoothTurbo - 300) / 150) ,0, 1) * 0.5
|
||||
local Pitch = math.Clamp( self.SmoothTurbo / 7 , 0 , 255)
|
||||
|
||||
local boost = math.Clamp( -0.25 + (self.SmoothTurbo / 500) ^ 5,0,1)
|
||||
|
||||
self.Turbo:ChangeVolume( Volume )
|
||||
self.Turbo:ChangePitch( Pitch )
|
||||
|
||||
return boost
|
||||
end
|
||||
|
||||
function ENT:SimulateBlower(LimitRPM)
|
||||
if not self.Blower or not self.BlowerWhine then return end
|
||||
|
||||
local Throttle = self:GetThrottle()
|
||||
|
||||
self.SmoothBlower = self.SmoothBlower + math.Clamp(math.min(self.EngineRPM / LimitRPM,1) * 500 - self.SmoothBlower,-20,20)
|
||||
|
||||
local Volume1 = math.Clamp( self.SmoothBlower / 400 * (1 - 0.4 * Throttle) ,0, 1)
|
||||
local Volume2 = math.Clamp( self.SmoothBlower / 400 * (0.10 + 0.4 * Throttle) ,0, 1)
|
||||
|
||||
local Pitch1 = 50 + math.Clamp( self.SmoothBlower / 4.5 , 0 , 205)
|
||||
local Pitch2 = Pitch1 * 1.2
|
||||
|
||||
local boost = math.Clamp( (self.SmoothBlower / 600) ^ 4 ,0,1)
|
||||
|
||||
self.Blower:ChangeVolume( Volume1 )
|
||||
self.Blower:ChangePitch( Pitch1 )
|
||||
|
||||
self.BlowerWhine:ChangeVolume( Volume2 )
|
||||
self.BlowerWhine:ChangePitch( Pitch2 )
|
||||
|
||||
return boost
|
||||
end
|
||||
710
lua/entities/gmod_sent_vehicle_fphysics_base/spawn.lua
Normal file
710
lua/entities/gmod_sent_vehicle_fphysics_base/spawn.lua
Normal file
@@ -0,0 +1,710 @@
|
||||
--[[
|
||||
| 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 function IsServerOK()
|
||||
|
||||
if GetConVar( "gmod_physiterations" ):GetInt() < 4 then
|
||||
RunConsoleCommand("gmod_physiterations", "4")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetNotSolid( true )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
--self:SetRenderMode( RENDERMODE_TRANSALPHA ) -- fix broken decals
|
||||
self:AddFlags( FL_OBJECT ) -- this allows npcs to see this entity
|
||||
|
||||
if not IsServerOK() then
|
||||
|
||||
self:Remove()
|
||||
|
||||
print("[SIMFPHYS] ERROR COULDN'T INITIALIZE VEHICLE!")
|
||||
end
|
||||
|
||||
local PObj = self:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PObj ) then print("[SIMFPHYS] ERROR COULDN'T INITIALIZE VEHICLE! '"..self:GetModel().."' has no physics model!") self:Remove() return end
|
||||
|
||||
PObj:EnableMotion( false )
|
||||
|
||||
self:SetValues()
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:InitializeVehicle()
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:PostEntityPaste( ply , ent , createdEntities )
|
||||
self:SetValues()
|
||||
|
||||
self:SetActive( false )
|
||||
self:SetDriver( NULL )
|
||||
self:SetLightsEnabled( false )
|
||||
self:SetLampsEnabled( false )
|
||||
self:SetFogLightsEnabled( false )
|
||||
|
||||
self:SetDriverSeat( NULL )
|
||||
self:SetFlyWheelRPM( 0 )
|
||||
self:SetThrottle( 0 )
|
||||
end
|
||||
|
||||
function ENT:UpdateTransmitState()
|
||||
return TRANSMIT_ALWAYS
|
||||
end
|
||||
|
||||
function ENT:SetupView()
|
||||
local AttachmentID = self:LookupAttachment( "vehicle_driver_eyes" )
|
||||
local AttachmentID2 = self:LookupAttachment( "vehicle_passenger0_eyes" )
|
||||
|
||||
local a_data1 = self:GetAttachment( AttachmentID )
|
||||
local a_data2 = self:GetAttachment( AttachmentID2 )
|
||||
|
||||
local ID
|
||||
local ViewPos
|
||||
|
||||
if a_data1 then
|
||||
ID = AttachmentID
|
||||
ViewPos = a_data1
|
||||
|
||||
elseif a_data2 then
|
||||
ID = AttachmentID2
|
||||
ViewPos = a_data2
|
||||
|
||||
else
|
||||
ID = false
|
||||
ViewPos = {Ang = self:LocalToWorldAngles( Angle(0, 90,0) ),Pos = self:GetPos()}
|
||||
end
|
||||
|
||||
local ViewAng = ViewPos.Ang - Angle(0,0,self.SeatPitch)
|
||||
ViewAng:RotateAroundAxis(self:GetUp(), -90 - (self.SeatYaw or 0))
|
||||
|
||||
local data = {
|
||||
ID = ID,
|
||||
ViewPos = ViewPos.Pos,
|
||||
ViewAng = ViewAng,
|
||||
}
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function ENT:SetupEnteringAnims()
|
||||
local attachments = self:GetAttachments()
|
||||
|
||||
self.Exitpoints = {}
|
||||
self.Enterpoints = {}
|
||||
|
||||
for _,i in pairs(attachments) do
|
||||
local curstring = string.lower( i.name )
|
||||
|
||||
if string.match( curstring, "exit", 1 ) then
|
||||
table.insert(self.Exitpoints, curstring)
|
||||
end
|
||||
|
||||
if string.match( curstring, "enter", 1 ) then
|
||||
table.insert(self.Enterpoints, curstring)
|
||||
end
|
||||
end
|
||||
|
||||
if table.Count( self.Enterpoints ) < 1 then
|
||||
self.Enterpoints = nil
|
||||
end
|
||||
|
||||
if table.Count( self.Exitpoints ) < 1 then
|
||||
self.Exitpoints = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:InitializeVehicle()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
local physObj = self:GetPhysicsObject()
|
||||
|
||||
if not IsValid( physObj ) then return end
|
||||
|
||||
if self.LightsTable then
|
||||
local vehiclelist = list.Get( "simfphys_lights" )[self.LightsTable] or false
|
||||
if vehiclelist then
|
||||
if vehiclelist.PoseParameters then
|
||||
self.LightsPP = vehiclelist.PoseParameters
|
||||
end
|
||||
|
||||
if vehiclelist.BodyGroups then
|
||||
self:SetBodygroup(vehiclelist.BodyGroups.Off[1], vehiclelist.BodyGroups.Off[2] )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
physObj:SetDragCoefficient( self.AirFriction or -250 )
|
||||
physObj:SetMass( self.Mass * 0.75 )
|
||||
|
||||
if self.Inertia then
|
||||
physObj:SetInertia( self.Inertia )
|
||||
end
|
||||
|
||||
local tanksize = self.FuelTankSize and self.FuelTankSize or 65
|
||||
local fueltype = self.FuelType and self.FuelType or FUELTYPE_PETROL
|
||||
|
||||
self:SetMaxFuel( tanksize )
|
||||
self:SetFuel( self:GetMaxFuel() )
|
||||
self:SetFuelType( fueltype )
|
||||
self:SetFuelPos( self.FuelFillPos and self.FuelFillPos or Vector(0,0,0) )
|
||||
|
||||
if fueltype ~= FUELTYPE_NONE then
|
||||
self:AddFuelTank()
|
||||
end
|
||||
|
||||
local View = self:SetupView()
|
||||
|
||||
self.DriverSeat = self:AddDriverSeat( self:WorldToLocal( View.ViewPos ), self:WorldToLocalAngles( View.ViewAng ) )
|
||||
self.DriverSeat:SetParent( NULL )
|
||||
self.DriverSeat:SetMoveType( MOVETYPE_NONE )
|
||||
self.DriverSeat:Spawn()
|
||||
self.DriverSeat:Activate()
|
||||
self.DriverSeat:SetPos( View.ViewPos + self.DriverSeat:GetUp() * (-34 + self.SeatOffset.z) + self.DriverSeat:GetRight() * (self.SeatOffset.y) + self.DriverSeat:GetForward() * (-6 + self.SeatOffset.x) )
|
||||
|
||||
if View.ID ~= false then
|
||||
self:SetupEnteringAnims()
|
||||
self.DriverSeat:SetParent( self , View.ID )
|
||||
else
|
||||
self.DriverSeat:SetParent( self )
|
||||
end
|
||||
|
||||
self.DriverSeat.fphysSeat = true
|
||||
self.DriverSeat.base = self
|
||||
|
||||
if self.PassengerSeats then
|
||||
for i = 1, table.Count( self.PassengerSeats ) do
|
||||
self.pSeat[i] = self:AddPassengerSeat( self.PassengerSeats[i].pos, self.PassengerSeats[i].ang )
|
||||
self.pSeat[i].fphysSeat = true
|
||||
self.pSeat[i].base = self
|
||||
end
|
||||
end
|
||||
|
||||
if istable(WireLib) then
|
||||
local passengersSeats = istable( self.pSeat ) and self.pSeat or {}
|
||||
WireLib.TriggerOutput(self, "PassengerSeats", passengersSeats )
|
||||
|
||||
WireLib.TriggerOutput(self, "DriverSeat", self.DriverSeat )
|
||||
end
|
||||
|
||||
if self.Attachments then
|
||||
for i = 1, table.Count( self.Attachments ) do
|
||||
local prop = ents.Create( "gmod_sent_vehicle_fphysics_attachment" )
|
||||
prop:SetModel( self.Attachments[i].model )
|
||||
prop:SetMaterial( self.Attachments[i].material )
|
||||
prop:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
prop:SetPos( self:LocalToWorld( self.Attachments[i].pos ) )
|
||||
prop:SetAngles( self:LocalToWorldAngles( self.Attachments[i].ang ) )
|
||||
prop:SetOwner( self )
|
||||
prop:Spawn()
|
||||
prop:Activate()
|
||||
prop:DrawShadow( true )
|
||||
prop:SetNotSolid( true )
|
||||
prop:SetParent( self )
|
||||
prop.DoNotDuplicate = true
|
||||
simfphys.SetOwner( self.EntityOwner, prop )
|
||||
|
||||
if self.Attachments[i].skin then
|
||||
prop:SetSkin( self.Attachments[i].skin )
|
||||
end
|
||||
|
||||
if self.Attachments[i].bodygroups then
|
||||
for b = 1, table.Count( self.Attachments[i].bodygroups ) do
|
||||
prop:SetBodygroup(b, self.Attachments[i].bodygroups[b] )
|
||||
end
|
||||
end
|
||||
|
||||
if self.Attachments[i].useVehicleColor == true then
|
||||
self.ColorableProps[i] = prop
|
||||
prop:SetColor( self:GetColor() )
|
||||
else
|
||||
prop:SetColor( self.Attachments[i].color or Color(255,255,255,255) )
|
||||
end
|
||||
|
||||
self:DeleteOnRemove( prop )
|
||||
end
|
||||
end
|
||||
|
||||
self:GetVehicleData()
|
||||
end
|
||||
|
||||
function ENT:GetVehicleData()
|
||||
self:SetPoseParameter("vehicle_steer",1)
|
||||
self:SetPoseParameter("vehicle_wheel_fl_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_fr_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_rl_height",1)
|
||||
self:SetPoseParameter("vehicle_wheel_rr_height",1)
|
||||
|
||||
timer.Simple( 0.15, function()
|
||||
if not IsValid(self) then return end
|
||||
self.posepositions["Pose0_Steerangle"] = self.CustomWheels and Angle(0,0,0) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Ang
|
||||
self.posepositions["Pose0_Pos_FL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFL ) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_FR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFR ) or self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_RL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRL ) or self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos
|
||||
self.posepositions["Pose0_Pos_RR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRR ) or self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos
|
||||
|
||||
self:WriteVehicleDataTable()
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:ResetJoystick()
|
||||
self.PressedKeys["joystick_steer_left"] = 0
|
||||
self.PressedKeys["joystick_steer_right"] = 0
|
||||
self.PressedKeys["joystick_brake"] = 0
|
||||
self.PressedKeys["joystick_throttle"] = 0
|
||||
self.PressedKeys["joystick_gearup"] = 0
|
||||
self.PressedKeys["joystick_geardown"] = 0
|
||||
self.PressedKeys["joystick_handbrake"] = 0
|
||||
self.PressedKeys["joystick_clutch"] = 0
|
||||
self.PressedKeys["joystick_air_w"] = 0
|
||||
self.PressedKeys["joystick_air_a"] = 0
|
||||
self.PressedKeys["joystick_air_s"] = 0
|
||||
self.PressedKeys["joystick_air_d"] = 0
|
||||
end
|
||||
|
||||
function ENT:SetValues()
|
||||
if istable( WireLib ) then
|
||||
self:createWireIO()
|
||||
end
|
||||
|
||||
self:SetGear( 2 )
|
||||
|
||||
self.WheelOnGroundDelay = 0
|
||||
self.SmoothAng = 0
|
||||
self.Steer = 0
|
||||
self.EngineIsOn = 0
|
||||
self.EngineTorque = 0
|
||||
|
||||
self.pSeat = {}
|
||||
self.exfx = {}
|
||||
self.Wheels = {}
|
||||
self.Elastics = {}
|
||||
self.GhostWheels = {}
|
||||
self.PressedKeys = {}
|
||||
self:ResetJoystick()
|
||||
|
||||
self.ColorableProps = {}
|
||||
self.posepositions = {}
|
||||
|
||||
self.HandBrakePower = 0
|
||||
self.DriveWheelsOnGround = 0
|
||||
self.WheelRPM = 0
|
||||
self.EngineRPM = 0
|
||||
self.RpmDiff = 0
|
||||
self.Torque = 0
|
||||
self.CurrentGear = 2
|
||||
self.GearUpPressed = 0
|
||||
self.GearDownPressed = 0
|
||||
self.RPM_DIFFERENCE = 0
|
||||
self.exprpmdiff = 0
|
||||
self.OldLockBrakes = 0
|
||||
self.ThrottleDelay = 0
|
||||
self.Brake = 0
|
||||
self.HandBrake = 0
|
||||
self.AutoClutch = 0
|
||||
self.NextShift = 0
|
||||
self.ForwardSpeed = 0
|
||||
self.EngineWasOn = 0
|
||||
self.SmoothTurbo = 0
|
||||
self.SmoothBlower = 0
|
||||
self.cc_speed = 0
|
||||
self.LightsActivated = false
|
||||
|
||||
self.VehicleData = {}
|
||||
for i = 1, 6 do
|
||||
self.VehicleData[ "spin_"..i ] = 0
|
||||
self.VehicleData[ "SurfaceMul_"..i ] = 1
|
||||
self.VehicleData[ "onGround_"..i ] = 0
|
||||
end
|
||||
|
||||
self.VehicleData[ "Steer" ] = 0
|
||||
end
|
||||
|
||||
function ENT:WriteVehicleDataTable()
|
||||
self:SetPoseParameter("vehicle_steer",0)
|
||||
self:SetPoseParameter("vehicle_wheel_fl_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_fr_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_rl_height",0)
|
||||
self:SetPoseParameter("vehicle_wheel_rr_height",0)
|
||||
|
||||
timer.Simple( 0.15, function()
|
||||
if not IsValid(self) then return end
|
||||
self.posepositions["Pose1_Steerangle"] = self.CustomWheels and Angle(0,0,0) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Ang
|
||||
self.posepositions["Pose1_Pos_FL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFL ) or self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_FR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosFR ) or self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_RL"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRL ) or self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos
|
||||
self.posepositions["Pose1_Pos_RR"] = self.CustomWheels and self:LocalToWorld( self.CustomWheelPosRR ) or self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos
|
||||
self.posepositions["PoseL_Pos_FL"] = self:WorldToLocal( self.posepositions.Pose1_Pos_FL )
|
||||
self.posepositions["PoseL_Pos_FR"] = self:WorldToLocal( self.posepositions.Pose1_Pos_FR )
|
||||
self.posepositions["PoseL_Pos_RL"] = self:WorldToLocal( self.posepositions.Pose1_Pos_RL )
|
||||
self.posepositions["PoseL_Pos_RR"] = self:WorldToLocal( self.posepositions.Pose1_Pos_RR )
|
||||
|
||||
self.VehicleData["suspensiontravel_fl"] = self.CustomWheels and self.FrontHeight or math.Round( (self.posepositions.Pose0_Pos_FL - self.posepositions.Pose1_Pos_FL):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_fr"] = self.CustomWheels and self.FrontHeight or math.Round( (self.posepositions.Pose0_Pos_FR - self.posepositions.Pose1_Pos_FR):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_rl"] = self.CustomWheels and self.RearHeight or math.Round( (self.posepositions.Pose0_Pos_RL - self.posepositions.Pose1_Pos_RL):Length() , 2)
|
||||
self.VehicleData["suspensiontravel_rr"] = self.CustomWheels and self.RearHeight or math.Round( (self.posepositions.Pose0_Pos_RR - self.posepositions.Pose1_Pos_RR):Length() , 2)
|
||||
|
||||
local Figure1 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Up():Dot(self.posepositions.Pose1_Steerangle:Up()),-1,1) ) * (180 / math.pi) , 2)
|
||||
local Figure2 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Forward():Dot(self.posepositions.Pose1_Steerangle:Forward()),-1,1) ) * (180 / math.pi) , 2)
|
||||
local Figure3 = math.Round( math.acos( math.Clamp(self.posepositions.Pose0_Steerangle:Right():Dot(self.posepositions.Pose1_Steerangle:Right()),-1,1) ) * (180 / math.pi) , 2)
|
||||
self.VehicleData["steerangle"] = self.CustomWheels and self.CustomSteerAngle or math.max(Figure1,Figure2,Figure3)
|
||||
|
||||
local pFL = self.posepositions.Pose0_Pos_FL
|
||||
local pFR = self.posepositions.Pose0_Pos_FR
|
||||
local pRL = self.posepositions.Pose0_Pos_RL
|
||||
local pRR = self.posepositions.Pose0_Pos_RR
|
||||
local pAngL = self:WorldToLocalAngles( ((pFL + pFR) / 2 - (pRL + pRR) / 2):Angle() )
|
||||
pAngL.r = 0
|
||||
pAngL.p = 0
|
||||
|
||||
self.VehicleData["LocalAngForward"] = pAngL
|
||||
|
||||
local yAngL = self.VehicleData.LocalAngForward - Angle(0,90,0)
|
||||
yAngL:Normalize()
|
||||
|
||||
self.VehicleData["LocalAngRight"] = yAngL
|
||||
self.VehicleData[ "pp_spin_1" ] = "vehicle_wheel_fl_spin"
|
||||
self.VehicleData[ "pp_spin_2" ] = "vehicle_wheel_fr_spin"
|
||||
self.VehicleData[ "pp_spin_3" ] = "vehicle_wheel_rl_spin"
|
||||
self.VehicleData[ "pp_spin_4" ] = "vehicle_wheel_rr_spin"
|
||||
|
||||
self.Turbo = CreateSound(self, "")
|
||||
self.Blower = CreateSound(self, "")
|
||||
self.BlowerWhine = CreateSound(self, "")
|
||||
self.BlowOff = CreateSound(self, "")
|
||||
|
||||
local Health = math.floor(self.MaxHealth ~= -1 and self.MaxHealth or (1000 + self:GetPhysicsObject():GetMass() / 3))
|
||||
self:SetMaxHealth( Health )
|
||||
self:SetCurHealth( Health )
|
||||
|
||||
self:SetAITEAM( self.AITEAM )
|
||||
|
||||
self:SetFastSteerAngle(self.FastSteeringAngle / self.VehicleData["steerangle"])
|
||||
self:SetNotSolid( false )
|
||||
self:SetupVehicle()
|
||||
end )
|
||||
end
|
||||
|
||||
function ENT:SetupVehicle()
|
||||
local BaseMass = self:GetPhysicsObject():GetMass()
|
||||
local MassCenterOffset = self.CustomMassCenter or Vector(0,0,0)
|
||||
local BaseMassCenter = self:LocalToWorld( self:GetPhysicsObject():GetMassCenter() - MassCenterOffset )
|
||||
|
||||
local OffsetMass = BaseMass * 0.25
|
||||
local CenterWheels = (self.posepositions["Pose1_Pos_FL"] + self.posepositions["Pose1_Pos_FR"] + self.posepositions["Pose1_Pos_RL"] + self.posepositions["Pose1_Pos_RR"]) / 4
|
||||
|
||||
local Sub = CenterWheels - BaseMassCenter
|
||||
local Dir = Sub:GetNormalized()
|
||||
local Dist = Sub:Length()
|
||||
local DistAdd = BaseMass * Dist / OffsetMass
|
||||
|
||||
local OffsetMassCenter = BaseMassCenter + Dir * (Dist + DistAdd)
|
||||
|
||||
self.MassOffset = ents.Create( "prop_physics" )
|
||||
self.MassOffset:SetModel( "models/hunter/plates/plate.mdl" )
|
||||
self.MassOffset:SetPos( OffsetMassCenter )
|
||||
self.MassOffset:SetAngles( Angle(0,0,0) )
|
||||
self.MassOffset:Spawn()
|
||||
self.MassOffset:Activate()
|
||||
self.MassOffset:GetPhysicsObject():EnableMotion(false)
|
||||
self.MassOffset:GetPhysicsObject():SetMass( OffsetMass )
|
||||
self.MassOffset:GetPhysicsObject():EnableDrag( false )
|
||||
self.MassOffset:SetOwner( self )
|
||||
self.MassOffset:DrawShadow( false )
|
||||
self.MassOffset:SetNotSolid( true )
|
||||
self.MassOffset:SetNoDraw( true )
|
||||
self.MassOffset.DoNotDuplicate = true
|
||||
simfphys.SetOwner( self.EntityOwner, self.MassOffset )
|
||||
|
||||
local weld = constraint.Weld(self.MassOffset,self, 0, 0, 0,true, true)
|
||||
weld.DoNotDuplicate = true
|
||||
|
||||
local ballsack = constraint.AdvBallsocket(self.MassOffset, self,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -0.01, -0.01, -0.01, 0.01, 0.01, 0.01, 0, 0, 0, 0, 1)
|
||||
ballsack.DoNotDuplicate = true
|
||||
|
||||
if self.CustomWheels then
|
||||
if self.CustomWheelModel then
|
||||
if not file.Exists( self.CustomWheelModel, "GAME" ) then
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" does not exist! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
if self.SteerFront ~= false then
|
||||
self.SteerMaster = ents.Create( "prop_physics" )
|
||||
self.SteerMaster:SetModel( self.CustomWheelModel )
|
||||
self.SteerMaster:SetPos( self:GetPos() )
|
||||
self.SteerMaster:SetAngles( self:GetAngles() )
|
||||
self.SteerMaster:Spawn()
|
||||
self.SteerMaster:Activate()
|
||||
|
||||
local pobj = self.SteerMaster:GetPhysicsObject()
|
||||
|
||||
if IsValid(pobj) then
|
||||
pobj:EnableMotion(false)
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" doesn't have an collision model! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self.SteerMaster:Remove()
|
||||
self:Remove()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self.SteerMaster:SetOwner( self )
|
||||
self.SteerMaster:DrawShadow( false )
|
||||
self.SteerMaster:SetNotSolid( true )
|
||||
self.SteerMaster:SetNoDraw( true )
|
||||
self.SteerMaster.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.SteerMaster )
|
||||
simfphys.SetOwner( self.EntityOwner, self.SteerMaster )
|
||||
end
|
||||
|
||||
if self.SteerRear then
|
||||
self.SteerMaster2 = ents.Create( "prop_physics" )
|
||||
self.SteerMaster2:SetModel( self.CustomWheelModel )
|
||||
self.SteerMaster2:SetPos( self:GetPos() )
|
||||
self.SteerMaster2:SetAngles( self:GetAngles() )
|
||||
self.SteerMaster2:Spawn()
|
||||
self.SteerMaster2:Activate()
|
||||
|
||||
local pobj = self.SteerMaster2:GetPhysicsObject()
|
||||
if IsValid(pobj) then
|
||||
pobj:EnableMotion(false)
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: \""..self.CustomWheelModel.."\" doesn't have an collision model! Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self.SteerMaster2:Remove()
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.SteerMaster2:SetOwner( self )
|
||||
self.SteerMaster2:DrawShadow( false )
|
||||
self.SteerMaster2:SetNotSolid( true )
|
||||
self.SteerMaster2:SetNoDraw( true )
|
||||
self.SteerMaster2.DoNotDuplicate = true
|
||||
self:DeleteOnRemove( self.SteerMaster2 )
|
||||
simfphys.SetOwner( self.EntityOwner, self.SteerMaster2 )
|
||||
end
|
||||
|
||||
local radius = IsValid(self.SteerMaster) and (self.SteerMaster:OBBMaxs() - self.SteerMaster:OBBMins()) or (self.SteerMaster2:OBBMaxs() - self.SteerMaster2:OBBMins())
|
||||
self.FrontWheelRadius = self.FrontWheelRadius or math.max( radius.x, radius.y, radius.z ) * 0.5
|
||||
self.RearWheelRadius = self.RearWheelRadius or self.FrontWheelRadius
|
||||
|
||||
self:CreateWheel(1, WheelFL, self:LocalToWorld( self.CustomWheelPosFL ), self.FrontHeight, self.FrontWheelRadius, false , self:LocalToWorld( self.CustomWheelPosFL + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(2, WheelFR, self:LocalToWorld( self.CustomWheelPosFR ), self.FrontHeight, self.FrontWheelRadius, true , self:LocalToWorld( self.CustomWheelPosFR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(3, WheelRL, self:LocalToWorld( self.CustomWheelPosRL ), self.RearHeight, self.RearWheelRadius, false , self:LocalToWorld( self.CustomWheelPosRL + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
self:CreateWheel(4, WheelRR, self:LocalToWorld( self.CustomWheelPosRR ), self.RearHeight, self.RearWheelRadius, true , self:LocalToWorld( self.CustomWheelPosRR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ), self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
|
||||
if self.CustomWheelPosML then
|
||||
self:CreateWheel(5, WheelML, self:LocalToWorld( self.CustomWheelPosML ), self.RearHeight, self.RearWheelRadius, false , self:LocalToWorld( self.CustomWheelPosML + Vector(0,0,self.CustomSuspensionTravel * 0.5) ),self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
|
||||
if self.CustomWheelPosMR then
|
||||
self:CreateWheel(6, WheelMR, self:LocalToWorld( self.CustomWheelPosMR ), self.RearHeight, self.RearWheelRadius, true , self:LocalToWorld( self.CustomWheelPosMR + Vector(0,0,self.CustomSuspensionTravel * 0.5) ), self.CustomSuspensionTravel, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
else
|
||||
if IsValid( self.EntityOwner ) then
|
||||
self.EntityOwner:PrintMessage( HUD_PRINTTALK, "ERROR: no wheel model defined. Removing vehicle. (Class: "..self:GetSpawn_List()..")")
|
||||
end
|
||||
self:Remove()
|
||||
end
|
||||
else
|
||||
self:CreateWheel(1, WheelFL, self:GetAttachment( self:LookupAttachment( "wheel_fl" ) ).Pos, self.FrontHeight, self.FrontWheelRadius, false , self.posepositions.Pose1_Pos_FL, self.VehicleData.suspensiontravel_fl, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(2, WheelFR, self:GetAttachment( self:LookupAttachment( "wheel_fr" ) ).Pos, self.FrontHeight, self.FrontWheelRadius, true , self.posepositions.Pose1_Pos_FR, self.VehicleData.suspensiontravel_fr, self.FrontConstant, self.FrontDamping, self.FrontRelativeDamping)
|
||||
self:CreateWheel(3, WheelRL, self:GetAttachment( self:LookupAttachment( "wheel_rl" ) ).Pos, self.RearHeight, self.RearWheelRadius, false , self.posepositions.Pose1_Pos_RL, self.VehicleData.suspensiontravel_rl, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
self:CreateWheel(4, WheelRR, self:GetAttachment( self:LookupAttachment( "wheel_rr" ) ).Pos, self.RearHeight, self.RearWheelRadius, true , self.posepositions.Pose1_Pos_RR, self.VehicleData.suspensiontravel_rr, self.RearConstant, self.RearDamping, self.RearRelativeDamping)
|
||||
end
|
||||
|
||||
timer.Simple( 0.01, function()
|
||||
if not istable( self.Wheels ) then return end
|
||||
|
||||
for i = 1, table.Count( self.Wheels ) do
|
||||
local Ent = self.Wheels[ i ]
|
||||
local PhysObj = Ent:GetPhysicsObject()
|
||||
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:EnableMotion( true )
|
||||
end
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
if not IsValid( self ) then return end
|
||||
|
||||
self:GetPhysicsObject():EnableMotion(true)
|
||||
|
||||
local PhysObj = self.MassOffset:GetPhysicsObject()
|
||||
if IsValid( PhysObj ) then
|
||||
PhysObj:EnableMotion(true)
|
||||
end
|
||||
end )
|
||||
end )
|
||||
|
||||
if istable( self.GibModels ) then
|
||||
for _, modelName in ipairs( self.GibModels ) do
|
||||
util.PrecacheModel( modelName )
|
||||
end
|
||||
end
|
||||
|
||||
self:OnSpawn()
|
||||
hook.Run( "simfphysOnSpawn", self )
|
||||
|
||||
self:SetlvsReady( true )
|
||||
|
||||
self.VehicleData["filter"] = self:GetCrosshairFilterEnts()
|
||||
end
|
||||
|
||||
function ENT:CreateWheel(index, name, attachmentpos, height, radius, swap_y , poseposition, suspensiontravel, constant, damping, rdamping)
|
||||
local fAng = self:LocalToWorldAngles( self.VehicleData.LocalAngForward )
|
||||
local rAng = self:LocalToWorldAngles( self.VehicleData.LocalAngRight )
|
||||
|
||||
local Forward = fAng:Forward()
|
||||
local Right = swap_y and -rAng:Forward() or rAng:Forward()
|
||||
local Up = self:GetUp()
|
||||
|
||||
local RopeLength = 150
|
||||
local LimiterLength = 60
|
||||
local LimiterRopeLength = math.sqrt( (suspensiontravel * 0.5) ^ 2 + LimiterLength ^ 2 )
|
||||
local WheelMass = self.Mass / 32
|
||||
|
||||
if self.FrontWheelMass and (index == 1 or index == 2) then
|
||||
WheelMass = self.FrontWheelMass
|
||||
end
|
||||
if self.RearWheelMass and (index == 3 or index == 4 or index == 5 or index == 6) then
|
||||
WheelMass = self.RearWheelMass
|
||||
end
|
||||
|
||||
self.name = ents.Create( "gmod_sent_vehicle_fphysics_wheel" )
|
||||
self.name:SetPos( attachmentpos - Up * height)
|
||||
self.name:SetAngles( fAng )
|
||||
self.name:Spawn()
|
||||
self.name:Activate()
|
||||
self.name:PhysicsInitSphere( radius, "jeeptire" )
|
||||
self.name:SetCollisionBounds( Vector(-radius,-radius,-radius), Vector(radius,radius,radius) )
|
||||
self.name:GetPhysicsObject():EnableMotion(false)
|
||||
self.name:GetPhysicsObject():SetMass( WheelMass )
|
||||
self.name:SetBaseEnt( self )
|
||||
simfphys.SetOwner( self.EntityOwner, self.name )
|
||||
self.name.EntityOwner = self.EntityOwner
|
||||
self.name.Index = index
|
||||
self.name.Radius = radius
|
||||
self.name:SetRadius( radius )
|
||||
|
||||
if self.CustomWheels then
|
||||
local Model = (self.CustomWheelModel_R and (index == 3 or index == 4 or index == 5 or index == 6)) and self.CustomWheelModel_R or self.CustomWheelModel
|
||||
local ghostAng = Right:Angle()
|
||||
local mirAng = swap_y and 1 or -1
|
||||
ghostAng:RotateAroundAxis(Forward,self.CustomWheelAngleOffset.p * mirAng)
|
||||
ghostAng:RotateAroundAxis(Right,self.CustomWheelAngleOffset.r * mirAng)
|
||||
ghostAng:RotateAroundAxis(Up,-self.CustomWheelAngleOffset.y)
|
||||
|
||||
local Camber = self.CustomWheelCamber or 0
|
||||
ghostAng:RotateAroundAxis(Forward, Camber * mirAng)
|
||||
|
||||
self.GhostWheels[index] = ents.Create( "gmod_sent_vehicle_fphysics_attachment" )
|
||||
self.GhostWheels[index]:SetModel( Model )
|
||||
self.GhostWheels[index]:SetPos( self.name:GetPos() )
|
||||
self.GhostWheels[index]:SetAngles( ghostAng )
|
||||
self.GhostWheels[index]:SetOwner( self )
|
||||
self.GhostWheels[index]:Spawn()
|
||||
self.GhostWheels[index]:Activate()
|
||||
self.GhostWheels[index]:SetNotSolid( true )
|
||||
self.GhostWheels[index].DoNotDuplicate = true
|
||||
self.GhostWheels[index]:SetParent( self.name )
|
||||
self:DeleteOnRemove( self.GhostWheels[index] )
|
||||
simfphys.SetOwner( self.EntityOwner, self.GhostWheels[index] )
|
||||
|
||||
self.GhostWheels[index]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
|
||||
if self.ModelInfo then
|
||||
if self.ModelInfo.WheelColor then
|
||||
self.GhostWheels[index]:SetColor( self.ModelInfo.WheelColor )
|
||||
end
|
||||
end
|
||||
|
||||
self.name.GhostEnt = self.GhostWheels[index]
|
||||
|
||||
local nocollide = constraint.NoCollide(self,self.name,0,0)
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
local targetentity = self
|
||||
if self.CustomWheels then
|
||||
if index == 1 or index == 2 then
|
||||
targetentity = self.SteerMaster or self
|
||||
end
|
||||
if index == 3 or index == 4 then
|
||||
targetentity = self.SteerMaster2 or self
|
||||
end
|
||||
end
|
||||
|
||||
local Ballsocket = constraint.AdvBallsocket(targetentity,self.name,0,0,Vector(0,0,0),Vector(0,0,0),0,0, -0.01, -0.01, -0.01, 0.01, 0.01, 0.01, 0, 0, 0, 1, 1)
|
||||
local Rope1 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( self.name:GetPos() + Forward * RopeLength * 0.5 + Right * RopeLength), Vector(0,0,0), Vector(RopeLength * 0.5,RopeLength,0):Length(), 0, 0, 0,"cable/cable2", true )
|
||||
local Rope2 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( self.name:GetPos() - Forward * RopeLength * 0.5 + Right * RopeLength), Vector(0,0,0), Vector(RopeLength * 0.5,RopeLength,0):Length(), 0, 0, 0,"cable/cable2", true )
|
||||
|
||||
if self.StrengthenSuspension == true then
|
||||
local Rope3 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 + Right * LimiterLength), Vector(0,0,0),LimiterRopeLength * 0.99, 0, 0, 0,"cable/cable2", false )
|
||||
local Rope4 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 - Right * LimiterLength), Vector(0,0,0),LimiterRopeLength * 1, 0, 0, 0,"cable/cable2", false )
|
||||
local elastic1 = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant * 0.5, damping * 0.5, rdamping * 0.5,"cable/cable2",0, false)
|
||||
local elastic2 = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant * 0.5, damping * 0.5, rdamping * 0.5,"cable/cable2",0, false)
|
||||
|
||||
Rope3.DoNotDuplicate = true
|
||||
Rope4.DoNotDuplicate = true
|
||||
elastic1.DoNotDuplicate = true
|
||||
elastic2.DoNotDuplicate = true
|
||||
self.Elastics[index] = elastic1
|
||||
self.Elastics[index * 10] = elastic2
|
||||
else
|
||||
local Rope3 = constraint.Rope(self,self.name,0,0,self:WorldToLocal( poseposition - Up * suspensiontravel * 0.5 + Right * LimiterLength), Vector(0,0,0),LimiterRopeLength, 0, 0, 0,"cable/cable2", false )
|
||||
local elastic = constraint.Elastic(self.name, self, 0, 0, Vector(0,0,height), self:WorldToLocal( self.name:GetPos() ), constant, damping, rdamping,"cable/cable2",0, false)
|
||||
|
||||
Rope3.DoNotDuplicate = true
|
||||
elastic.DoNotDuplicate = true
|
||||
self.Elastics[index] = elastic
|
||||
end
|
||||
|
||||
self.Wheels[index] = self.name
|
||||
|
||||
Ballsocket.DoNotDuplicate = true
|
||||
Rope1.DoNotDuplicate = true
|
||||
Rope2.DoNotDuplicate = true
|
||||
|
||||
if index == 2 then
|
||||
if IsValid( self.Wheels[ 1 ] ) and IsValid( self.Wheels[ 2 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 1 ], self.Wheels[ 2 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
elseif index == 4 then
|
||||
if IsValid( self.Wheels[ 3 ] ) and IsValid( self.Wheels[ 4 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 3 ], self.Wheels[ 4 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
|
||||
elseif index == 6 then
|
||||
if IsValid( self.Wheels[ 5 ] ) and IsValid( self.Wheels[ 6 ] ) then
|
||||
local nocollide = constraint.NoCollide( self.Wheels[ 5 ], self.Wheels[ 6 ], 0, 0 )
|
||||
nocollide.DoNotDuplicate = true
|
||||
end
|
||||
end
|
||||
end
|
||||
102
lua/entities/gmod_sent_vehicle_fphysics_fueltank.lua
Normal file
102
lua/entities/gmod_sent_vehicle_fphysics_fueltank.lua
Normal file
@@ -0,0 +1,102 @@
|
||||
--[[
|
||||
| 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.DoNotDuplicate = true
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar( "Entity",0, "Base" )
|
||||
end
|
||||
|
||||
function ENT:GetFuel()
|
||||
local veh = self:GetBase()
|
||||
|
||||
if not IsValid( veh ) then return 0 end
|
||||
|
||||
return veh:GetFuel() / veh:GetMaxFuel()
|
||||
end
|
||||
|
||||
function ENT:SetFuel( new )
|
||||
local veh = self:GetBase()
|
||||
|
||||
if not IsValid( veh ) then return end
|
||||
|
||||
veh:SetFuel( new * veh:GetMaxFuel() )
|
||||
end
|
||||
|
||||
function ENT:GetSize()
|
||||
local veh = self:GetBase()
|
||||
|
||||
if not IsValid( veh ) then return 0 end
|
||||
|
||||
return veh:GetMaxFuel()
|
||||
end
|
||||
|
||||
function ENT:GetFuelType()
|
||||
local veh = self:GetBase()
|
||||
|
||||
if not IsValid( veh ) then return -1 end
|
||||
|
||||
return veh:GetFuelType()
|
||||
end
|
||||
|
||||
function ENT:GetDoorHandler()
|
||||
return NULL
|
||||
end
|
||||
|
||||
function ENT:GetHP()
|
||||
return 100
|
||||
end
|
||||
|
||||
function ENT:GetMaxHP()
|
||||
return 100
|
||||
end
|
||||
|
||||
function ENT:GetDestroyed()
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_NONE )
|
||||
self:DrawShadow( false )
|
||||
debugoverlay.Cross( self:GetPos(), 20, 5, Color( 255, 93, 0 ) )
|
||||
end
|
||||
|
||||
function ENT:ExtinguishAndRepair()
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
self:NextThink( CurTime() + 1 )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
return false
|
||||
end
|
||||
103
lua/entities/gmod_sent_vehicle_fphysics_gib.lua
Normal file
103
lua/entities/gmod_sent_vehicle_fphysics_gib.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| 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.AdminSpawnable = false
|
||||
|
||||
if CLIENT then
|
||||
local Mat = CreateMaterial("simfphysdamage", "VertexLitGeneric", {["$basetexture"] = "models/player/player_chrome1"})
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
|
||||
render.ModelMaterialOverride( Mat )
|
||||
render.SetBlend( 0.8 )
|
||||
self:DrawModel()
|
||||
|
||||
render.ModelMaterialOverride()
|
||||
render.SetBlend(1)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
|
||||
if not IsValid( self:GetPhysicsObject() ) then
|
||||
self.RemoveTimer = 0
|
||||
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
local PhysObj = self:GetPhysicsObject()
|
||||
|
||||
PhysObj:EnableMotion(true)
|
||||
PhysObj:Wake()
|
||||
|
||||
self:SetCollisionGroup( COLLISION_GROUP_DEBRIS )
|
||||
self:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
|
||||
local fxPos = self:LocalToWorld( self:OBBCenter() )
|
||||
|
||||
timer.Simple( 0.05, function()
|
||||
if not IsValid( self ) then return end
|
||||
if self.MakeSound == true then
|
||||
self:Ignite( 30 )
|
||||
else
|
||||
local GibDir = Vector( math.Rand(-1,1), math.Rand(-1,1), 1.5 ):GetNormalized()
|
||||
PhysObj:SetVelocityInstantaneous( GibDir * math.random(800,1300) )
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( fxPos )
|
||||
effectdata:SetStart( PhysObj:GetMassCenter() )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetScale( math.Rand(0.3,0.7) )
|
||||
effectdata:SetMagnitude( math.Rand(0.5,2.5) )
|
||||
util.Effect( "lvs_firetrail", effectdata )
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
self.RemoveDis = GetConVar("sv_simfphys_gib_lifetime"):GetFloat()
|
||||
|
||||
self.RemoveTimer = CurTime() + self.RemoveDis
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if self.RemoveTimer < CurTime() then
|
||||
if self.RemoveDis > 0 then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink( CurTime() + 0.2 )
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if self.FireSound then
|
||||
self.FireSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
end
|
||||
end
|
||||
663
lua/entities/gmod_sent_vehicle_fphysics_wheel.lua
Normal file
663
lua/entities/gmod_sent_vehicle_fphysics_wheel.lua
Normal file
@@ -0,0 +1,663 @@
|
||||
--[[
|
||||
| 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.AdminSpawnable = false
|
||||
|
||||
ENT.DoNotDuplicate = true
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar( "Float", 0, "Radius")
|
||||
self:NetworkVar( "Float", 1, "OnGround" )
|
||||
self:NetworkVar( "Float", 2, "RPM" )
|
||||
self:NetworkVar( "Float", 3, "GripLoss" )
|
||||
self:NetworkVar( "Float", 4, "Speed" )
|
||||
self:NetworkVar( "Float", 5, "SkidSound" )
|
||||
self:NetworkVar( "String", 2, "SurfaceMaterial" )
|
||||
self:NetworkVar( "Bool", 1, "Damaged" )
|
||||
self:NetworkVar( "Entity", 1, "BaseEnt" )
|
||||
|
||||
if SERVER then
|
||||
self:NetworkVarNotify( "Damaged", self.OnDamaged )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetWidth()
|
||||
return 3
|
||||
end
|
||||
|
||||
function ENT:VelToRPM( speed )
|
||||
if not speed then return 0 end
|
||||
|
||||
return speed * 60 / math.pi / (self:GetRadius() * 2)
|
||||
end
|
||||
|
||||
function ENT:RPMToVel( rpm )
|
||||
if not rpm then return 0 end
|
||||
|
||||
return (math.pi * rpm * self:GetRadius() * 2) / 60
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel( "models/props_vehicles/tire001c_car.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
self:AddFlags( FL_OBJECT )
|
||||
self:AddEFlags( EFL_NO_PHYSCANNON_INTERACTION )
|
||||
|
||||
self:DrawShadow( false )
|
||||
|
||||
self.OldMaterial = ""
|
||||
self.OldMaterial2 = ""
|
||||
self.OldVar = 0
|
||||
self.OldVar2 = 0
|
||||
|
||||
local Color = self:GetColor()
|
||||
local dot = Color.r * Color.g * Color.b * Color.a
|
||||
self.OldColor = dot
|
||||
end
|
||||
|
||||
function ENT:Use( ply )
|
||||
local base = self:GetBaseEnt()
|
||||
|
||||
if not IsValid( base ) then return end
|
||||
|
||||
base:Use( ply )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if self.GhostEnt then
|
||||
local Color = self:GetColor()
|
||||
local dot = Color.r * Color.g * Color.b * Color.a
|
||||
if dot ~= self.OldColor then
|
||||
if IsValid( self.GhostEnt ) then
|
||||
self.GhostEnt:SetColor( Color )
|
||||
self.GhostEnt:SetRenderMode( self:GetRenderMode() )
|
||||
end
|
||||
self.OldColor = dot
|
||||
end
|
||||
end
|
||||
|
||||
self:NextThink( CurTime() + 0.15 )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:FixTire()
|
||||
self:SetDamaged( false )
|
||||
|
||||
if not self.PreBreak then return end
|
||||
|
||||
self.PreBreak:Stop()
|
||||
self.PreBreak = nil
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if self.PreBreak then
|
||||
self.PreBreak:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
if data.Speed > 100 and data.DeltaTime > 0.2 then
|
||||
if data.Speed > 400 then
|
||||
self:EmitSound( "Rubber_Tire.ImpactHard" )
|
||||
self:EmitSound( "simulated_vehicles/suspension_creak_".. math.random(1,6) ..".ogg" )
|
||||
else
|
||||
self:EmitSound( "Rubber.ImpactSoft" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
local BaseEnt = self:GetBaseEnt()
|
||||
|
||||
if IsValid( BaseEnt ) and dmginfo:IsDamageType( DMG_AIRBOAT + DMG_BULLET ) then
|
||||
BaseEnt:OnTakeDamage( dmginfo )
|
||||
end
|
||||
|
||||
if self:GetDamaged() or not simfphys.DamageEnabled then return end
|
||||
|
||||
local Damage = dmginfo:GetDamage()
|
||||
local DamagePos = dmginfo:GetDamagePosition()
|
||||
|
||||
if not IsValid( BaseEnt ) or BaseEnt:GetBulletProofTires() or Damage <= 1 then return end
|
||||
|
||||
if not self.PreBreak then
|
||||
self.PreBreak = CreateSound(self, "ambient/gas/cannister_loop.wav")
|
||||
self.PreBreak:PlayEx(0.5,100)
|
||||
|
||||
timer.Simple(math.Rand(0.5,5), function()
|
||||
if IsValid(self) and not self:GetDamaged() then
|
||||
self:SetDamaged( true )
|
||||
if self.PreBreak then
|
||||
self.PreBreak:Stop()
|
||||
self.PreBreak = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
else
|
||||
self:SetDamaged( true )
|
||||
self.PreBreak:Stop()
|
||||
self.PreBreak = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnDamaged( name, old, new)
|
||||
if new == old then return end
|
||||
|
||||
if new == true then
|
||||
self.dRadius = self:BoundingRadius() * 0.28
|
||||
|
||||
self:EmitSound( "simulated_vehicles/sfx/tire_break.ogg" )
|
||||
|
||||
if IsValid( self.GhostEnt ) then
|
||||
self.GhostEnt:SetParent( nil )
|
||||
self.GhostEnt:GetPhysicsObject():EnableMotion( false )
|
||||
self.GhostEnt:SetPos( self:LocalToWorld( Vector(0,0,-self.dRadius) ) )
|
||||
self.GhostEnt:SetParent( self )
|
||||
end
|
||||
else
|
||||
if IsValid( self.GhostEnt ) then
|
||||
self.GhostEnt:SetParent( nil )
|
||||
self.GhostEnt:GetPhysicsObject():EnableMotion( false )
|
||||
self.GhostEnt:SetPos( self:LocalToWorld( Vector(0,0,0) ) )
|
||||
self.GhostEnt:SetParent( self )
|
||||
end
|
||||
end
|
||||
|
||||
local BaseEnt = self:GetBaseEnt()
|
||||
|
||||
if not IsValid( BaseEnt ) then return end
|
||||
|
||||
BaseEnt:SetSuspension( self.Index , new )
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
ENT.SkidmarkTraceAdd = Vector(0,0,10)
|
||||
ENT.SkidmarkDelay = 0.05
|
||||
ENT.SkidmarkLifetime = 10
|
||||
|
||||
ENT.SkidmarkRed = 0
|
||||
ENT.SkidmarkGreen = 0
|
||||
ENT.SkidmarkBlue = 0
|
||||
ENT.SkidmarkAlpha = 150
|
||||
|
||||
ENT.SkidmarkSurfaces = {
|
||||
["concrete"] = true,
|
||||
["tile"] = true,
|
||||
["metal"] = true,
|
||||
["boulder"] = true,
|
||||
["default"] = true,
|
||||
}
|
||||
|
||||
ENT.DustEffectSurfaces = {
|
||||
["sand"] = true,
|
||||
["dirt"] = true,
|
||||
["grass"] = true,
|
||||
["antlionsand"] = true,
|
||||
}
|
||||
|
||||
function ENT:Initialize()
|
||||
self.FadeHeat = 0
|
||||
|
||||
timer.Simple( 0.01, function()
|
||||
if not IsValid( self ) then return end
|
||||
self.Radius = self:BoundingRadius()
|
||||
end)
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
self:ManageSmoke()
|
||||
|
||||
local T = CurTime()
|
||||
|
||||
if (self.fxTimer or 0) < T then
|
||||
self:CalcWheelSlip()
|
||||
|
||||
self.fxTimer = T + 0.1
|
||||
end
|
||||
|
||||
self:SetNextClientThink( CurTime() + 0.005 )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:ManageSmoke()
|
||||
local BaseEnt = self:GetBaseEnt()
|
||||
|
||||
if not IsValid( BaseEnt ) then return end
|
||||
|
||||
if LocalPlayer():GetPos():DistToSqr(self:GetPos()) > 6000 * 6000 or not BaseEnt:GetActive() then return end
|
||||
|
||||
local WheelOnGround = self:GetOnGround()
|
||||
local GripLoss = self:GetGripLoss()
|
||||
local Material = self:GetSurfaceMaterial()
|
||||
|
||||
if WheelOnGround > 0 and (Material == "concrete" or Material == "rock" or Material == "tile") and GripLoss > 0 then
|
||||
self.FadeHeat = math.Clamp( self.FadeHeat + GripLoss * 0.06,0,10)
|
||||
else
|
||||
self.FadeHeat = self.FadeHeat * 0.995
|
||||
end
|
||||
|
||||
local Scale = self.FadeHeat ^ 3 * 0.001
|
||||
local SmokeOn = (self.FadeHeat >= 7)
|
||||
local DirtOn = GripLoss > 0.05
|
||||
local lcolor = BaseEnt:GetTireSmokeColor() * 255
|
||||
local Speed = self:GetVelocity():Length()
|
||||
local OnRim = self:GetDamaged()
|
||||
|
||||
local Forward = self:GetForward()
|
||||
local Dir = (BaseEnt:GetGear() < 2) and Forward or -Forward
|
||||
|
||||
local WheelSize = self.Radius or 0
|
||||
local Pos = self:GetPos()
|
||||
|
||||
if SmokeOn and not OnRim then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos )
|
||||
effectdata:SetNormal( Dir )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetRadius( WheelSize )
|
||||
effectdata:SetStart( Vector( lcolor.r, lcolor.g, lcolor.b ) )
|
||||
util.Effect( "simfphys_tiresmoke", effectdata )
|
||||
end
|
||||
|
||||
if WheelOnGround == 0 then return end
|
||||
|
||||
if (Speed > 150 or DirtOn) and OnRim then
|
||||
self:MakeSparks( GripLoss, Dir, Pos, WheelSize )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:MakeSparks( Scale, Dir, Pos, WheelSize )
|
||||
self.NextSpark = self.NextSpark or 0
|
||||
|
||||
if self.NextSpark < CurTime() then
|
||||
|
||||
self.NextSpark = CurTime() + 0.1
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( Pos - Vector(0,0,WheelSize * 0.5) )
|
||||
effectdata:SetNormal( (Dir + Vector(0,0,0.5)) * Scale * 0.5)
|
||||
util.Effect( "manhacksparks", effectdata, true, true )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
self:CalcWheelEffects()
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
self:StopWheelEffects()
|
||||
end
|
||||
|
||||
function ENT:CalcWheelSlip()
|
||||
local Base = self:GetBaseEnt()
|
||||
|
||||
if not IsValid( Base ) then return end
|
||||
|
||||
local Vel = self:GetVelocity()
|
||||
local VelLength = Vel:Length()
|
||||
|
||||
local rpmTheoretical = self:VelToRPM( VelLength )
|
||||
local rpm = math.abs( self:GetRPM() )
|
||||
|
||||
self._WheelSlip = math.max( rpm - rpmTheoretical - 250, 0 ) ^ 2 + math.max( math.abs( Base:VectorSplitNormal( self:GetRight(), Vel * 4 ) ) - VelLength, 0 )
|
||||
self._WheelSkid = VelLength + self._WheelSlip
|
||||
end
|
||||
|
||||
function ENT:GetSlip()
|
||||
return (self._WheelSlip or 0)
|
||||
end
|
||||
|
||||
function ENT:GetSkid()
|
||||
return (self._WheelSkid or 0)
|
||||
end
|
||||
|
||||
|
||||
function ENT:StopWheelEffects()
|
||||
if not self._DoingWheelFx then return end
|
||||
|
||||
self._DoingWheelFx = nil
|
||||
|
||||
self:FinishSkidmark()
|
||||
end
|
||||
|
||||
function ENT:StartWheelEffects( Base, trace, traceWater )
|
||||
self:DoWheelEffects( Base, trace, traceWater )
|
||||
|
||||
if self._DoingWheelFx then return end
|
||||
|
||||
self._DoingWheelFx = true
|
||||
end
|
||||
|
||||
function ENT:DoWheelEffects( Base, trace, traceWater )
|
||||
if not trace.Hit then self:FinishSkidmark() return end
|
||||
|
||||
local SurfacePropName = util.GetSurfacePropName( trace.SurfaceProps )
|
||||
local SkidValue = self:GetSkid()
|
||||
|
||||
if traceWater.Hit then
|
||||
local Scale = math.min( 0.3 + (SkidValue - 100) / 4000, 1 ) ^ 2
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetEntity( Base )
|
||||
effectdata:SetNormal( trace.HitNormal )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetFlags( 1 )
|
||||
util.Effect( "simfphys_physics_wheeldust", effectdata, true, true )
|
||||
|
||||
self:FinishSkidmark()
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self.SkidmarkSurfaces[ SurfacePropName ] then
|
||||
local Scale = math.min( 0.3 + SkidValue / 4000, 1 ) ^ 2
|
||||
|
||||
if Scale > 0.2 then
|
||||
self:StartSkidmark( trace.HitPos )
|
||||
self:CalcSkidmark( trace, Base:GetCrosshairFilterEnts() )
|
||||
else
|
||||
self:FinishSkidmark()
|
||||
end
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetEntity( Base )
|
||||
effectdata:SetNormal( trace.HitNormal )
|
||||
util.Effect( "simfphys_physics_wheelsmoke", effectdata, true, true )
|
||||
else
|
||||
self:FinishSkidmark()
|
||||
end
|
||||
|
||||
if not LVS.ShowEffects then return end
|
||||
|
||||
if self.DustEffectSurfaces[ SurfacePropName ] then
|
||||
local Scale = math.min( 0.3 + (SkidValue - 100) / 4000, 1 ) ^ 2
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetEntity( Base )
|
||||
effectdata:SetNormal( trace.HitNormal )
|
||||
effectdata:SetMagnitude( Scale )
|
||||
effectdata:SetFlags( 0 )
|
||||
util.Effect( "simfphys_physics_wheeldust", effectdata, true, true )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:CalcWheelEffects()
|
||||
local T = CurTime()
|
||||
|
||||
if (self._NextFx or 0) > T then return end
|
||||
|
||||
self._NextFx = T + 0.05
|
||||
|
||||
local Base = self:GetBaseEnt()
|
||||
|
||||
if not IsValid( Base ) then return end
|
||||
|
||||
local Radius = Base:GetUp() * (self:GetRadius() + 1)
|
||||
|
||||
local Pos = self:GetPos() + self:GetVelocity() * 0.025
|
||||
local StartPos = Pos + Radius
|
||||
local EndPos = Pos - Radius
|
||||
|
||||
local trace = util.TraceLine( {
|
||||
start = StartPos,
|
||||
endpos = EndPos,
|
||||
filter = Base:GetCrosshairFilterEnts(),
|
||||
} )
|
||||
|
||||
local traceWater = util.TraceLine( {
|
||||
start = StartPos,
|
||||
endpos = EndPos,
|
||||
filter = Base:GetCrosshairFilterEnts(),
|
||||
mask = MASK_WATER,
|
||||
} )
|
||||
|
||||
self:CalcWheelSounds( Base, trace, traceWater )
|
||||
|
||||
if traceWater.Hit and trace.HitPos.z < traceWater.HitPos.z then
|
||||
if math.abs( self:GetRPM() ) > 25 then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( traceWater.Fraction > 0.5 and traceWater.HitPos or Pos )
|
||||
effectdata:SetEntity( Base )
|
||||
effectdata:SetMagnitude( self:BoundingRadius() )
|
||||
effectdata:SetFlags( 0 )
|
||||
util.Effect( "simfphys_physics_wheelwatersplash", effectdata )
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetSlip() < 500 or self:GetDamaged() then self:StopWheelEffects() return end
|
||||
|
||||
self:StartWheelEffects( Base, trace, traceWater )
|
||||
end
|
||||
|
||||
function ENT:CalcWheelSounds( Base, trace, traceWater )
|
||||
if not trace.Hit then return end
|
||||
|
||||
-- TODO: fix reason for this workaround
|
||||
if trace.Entity == self then
|
||||
if istable( Base.CrosshairFilterEnts ) and #Base.CrosshairFilterEnts > 1 then
|
||||
Base.CrosshairFilterEnts = nil
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local RPM = math.abs( self:GetRPM() )
|
||||
|
||||
if RPM > 50 then
|
||||
if traceWater.Hit then
|
||||
Base:DoTireSound( "roll_wet" )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetDamaged() then
|
||||
Base:DoTireSound( "roll_damaged" )
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local surface = self.DustEffectSurfaces[ util.GetSurfacePropName( trace.SurfaceProps ) ] and "_dirt" or ""
|
||||
local snd_type = (self:GetSlip() > 500) and "skid" or "roll"
|
||||
|
||||
if (istable( StormFox ) or istable( StormFox2 )) and surface ~= "_dirt" then
|
||||
local Rain = false
|
||||
|
||||
if StormFox then
|
||||
Rain = StormFox.IsRaining()
|
||||
end
|
||||
|
||||
if StormFox2 then
|
||||
Rain = StormFox2.Weather:IsRaining()
|
||||
end
|
||||
|
||||
if Rain then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetEntity( Base )
|
||||
effectdata:SetMagnitude( self:BoundingRadius() )
|
||||
effectdata:SetFlags( 1 )
|
||||
util.Effect( "lvs_physics_wheelwatersplash", effectdata )
|
||||
|
||||
Base:DoTireSound( snd_type.."_wet" )
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
Base:DoTireSound( snd_type..surface )
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetSkidMarks()
|
||||
if not istable( self._activeSkidMarks ) then
|
||||
self._activeSkidMarks = {}
|
||||
end
|
||||
|
||||
return self._activeSkidMarks
|
||||
end
|
||||
|
||||
function ENT:StartSkidmark( pos )
|
||||
if self:GetWidth() <= 0 or self._SkidMarkID or not LVS.ShowTraileffects then return end
|
||||
|
||||
local ID = 1
|
||||
for _,_ in ipairs( self:GetSkidMarks() ) do
|
||||
ID = ID + 1
|
||||
end
|
||||
|
||||
self._activeSkidMarks[ ID ] = {
|
||||
active = true,
|
||||
startpos = pos + self.SkidmarkTraceAdd,
|
||||
delay = CurTime() + self.SkidmarkDelay,
|
||||
positions = {},
|
||||
}
|
||||
|
||||
self._SkidMarkID = ID
|
||||
end
|
||||
|
||||
function ENT:FinishSkidmark()
|
||||
if not self._SkidMarkID then return end
|
||||
|
||||
self._activeSkidMarks[ self._SkidMarkID ].active = false
|
||||
|
||||
self._SkidMarkID = nil
|
||||
end
|
||||
|
||||
function ENT:RemoveSkidmark( id )
|
||||
if not id then return end
|
||||
|
||||
self._activeSkidMarks[ id ] = nil
|
||||
end
|
||||
|
||||
function ENT:CalcSkidmark( trace, Filter )
|
||||
local T = CurTime()
|
||||
local CurActive = self:GetSkidMarks()[ self._SkidMarkID ]
|
||||
|
||||
if not CurActive or not CurActive.active or CurActive.delay >= T then return end
|
||||
|
||||
CurActive.delay = T + self.SkidmarkDelay
|
||||
|
||||
local W = self:GetWidth()
|
||||
|
||||
local cur = trace.HitPos + self.SkidmarkTraceAdd * 0.5
|
||||
|
||||
local prev = CurActive.positions[ #CurActive.positions ]
|
||||
|
||||
if not prev then
|
||||
local sub = cur - CurActive.startpos
|
||||
|
||||
local L = sub:Length() * 0.5
|
||||
local C = (cur + CurActive.startpos) * 0.5
|
||||
|
||||
local Ang = sub:Angle()
|
||||
local Forward = Ang:Right()
|
||||
local Right = Ang:Forward()
|
||||
|
||||
local p1 = C + Forward * W + Right * L
|
||||
local p2 = C - Forward * W + Right * L
|
||||
|
||||
local t1 = util.TraceLine( { start = p1, endpos = p1 - self.SkidmarkTraceAdd } )
|
||||
local t2 = util.TraceLine( { start = p2, endpos = p2 - self.SkidmarkTraceAdd } )
|
||||
|
||||
prev = {
|
||||
px = CurActive.startpos,
|
||||
p1 = t1.HitPos + t1.HitNormal,
|
||||
p2 = t2.HitPos + t2.HitNormal,
|
||||
lifetime = T + self.SkidmarkLifetime - self.SkidmarkDelay,
|
||||
alpha = 0,
|
||||
}
|
||||
end
|
||||
|
||||
local sub = cur - prev.px
|
||||
|
||||
local L = sub:Length() * 0.5
|
||||
local C = (cur + prev.px) * 0.5
|
||||
|
||||
local Ang = sub:Angle()
|
||||
local Forward = Ang:Right()
|
||||
local Right = Ang:Forward()
|
||||
|
||||
local p1 = C + Forward * W + Right * L
|
||||
local p2 = C - Forward * W + Right * L
|
||||
|
||||
local t1 = util.TraceLine( { start = p1, endpos = p1 - self.SkidmarkTraceAdd, filter = Filter, } )
|
||||
local t2 = util.TraceLine( { start = p2, endpos = p2 - self.SkidmarkTraceAdd, filter = Filter, } )
|
||||
|
||||
local nextID = #CurActive.positions + 1
|
||||
|
||||
CurActive.positions[ nextID ] = {
|
||||
px = cur,
|
||||
p1 = t1.HitPos + t1.HitNormal,
|
||||
p2 = t2.HitPos + t2.HitNormal,
|
||||
lifetime = T + self.SkidmarkLifetime,
|
||||
alpha = math.min( nextID / 10, 1 ),
|
||||
}
|
||||
end
|
||||
|
||||
function ENT:RenderSkidMarks()
|
||||
local T = CurTime()
|
||||
|
||||
for id, skidmark in pairs( self:GetSkidMarks() ) do
|
||||
local prev
|
||||
local AmountDrawn = 0
|
||||
|
||||
for markID, data in pairs( skidmark.positions ) do
|
||||
if not prev then
|
||||
|
||||
prev = data
|
||||
|
||||
continue
|
||||
end
|
||||
|
||||
local Mul = math.max( data.lifetime - CurTime(), 0 ) / self.SkidmarkLifetime
|
||||
|
||||
if Mul > 0 then
|
||||
AmountDrawn = AmountDrawn + 1
|
||||
render.DrawQuad( data.p2, data.p1, prev.p1, prev.p2, Color( self.SkidmarkRed, self.SkidmarkGreen, self.SkidmarkBlue, math.min(255 * Mul * data.alpha,self.SkidmarkAlpha) ) )
|
||||
end
|
||||
|
||||
prev = data
|
||||
end
|
||||
|
||||
if not skidmark.active and AmountDrawn == 0 then
|
||||
self:RemoveSkidmark( id )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add( "PreDrawTranslucentRenderables", "!!!!lvs_fakephysics_skidmarks", function( bDepth, bSkybox )
|
||||
if bSkybox then return end
|
||||
|
||||
render.SetColorMaterial()
|
||||
|
||||
for _, wheel in ipairs( ents.FindByClass("gmod_sent_vehicle_fphysics_wheel") ) do
|
||||
wheel:RenderSkidMarks()
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,30 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- StormFox2 E2 extension
|
||||
-- Created by Nak
|
||||
|
||||
-- Time
|
||||
E2Helper.Descriptions["sfTime()"] = "Returns the time as a number between 0 and 1439"
|
||||
E2Helper.Descriptions["isNight()"] = "Is it night?"
|
||||
E2Helper.Descriptions["isDay()"] = "Is it day?"
|
||||
E2Helper.Descriptions["sfTimeDisplay()"] = "Returns the time as a 24h string"
|
||||
E2Helper.Descriptions["sfTimeDisplay12h()"] = "Returns the time as a 12h string"
|
||||
|
||||
-- Weather
|
||||
E2Helper.Descriptions["isRaining()"] = "Is it raining?"
|
||||
E2Helper.Descriptions["isSnowing()"] = "Is it snowing?"
|
||||
E2Helper.Descriptions["isThundering()"] = "Is it thundering?"
|
||||
E2Helper.Descriptions["getWeather()"] = "Returns the description of the current weahter"
|
||||
E2Helper.Descriptions["getWeatherPercent()"] = "Returns the weather amount between [0-1]"
|
||||
|
||||
-- Wind
|
||||
E2Helper.Descriptions["getWind()"] = "Returns the wind in m/s"
|
||||
E2Helper.Descriptions["getWindBeaufort()"] = "Returns the wind in Beaufort scale"
|
||||
79
lua/entities/gmod_wire_expression2/core/custom/stormfox2.lua
Normal file
79
lua/entities/gmod_wire_expression2/core/custom/stormfox2.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- StormFox2 E2 extension
|
||||
-- By Nak
|
||||
|
||||
E2Lib.RegisterExtension("stormfox2", true, "Lets E2 chips use StormFox functions")
|
||||
|
||||
__e2setcost( 3 )
|
||||
|
||||
-- Time
|
||||
e2function number sfTime()
|
||||
return StormFox2.Time.Get()
|
||||
end
|
||||
e2function number isNight()
|
||||
return StormFox2.Time.IsNight() and 1 or 0
|
||||
end
|
||||
e2function number isDay()
|
||||
return StormFox2.Time.IsDay() and 1 or 0
|
||||
end
|
||||
|
||||
__e2setcost( 15 )
|
||||
e2function string sfTimeDisplay()
|
||||
return StormFox2.Time.TimeToString(nil)
|
||||
end
|
||||
|
||||
e2function string sfTimeDisplay12h()
|
||||
return StormFox2.Time.TimeToString(nil,true)
|
||||
end
|
||||
|
||||
-- Weather
|
||||
__e2setcost( 7 )
|
||||
local function isRaining()
|
||||
local wD = StormFox2.Weather.GetCurrent()
|
||||
return wD.Name == "Rain" or wD.Inherit == "Rain"
|
||||
end
|
||||
local function isCold()
|
||||
return StormFox2.Temperature.Get() <= -2
|
||||
end
|
||||
|
||||
e2function number isRaining()
|
||||
if isCold() then return 0 end
|
||||
return isRaining() and 1 or 0
|
||||
end
|
||||
|
||||
e2function number isSnowing()
|
||||
if not isCold() then return 0 end
|
||||
return isRaining() and 1 or 0
|
||||
end
|
||||
|
||||
e2function number isThundering()
|
||||
return StormFox2.Thunder.IsThundering() and 1 or 0
|
||||
end
|
||||
|
||||
__e2setcost( 10 )
|
||||
e2function string getWeather()
|
||||
return StormFox2.Weather.GetDescription()
|
||||
end
|
||||
|
||||
e2function number getWeatherPercent()
|
||||
return StormFox2.Weather.GetPercent()
|
||||
end
|
||||
-- Wind
|
||||
__e2setcost( 3 )
|
||||
e2function number getWind()
|
||||
return StormFox2.Wind.GetForce()
|
||||
end
|
||||
|
||||
__e2setcost( 10 )
|
||||
e2function number getWindBeaufort()
|
||||
return StormFox2.Wind.GetBeaufort()
|
||||
end
|
||||
102
lua/entities/ladder_base/shared.lua
Normal file
102
lua/entities/ladder_base/shared.lua
Normal file
@@ -0,0 +1,102 @@
|
||||
--[[
|
||||
| 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 (SERVER) then
|
||||
AddCSLuaFile();
|
||||
end;
|
||||
|
||||
DEFINE_BASECLASS("base_entity");
|
||||
|
||||
ENT.PrintName = "Ladder (BASE)";
|
||||
ENT.Category = "Ladders";
|
||||
ENT.Spawnable = false;
|
||||
ENT.AdminOnly = false;
|
||||
ENT.Model = Model("models/props_c17/metalladder001.mdl");
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH;
|
||||
|
||||
if (SERVER) then
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel(self.Model);
|
||||
self:SetSolid(SOLID_VPHYSICS);
|
||||
self:PhysicsInit(SOLID_VPHYSICS);
|
||||
self:SetUseType(SIMPLE_USE);
|
||||
self:SetCollisionGroup(COLLISION_GROUP_WEAPON);
|
||||
local phys = self:GetPhysicsObject();
|
||||
|
||||
if (IsValid(phys)) then
|
||||
phys:EnableMotion(false);
|
||||
end;
|
||||
|
||||
self:UpdateLadder(true);
|
||||
end;
|
||||
|
||||
function ENT:UpdateLadder(bCreate)
|
||||
if (bCreate) then
|
||||
local oldAngs = self:GetAngles();
|
||||
|
||||
self:SetAngles(Angle(0, 0, 0));
|
||||
|
||||
local pos = self:GetPos();
|
||||
local dist = self:OBBMaxs().x + 17;
|
||||
local dismountDist = self:OBBMaxs().x + 49;
|
||||
local bottom = self:LocalToWorld(Vector(0, 0, self:OBBMins().z));
|
||||
local top = self:LocalToWorld(Vector(0, 0, self:OBBMaxs().z));
|
||||
|
||||
for k, v in pairs(self:GetChildren()) do
|
||||
SafeRemoveEntity(v);
|
||||
end;
|
||||
|
||||
self.ladder = ents.Create("func_useableladder");
|
||||
self.ladder:SetPos(pos + self:GetForward() * dist);
|
||||
self.ladder:SetKeyValue("point0", tostring(bottom + self:GetForward() * dist));
|
||||
self.ladder:SetKeyValue("point1", tostring(top + self:GetForward() * dist));
|
||||
self.ladder:SetKeyValue("targetname", "zladder_" .. self:EntIndex());
|
||||
self.ladder:SetParent(self);
|
||||
self.ladder:Spawn();
|
||||
|
||||
self.bottomDismount = ents.Create("info_ladder_dismount");
|
||||
self.bottomDismount:SetPos(bottom + self:GetForward() * dismountDist);
|
||||
self.bottomDismount:SetKeyValue("laddername", "zladder_" .. self:EntIndex());
|
||||
self.bottomDismount:SetParent(self);
|
||||
self.bottomDismount:Spawn();
|
||||
|
||||
self.topDismount = ents.Create("info_ladder_dismount");
|
||||
self.topDismount:SetPos(top - self:GetForward() * dist);
|
||||
self.topDismount:SetKeyValue("laddername", "zladder_" .. self:EntIndex());
|
||||
self.topDismount:SetParent(self);
|
||||
self.topDismount:Spawn();
|
||||
|
||||
self.ladder:Activate();
|
||||
|
||||
self:SetAngles(oldAngs);
|
||||
else
|
||||
self.ladder:Activate();
|
||||
end;
|
||||
end;
|
||||
|
||||
function ENT:Think()
|
||||
if (IsValid(self.ladder)) then
|
||||
self:UpdateLadder();
|
||||
self:NextThink(CurTime() + 1);
|
||||
return true;
|
||||
end;
|
||||
end;
|
||||
|
||||
elseif (CLIENT) then
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetSolid(SOLID_VPHYSICS);
|
||||
end;
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel();
|
||||
end;
|
||||
end;
|
||||
22
lua/entities/ladder_small/shared.lua
Normal file
22
lua/entities/ladder_small/shared.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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 (SERVER) then
|
||||
AddCSLuaFile();
|
||||
end;
|
||||
|
||||
ENT.Type = "anim";
|
||||
ENT.Base = "ladder_base";
|
||||
ENT.PrintName = "Ladder (Small)"
|
||||
ENT.Category = "Ladders"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.Model = Model("models/props_c17/metalladder001.mdl");
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH;
|
||||
22
lua/entities/ladder_small2/shared.lua
Normal file
22
lua/entities/ladder_small2/shared.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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 (SERVER) then
|
||||
AddCSLuaFile();
|
||||
end;
|
||||
|
||||
ENT.Type = "anim";
|
||||
ENT.Base = "ladder_base";
|
||||
ENT.PrintName = "Ladder (Small - Attached)"
|
||||
ENT.Category = "Ladders"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.Model = Model("models/props_c17/metalladder002.mdl");
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH;
|
||||
22
lua/entities/ladder_small3/shared.lua
Normal file
22
lua/entities/ladder_small3/shared.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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 (SERVER) then
|
||||
AddCSLuaFile();
|
||||
end;
|
||||
|
||||
ENT.Type = "anim";
|
||||
ENT.Base = "ladder_base";
|
||||
ENT.PrintName = "Ladder (Small - Runged)"
|
||||
ENT.Category = "Ladders"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.Model = Model("models/props/cs_militia/ladderrung.mdl");
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH;
|
||||
22
lua/entities/ladder_small4/shared.lua
Normal file
22
lua/entities/ladder_small4/shared.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| 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 (SERVER) then
|
||||
AddCSLuaFile();
|
||||
end;
|
||||
|
||||
ENT.Type = "anim";
|
||||
ENT.Base = "ladder_base";
|
||||
ENT.PrintName = "Ladder (Small - Wood)"
|
||||
ENT.Category = "Ladders"
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.Model = Model("models/props/cs_militia/ladderwood.mdl");
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH;
|
||||
46
lua/entities/logic_day_relay.lua
Normal file
46
lua/entities/logic_day_relay.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
A day relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
|
||||
ENT.PrintName = "logic_day_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when it is daytime"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
--[[
|
||||
0 : "When lightlvl change."
|
||||
1 : "When it turns day."
|
||||
]]
|
||||
function ENT:GetTriggerType()
|
||||
return self.trigger_type or 0
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "trigger_type" then
|
||||
self.trigger_type = tonumber(v)
|
||||
end
|
||||
end
|
||||
46
lua/entities/logic_night_relay.lua
Normal file
46
lua/entities/logic_night_relay.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
A night relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
|
||||
ENT.PrintName = "logic_night_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when it is daytime"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
--[[
|
||||
0 : "When lightlvl change."
|
||||
1 : "When it turns night."
|
||||
]]
|
||||
function ENT:GetTriggerType()
|
||||
return self.trigger_type or 0
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "trigger_type" then
|
||||
self.trigger_type = tonumber(v)
|
||||
end
|
||||
end
|
||||
88
lua/entities/logic_temperature_relay.lua
Normal file
88
lua/entities/logic_temperature_relay.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
--[[
|
||||
| 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 temperature relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
|
||||
ENT.PrintName = "logic_temperature_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when temperature is within"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
self.triggered = false
|
||||
self.bake = false
|
||||
end
|
||||
|
||||
--[[
|
||||
0 : "When lightlvl change."
|
||||
1 : "When it turns day."
|
||||
]]
|
||||
function ENT:GetTriggerType()
|
||||
return self.trigger_type or 0
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "temperature_type" then
|
||||
--[[[
|
||||
0 : "Celsius"
|
||||
1 : "Fahrenheit"
|
||||
2 : "Kelvin"
|
||||
]]
|
||||
self.temperature_type = tonumber(v)
|
||||
elseif k == "temperature_min" then
|
||||
self.temperature_min = tonumber(v)
|
||||
elseif k == "temperature_max" then
|
||||
self.temperature_max = tonumber(v)
|
||||
end
|
||||
end
|
||||
|
||||
-- Converts the temperatures into celcius, so we don't have to keep converting.
|
||||
function ENT:Bake()
|
||||
if self.bake then return end
|
||||
if self.temperature_type == 1 then
|
||||
self.temperature_min = StormFox2.Temperature.Convert("fahrenheit","celsius",self.temperature_min)
|
||||
self.temperature_max = StormFox2.Temperature.Convert("fahrenheit","celsius",self.temperature_max)
|
||||
elseif temperature_type == 2 then
|
||||
self.temperature_min = StormFox2.Temperature.Convert("kelvin","celsius",self.temperature_min)
|
||||
self.temperature_max = StormFox2.Temperature.Convert("kelvin","celsius",self.temperature_max)
|
||||
end
|
||||
self.bake = true
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if not StormFox2 or not StormFox2.Loaded then return end
|
||||
self:Bake() -- Convert variables
|
||||
local c = StormFox2.Temperature.Get()
|
||||
if not self.triggered then
|
||||
if c >= self.temperature_min and c <= self.temperature_max then
|
||||
self:Trigger()
|
||||
self.triggered = true
|
||||
end
|
||||
else
|
||||
if c < self.temperature_min or c > self.temperature_max then
|
||||
self.triggered = false
|
||||
end
|
||||
end
|
||||
self:NextThink( CurTime() + 3 )
|
||||
return true
|
||||
end
|
||||
69
lua/entities/logic_thunder_relay.lua
Normal file
69
lua/entities/logic_thunder_relay.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
--[[
|
||||
| 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 thunder relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
|
||||
ENT.PrintName = "logic_thunder_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when thunder gets turned on/off"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
self.triggered = false
|
||||
end
|
||||
|
||||
--[[
|
||||
0 : "Starts thundering."
|
||||
1 : "Stops thundering."
|
||||
]]
|
||||
function ENT:GetTriggerType()
|
||||
return self.trigger_type or 0
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "trigger_type" then
|
||||
self.trigger_type = tonumber(v)
|
||||
if self.trigger_type == 1 then
|
||||
self.triggered = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if not StormFox2 or not StormFox2.Loaded then return end
|
||||
local b = StormFox2.Thunder.IsThundering()
|
||||
local c = self:GetTriggerType() == 0 -- True if we want to trigger doing thunder
|
||||
local on = b == c
|
||||
if not self.triggered then
|
||||
if on then
|
||||
self:Trigger()
|
||||
self.triggered = true
|
||||
end
|
||||
else
|
||||
if not on then
|
||||
self.triggered = false
|
||||
end
|
||||
end
|
||||
self:NextThink( CurTime() + 6 )
|
||||
return true
|
||||
end
|
||||
58
lua/entities/logic_time_relay.lua
Normal file
58
lua/entities/logic_time_relay.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
A temperature relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
|
||||
ENT.PrintName = "logic_time_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when time is within settings"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
self.triggered = false
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "time_min" then
|
||||
self.time_min = StormFox2.Time.StringToTime(v)
|
||||
elseif k == "time_max" then
|
||||
self.time_max = StormFox2.Time.StringToTime(v)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if not StormFox2 or not StormFox2.Loaded then return end
|
||||
local c = StormFox2.Time.Get()
|
||||
if not self.triggered then
|
||||
if StormFox2.Time.IsBetween(self.time_min, self.time_max, c) then
|
||||
self:Trigger()
|
||||
self.triggered = true
|
||||
end
|
||||
else
|
||||
if not StormFox2.Time.IsBetween(self.time_min, self.time_max, c) then
|
||||
self.triggered = false
|
||||
end
|
||||
end
|
||||
self:NextThink( CurTime() + 3 )
|
||||
return true
|
||||
end
|
||||
46
lua/entities/logic_weather_off_relay.lua
Normal file
46
lua/entities/logic_weather_off_relay.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
A weather relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
ENT.Base = "base_point"
|
||||
|
||||
ENT.PrintName = "logic_weather_off_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when weather turned off"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
self.triggered = false
|
||||
end
|
||||
|
||||
function ENT:GetRequiredWeather()
|
||||
return self.weather_type
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "weather_type" then
|
||||
self.weather_type = string.lower(v)
|
||||
elseif k == "weather_amount" then
|
||||
self.weather_amount = tonumber(v)
|
||||
end
|
||||
end
|
||||
65
lua/entities/logic_weather_relay.lua
Normal file
65
lua/entities/logic_weather_relay.lua
Normal 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/
|
||||
--]]
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
A weather relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
ENT.Base = "base_point"
|
||||
|
||||
ENT.PrintName = "logic_weather_relay"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Gets fired when weather turned on"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
self.triggered = false
|
||||
end
|
||||
|
||||
function ENT:HasRequredAmount()
|
||||
if self.weather_type == "clear" then return true end -- Doesn't matter when it is 'Clear'.
|
||||
local a = self.weather_amount or 1
|
||||
local p = StormFox2.Data.GetFinal("w_Percentage") or 0
|
||||
if a == 0 then
|
||||
return p > 0
|
||||
elseif a == 1 then
|
||||
return p >= 0.1
|
||||
elseif a == 2 then
|
||||
return p >= 0.25
|
||||
elseif a == 3 then
|
||||
return p >= 0.50
|
||||
elseif a == 4 then
|
||||
return p >= 0.75
|
||||
else
|
||||
return p >= 1
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetRequiredWeather()
|
||||
return self.weather_type or "clear"
|
||||
end
|
||||
|
||||
function ENT:Trigger()
|
||||
self:TriggerOutput("OnTrigger")
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "OnTrigger" then
|
||||
self:StoreOutput( k, v )
|
||||
elseif k == "weather_type" then
|
||||
self.weather_type = string.lower(v)
|
||||
elseif k == "weather_amount" then
|
||||
self.weather_amount = tonumber(v)
|
||||
end
|
||||
end
|
||||
83
lua/entities/logic_weather_set.lua
Normal file
83
lua/entities/logic_weather_set.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
--[[
|
||||
| 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 weather relay
|
||||
---------------------------------------------------------------------------]]
|
||||
ENT.Type = "point"
|
||||
ENT.Base = "base_point"
|
||||
|
||||
ENT.PrintName = "logic_weather_set"
|
||||
ENT.Author = "Nak"
|
||||
ENT.Information = "Allows the map to set weather"
|
||||
ENT.Category = "StormFox2"
|
||||
|
||||
ENT.Editable = false
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
function ENT:KeyValue( k, v )
|
||||
if k == "weather_type" then
|
||||
local n = string.lower(v)
|
||||
n = n:sub(0, 1):upper() .. n:sub(2)
|
||||
self.weather_type = n
|
||||
elseif k == "weather_amount" then
|
||||
self.weather_amount = math.Clamp(tonumber(v), 0, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:GetWeather()
|
||||
return self.weather_type or "Clear", self.weather_amount or 0.8
|
||||
end
|
||||
|
||||
local delay = 0
|
||||
function ENT:TriggerWeather()
|
||||
if delay > CurTime() then return false end
|
||||
local w, p = self:GetWeather()
|
||||
StormFox2.Weather.Set(w, p)
|
||||
delay = CurTime() + 1.5
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:AcceptInput( name, activator, caller, data )
|
||||
if name == "SetWeather" then
|
||||
self:TriggerWeather()
|
||||
return true
|
||||
elseif name == "SetTemperature" then
|
||||
local num = tonumber(string.match(data or "0", "[-%d]+") or 0)
|
||||
local t = string.match(data:lower(), "[fck]") or "c"
|
||||
if t == 'k' then
|
||||
num = StormFox2.Temperature.Convert("kelvin", "celsius")
|
||||
elseif t == 'f' then
|
||||
num = StormFox2.Temperature.Convert("fahrenheit", "celsius")
|
||||
end
|
||||
StormFox2.Temperature.Set(num, 2)
|
||||
return true
|
||||
elseif name == "EnableThunder" then
|
||||
StormFox2.Thunder.SetEnabled(true)
|
||||
return true
|
||||
elseif name == "DisableThunder" then
|
||||
StormFox2.Thunder.SetEnabled(false)
|
||||
return true
|
||||
elseif name == "ClearWeather" then
|
||||
StormFox2.Weather.Set("Clear")
|
||||
elseif name == "SetWind" then
|
||||
StormFox2.Wind.SetForce( tonumber(data or "0") or 0, 2 )
|
||||
elseif name == "SetWindYaw" then
|
||||
local n = tonumber(data or "0") or 0
|
||||
StormFox2.Wind.SetYaw( math.Clamp(n,0,360) )
|
||||
elseif name == "ClearWeather" then
|
||||
StormFox2.Weather.Set("Clear")
|
||||
end
|
||||
return false
|
||||
end
|
||||
239
lua/entities/lvs_armor.lua
Normal file
239
lua/entities/lvs_armor.lua
Normal file
@@ -0,0 +1,239 @@
|
||||
--[[
|
||||
| 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.DoNotDuplicate = true
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar( "Entity",0, "Base" )
|
||||
|
||||
self:NetworkVar( "Float",0, "HP" )
|
||||
self:NetworkVar( "Float",1, "MaxHP" )
|
||||
self:NetworkVar( "Float",2, "IgnoreForce" )
|
||||
|
||||
self:NetworkVar( "Vector",0, "Mins" )
|
||||
self:NetworkVar( "Vector",1, "Maxs" )
|
||||
|
||||
self:NetworkVar( "Bool",0, "Destroyed" )
|
||||
|
||||
self:NetworkVar( "String",0, "Label" )
|
||||
|
||||
if SERVER then
|
||||
self:SetMaxHP( 100 )
|
||||
self:SetHP( 100 )
|
||||
self:SetLabel( "Armor Plate" )
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetMoveType( MOVETYPE_NONE )
|
||||
self:SetSolid( SOLID_NONE )
|
||||
self:DrawShadow( false )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
return false
|
||||
end
|
||||
|
||||
function ENT:OnHealthChanged( dmginfo, old, new )
|
||||
if old == new then return end
|
||||
end
|
||||
|
||||
function ENT:OnRepaired()
|
||||
end
|
||||
|
||||
function ENT:OnDestroyed( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:TakeTransmittedDamage( dmginfo )
|
||||
local Force = dmginfo:GetDamageForce()
|
||||
|
||||
local Damage = dmginfo:GetDamage()
|
||||
local DamageForce = Force:Length()
|
||||
|
||||
local CurHealth = self:GetHP()
|
||||
|
||||
local pos = dmginfo:GetDamagePosition()
|
||||
local dir = Force:GetNormalized()
|
||||
|
||||
local trace = util.TraceLine( {
|
||||
start = pos - dir * 20,
|
||||
endpos = pos + dir * 20,
|
||||
} )
|
||||
|
||||
local DotHitNormal = math.Clamp( trace.HitNormal:Dot( dir ) ,-1,1)
|
||||
|
||||
local Armor = self:GetIgnoreForce()
|
||||
local ArmorEffective = Armor / math.abs( DotHitNormal )
|
||||
|
||||
if math.abs( DotHitNormal ) > 0.9 then
|
||||
ArmorEffective = Armor
|
||||
end
|
||||
|
||||
local DisableBounce = false
|
||||
|
||||
local Inflictor = dmginfo:GetInflictor()
|
||||
|
||||
if IsValid( Inflictor ) then
|
||||
if Inflictor.DisableBallistics or Inflictor:IsNPC() or Inflictor:IsNextBot() then
|
||||
DisableBounce = true
|
||||
end
|
||||
end
|
||||
|
||||
if DamageForce <= ArmorEffective then
|
||||
local T = CurTime()
|
||||
|
||||
if trace.Entity ~= self:GetBase() then
|
||||
self._NextBounce = T + 1
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local Ax = math.acos( DotHitNormal )
|
||||
local HitAngle = 90 - (180 - math.deg( Ax ))
|
||||
|
||||
if HitAngle > 20 then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetNormal( -dir )
|
||||
util.Effect( "manhacksparks", effectdata, true, true )
|
||||
|
||||
self._NextBounce = T + 1
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local NewDir = dir - trace.HitNormal * math.cos( Ax ) * 2
|
||||
|
||||
if (self._NextBounce or 0) > T or DisableBounce then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( trace.HitPos )
|
||||
effectdata:SetNormal( NewDir:GetNormalized() * 0.25 )
|
||||
util.Effect( "manhacksparks", effectdata, true, true )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
self._NextBounce = T + 1
|
||||
|
||||
local hit_decal = ents.Create( "lvs_armor_bounce" )
|
||||
hit_decal:SetPos( trace.HitPos )
|
||||
hit_decal:SetAngles( NewDir:Angle() )
|
||||
hit_decal:Spawn()
|
||||
hit_decal:Activate()
|
||||
hit_decal:EmitSound("lvs/armor_rico"..math.random(1,6)..".wav", 95, 100, math.min( dmginfo:GetDamage() / 1000, 1 ) )
|
||||
|
||||
local PhysObj = hit_decal:GetPhysicsObject()
|
||||
if not IsValid( PhysObj ) then return false end
|
||||
|
||||
PhysObj:EnableDrag( false )
|
||||
PhysObj:SetVelocityInstantaneous( NewDir * 2000 + Vector(0,0,250) )
|
||||
PhysObj:SetAngleVelocityInstantaneous( VectorRand() * 250 )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local NewHealth = math.Clamp( CurHealth - Damage, 0, self:GetMaxHP() )
|
||||
|
||||
self:OnHealthChanged( dmginfo, CurHealth, NewHealth )
|
||||
self:SetHP( NewHealth )
|
||||
|
||||
local hit_decal = ents.Create( "lvs_armor_penetrate" )
|
||||
hit_decal:SetPos( trace.HitPos )
|
||||
hit_decal:SetAngles( trace.HitNormal:Angle() + Angle(90,0,0) )
|
||||
hit_decal:Spawn()
|
||||
hit_decal:Activate()
|
||||
hit_decal:SetParent( trace.Entity )
|
||||
|
||||
if not self:GetDestroyed() then
|
||||
self:SetDestroyed( true )
|
||||
self:OnDestroyed( dmginfo )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
end
|
||||
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
|
||||
local function DrawText( pos, text, col )
|
||||
cam.Start2D()
|
||||
local data2D = pos:ToScreen()
|
||||
|
||||
if not data2D.visible then return end
|
||||
|
||||
local font = "TargetIDSmall"
|
||||
|
||||
local x = data2D.x
|
||||
local y = data2D.y
|
||||
|
||||
draw.DrawText( text, font, x + 1, y + 1, Color( 0, 0, 0, 120 ), TEXT_ALIGN_CENTER )
|
||||
draw.DrawText( text, font, x + 2, y + 2, Color( 0, 0, 0, 50 ), TEXT_ALIGN_CENTER )
|
||||
draw.DrawText( text, font, x, y, col or color_white, TEXT_ALIGN_CENTER )
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
local LVS = LVS
|
||||
local BoxMat = Material("models/wireframe")
|
||||
local ColorSelect = Color(0,127,255,150)
|
||||
local ColorNormal = Color(50,50,50,150)
|
||||
local ColorTransBlack = Color(0,0,0,150)
|
||||
local OutlineThickness = Vector(0.5,0.5,0.5)
|
||||
local ColorText = Color(255,0,0,255)
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
if not LVS.DeveloperEnabled then return end
|
||||
|
||||
local ply = LocalPlayer()
|
||||
|
||||
if not IsValid( ply ) or ply:InVehicle() or not ply:KeyDown( IN_SPEED ) then return end
|
||||
|
||||
local boxOrigin = self:GetPos()
|
||||
local boxAngles = self:GetAngles()
|
||||
local boxMins = self:GetMins()
|
||||
local boxMaxs = self:GetMaxs()
|
||||
|
||||
local HitPos, _, _ = util.IntersectRayWithOBB( ply:GetShootPos(), ply:GetAimVector() * 1000, boxOrigin, boxAngles, boxMins, boxMaxs )
|
||||
|
||||
local InRange = isvector( HitPos )
|
||||
|
||||
local Col = InRange and ColorSelect or ColorNormal
|
||||
|
||||
render.SetColorMaterial()
|
||||
render.DrawBox( boxOrigin, boxAngles, boxMins, boxMaxs, Col )
|
||||
render.DrawBox( boxOrigin, boxAngles, boxMaxs + OutlineThickness, boxMins - OutlineThickness, ColorTransBlack )
|
||||
|
||||
local boxCenter = (self:LocalToWorld( boxMins ) + self:LocalToWorld( boxMaxs )) * 0.5
|
||||
|
||||
if not InRange then return end
|
||||
|
||||
DrawText( boxCenter, "Armor: "..(self:GetIgnoreForce() / 100).."mm\nHealth:"..self:GetHP().."/"..self:GetMaxHP(), ColorText )
|
||||
end
|
||||
134
lua/entities/lvs_armor_bounce.lua
Normal file
134
lua/entities/lvs_armor_bounce.lua
Normal file
@@ -0,0 +1,134 @@
|
||||
--[[
|
||||
| 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 = "88mm Round"
|
||||
ENT.Author = "Luna"
|
||||
ENT.Information = "Luna's Vehicle Script"
|
||||
ENT.Category = "[LVS] - Cars - Items"
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
|
||||
ENT.LifeTime = 10
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:SetModel( "models/misc/88mm_projectile.mdl" )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:PhysicsInit( SOLID_VPHYSICS)
|
||||
|
||||
self.DieTime = CurTime() + self.LifeTime
|
||||
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if self.MarkForRemove then self:Remove() return false end
|
||||
|
||||
self:NextThink( CurTime() + 0.1 )
|
||||
|
||||
if (self.DieTime or 0) > CurTime() then return true end
|
||||
|
||||
self:Remove()
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
self.MarkForRemove = true
|
||||
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( data.HitPos )
|
||||
effectdata:SetNormal( -data.HitNormal )
|
||||
effectdata:SetMagnitude( 0.5 )
|
||||
util.Effect( "lvs_bullet_impact", effectdata )
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
ENT.MatSmoke = {
|
||||
"particle/smokesprites_0001",
|
||||
"particle/smokesprites_0002",
|
||||
"particle/smokesprites_0003",
|
||||
"particle/smokesprites_0004",
|
||||
"particle/smokesprites_0005",
|
||||
"particle/smokesprites_0006",
|
||||
"particle/smokesprites_0007",
|
||||
"particle/smokesprites_0008",
|
||||
"particle/smokesprites_0009",
|
||||
"particle/smokesprites_0010",
|
||||
"particle/smokesprites_0011",
|
||||
"particle/smokesprites_0012",
|
||||
"particle/smokesprites_0013",
|
||||
"particle/smokesprites_0014",
|
||||
"particle/smokesprites_0015",
|
||||
"particle/smokesprites_0016"
|
||||
}
|
||||
|
||||
function ENT:Initialize()
|
||||
self.DieTime = CurTime() + self.LifeTime
|
||||
|
||||
self.emitter = ParticleEmitter( self:GetPos(), false )
|
||||
end
|
||||
|
||||
function ENT:Smoke()
|
||||
local T = CurTime()
|
||||
|
||||
if (self.DieTime or 0) < T then return end
|
||||
|
||||
if not self.emitter then return end
|
||||
|
||||
if (self.NextFX or 0) < T then
|
||||
self.NextFX = T + 0.02
|
||||
|
||||
local Timed = 1 - (self.DieTime - T) / self.LifeTime
|
||||
local Scale = math.max(math.min(2 - Timed * 2,1),0)
|
||||
|
||||
local Pos = self:GetPos()
|
||||
|
||||
local particle = self.emitter:Add( self.MatSmoke[math.random(1,#self.MatSmoke)], Pos )
|
||||
|
||||
local VecCol = (render.GetLightColor( Pos ) * 0.8 + Vector(0.2,0.2,0.2)) * 255
|
||||
|
||||
if particle then
|
||||
particle:SetVelocity( VectorRand() * 10 )
|
||||
particle:SetDieTime( math.Rand(0.5,1) )
|
||||
particle:SetAirResistance( 100 )
|
||||
particle:SetStartAlpha( 100 * Scale )
|
||||
particle:SetEndAlpha( 0 )
|
||||
particle:SetStartSize( 10 )
|
||||
particle:SetEndSize( 20 )
|
||||
particle:SetRollDelta( 1 )
|
||||
particle:SetColor( VecCol.r, VecCol.g, VecCol.b )
|
||||
particle:SetGravity( Vector( 0, 0, 200 ) )
|
||||
particle:SetCollide( false )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
self:Smoke()
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if not self.emitter then return end
|
||||
|
||||
self.emitter:Finish()
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user