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

View File

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

View 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

View 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
View 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

View 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"

View 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"

View 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"

View 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"

View 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"

View 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"

View 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"

View 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"

View File

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

View File

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

View 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"

View File

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

View File

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

View 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"

View 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"

View 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"

View File

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

View 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

View 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

View File

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

View 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
]]

View 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

View File

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

View 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

View File

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

View 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

View File

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

View File

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

View 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

View 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

View 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

View File

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

View 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

View 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

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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
View File

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

View 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

View 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

View 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"

View 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"

View 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"

View File

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

View File

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

View 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

View 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

View File

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

View 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

View 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

View 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

View 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

View 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

View File

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

View 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

View 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

View 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

View File

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

View 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.
]]

View 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

View File

@@ -0,0 +1,16 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
include( "shared.lua" )
function ENT:Draw()
self.BaseClass.Draw(self)
self.Entity:DrawModel()
end

View 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 )

View File

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

View File

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

View File

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

View 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

View File

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

View 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

File diff suppressed because it is too large Load Diff

View File

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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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/
--]]
-- 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"

View File

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

View 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;

View 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;

View 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;

View 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;

View 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;

View File

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

View File

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

View 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

View 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

View File

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

View File

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

View File

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

View 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
View 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

View 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