310 lines
6.9 KiB
Lua
310 lines
6.9 KiB
Lua
AddCSLuaFile()
|
|
DEFINE_BASECLASS( "base_wire_entity" )
|
|
ENT.PrintName = "Wire Thruster"
|
|
ENT.RenderGroup = RENDERGROUP_BOTH -- TODO: this is only needed when they're active.
|
|
ENT.WireDebugName = "Thruster"
|
|
|
|
WireLib.ThrusterNetEffects = {
|
|
["fire_smoke"] = true
|
|
}
|
|
|
|
function ENT:SetEffect( name )
|
|
self:SetNWString( "Effect", name )
|
|
self.neteffect = WireLib.ThrusterNetEffects[ name ]
|
|
end
|
|
function ENT:GetEffect( name )
|
|
return self:GetNWString( "Effect" )
|
|
end
|
|
|
|
function ENT:SetOn( boolon )
|
|
self:SetNWBool( "On", boolon, true )
|
|
end
|
|
function ENT:IsOn( name )
|
|
return self:GetNWBool( "On" )
|
|
end
|
|
|
|
function ENT:SetOffset( v )
|
|
self:SetNWVector( "Offset", v, true )
|
|
end
|
|
function ENT:GetOffset( name )
|
|
return self:GetNWVector( "Offset" )
|
|
end
|
|
|
|
|
|
if CLIENT then
|
|
function ENT:Initialize()
|
|
self.ShouldDraw = 1
|
|
self.EffectAvg = 0
|
|
|
|
local mx, mn = self:GetRenderBounds()
|
|
self:SetRenderBounds(mn + Vector(0,0,128), mx, 0)
|
|
end
|
|
|
|
function ENT:DrawTranslucent()
|
|
if self.ShouldDraw == 0 or not self:IsOn() then return end
|
|
|
|
local EffectDraw = WireLib.ThrusterEffectDraw[self:GetEffect()]
|
|
if EffectDraw then EffectDraw(self) end
|
|
end
|
|
|
|
function ENT:Think()
|
|
BaseClass.Think(self)
|
|
|
|
self.ShouldDraw = GetConVarNumber("cl_drawthrusterseffects")
|
|
|
|
if self.ShouldDraw == 0 or not self:IsOn() then return end
|
|
|
|
local EffectThink = WireLib.ThrusterEffectThink[self:GetEffect()]
|
|
if EffectThink then EffectThink(self) end
|
|
end
|
|
|
|
function ENT:CalcNormal()
|
|
return (self:LocalToWorld(self:GetOffset()) - self:GetPos()):GetNormalized()
|
|
end
|
|
|
|
return -- No more client
|
|
end
|
|
|
|
-- Server
|
|
|
|
function ENT:Initialize()
|
|
self:PhysicsInit( SOLID_VPHYSICS )
|
|
self:SetMoveType( MOVETYPE_VPHYSICS )
|
|
self:SetSolid( SOLID_VPHYSICS )
|
|
|
|
self:DrawShadow( false )
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if (phys:IsValid()) then
|
|
phys:Wake()
|
|
end
|
|
|
|
local max = self:OBBMaxs()
|
|
local min = self:OBBMins()
|
|
|
|
self.ThrustOffset = Vector( 0, 0, max.z )
|
|
self.ThrustOffsetR = Vector( 0, 0, min.z )
|
|
self.ForceAngle = self.ThrustOffset:GetNormalized() * -1
|
|
|
|
self:SetForce( 2000 )
|
|
|
|
self.oweffect = "fire"
|
|
self.uweffect = "same"
|
|
|
|
self:SetOffset( self.ThrustOffset )
|
|
self:StartMotionController()
|
|
|
|
self:Switch( false )
|
|
|
|
self.Inputs = Wire_CreateInputs(self, { "A" })
|
|
|
|
self.soundname = Sound( "PhysicsCannister.ThrusterLoop" )
|
|
end
|
|
|
|
function ENT:OnRemove()
|
|
BaseClass.OnRemove(self)
|
|
|
|
if (self.soundname and self.soundname != "") then
|
|
self:StopSound(self.soundname)
|
|
end
|
|
end
|
|
|
|
function ENT:SetForce( force, mul )
|
|
if (force) then
|
|
self.force = force
|
|
self:ShowOutput()
|
|
end
|
|
mul = mul or 1
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if (!phys:IsValid()) then
|
|
Msg("Warning: [",self,"] Physics object isn't valid!\n")
|
|
return
|
|
end
|
|
|
|
// Get the data in worldspace
|
|
local ThrusterWorldPos = phys:LocalToWorld( self.ThrustOffset )
|
|
local ThrusterWorldForce = phys:LocalToWorldVector( self.ThrustOffset * -1 )
|
|
|
|
// Calculate the velocity
|
|
ThrusterWorldForce = ThrusterWorldForce * self.force * mul * 50
|
|
self.ForceLinear, self.ForceAngle = phys:CalculateVelocityOffset( ThrusterWorldForce, ThrusterWorldPos );
|
|
self.ForceLinear = phys:WorldToLocalVector( self.ForceLinear )
|
|
|
|
if self.neteffect then
|
|
-- self.ForceLinear is 0 if the thruster is frozen
|
|
self.effectforce = ThrusterWorldForce:Length()
|
|
self.updateeffect = true
|
|
end
|
|
|
|
if ( mul > 0 ) then
|
|
self:SetOffset( self.ThrustOffset )
|
|
else
|
|
self:SetOffset( self.ThrustOffsetR )
|
|
end
|
|
end
|
|
|
|
function ENT:SetDatEffect(uwater, owater, uweffect, oweffect)
|
|
if self:WaterLevel() > 0 then
|
|
if not uwater then
|
|
self:SetEffect("none")
|
|
return
|
|
end
|
|
|
|
if uweffect == "same" then
|
|
self:SetEffect(oweffect)
|
|
return
|
|
else
|
|
self:SetEffect(uweffect)
|
|
return
|
|
end
|
|
else
|
|
if not owater then
|
|
self:SetEffect("none")
|
|
return
|
|
end
|
|
self:SetEffect(oweffect)
|
|
return
|
|
end
|
|
end
|
|
|
|
function ENT:Setup(force, force_min, force_max, oweffect, uweffect, owater, uwater, bidir, soundname)
|
|
self:SetForce(force)
|
|
|
|
self:SetDatEffect(uwater, owater, uweffect, oweffect)
|
|
|
|
self.oweffect = oweffect
|
|
self.uweffect = uweffect
|
|
self.force_min = force_min
|
|
self.force_max = force_max
|
|
self.bidir = bidir
|
|
self.owater = owater
|
|
self.uwater = uwater
|
|
|
|
if (!soundname) then soundname = "" end
|
|
|
|
-- Preventing client crashes
|
|
local BlockedChars = '["?]'
|
|
if ( string.find(soundname, BlockedChars) ) then
|
|
self:StopSound( self.SoundName )
|
|
soundname = ""
|
|
end
|
|
|
|
if (soundname == "") then
|
|
self:StopSound( self.soundname )
|
|
end
|
|
|
|
self.soundname = Sound( soundname )
|
|
|
|
--self:SetOverlayText( "Thrust = " .. 0 .. "\nMul: " .. math.Round(force*1000)/1000 )
|
|
end
|
|
|
|
function ENT:TriggerInput(iname, value)
|
|
if (iname == "A") then
|
|
if ( (self.bidir) and (math.abs(value) > 0.01) and (math.abs(value) > self.force_min) ) or ( (value > 0.01) and (value > self.force_min) ) then
|
|
self:Switch(true, math.min(value, self.force_max))
|
|
else
|
|
self:Switch(false, 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ENT:Think()
|
|
if self.neteffect and self.updateeffect then
|
|
self.updateeffect = false
|
|
self:SetNWFloat("Thrust", self.effectforce)
|
|
end
|
|
self:NextThink(CurTime()+0.5)
|
|
end
|
|
|
|
function ENT:PhysicsSimulate( phys, deltatime )
|
|
if (!self:IsOn()) then return SIM_NOTHING end
|
|
|
|
if (self:WaterLevel() > 0) then
|
|
if (not self.uwater) then
|
|
self:SetEffect("none")
|
|
return SIM_NOTHING
|
|
end
|
|
|
|
if (self.uweffect == "same") then
|
|
self:SetEffect(self.oweffect)
|
|
else
|
|
self:SetEffect(self.uweffect)
|
|
end
|
|
else
|
|
if (not self.owater) then
|
|
self:SetEffect("none")
|
|
return SIM_NOTHING
|
|
end
|
|
|
|
self:SetEffect(self.oweffect)
|
|
end
|
|
|
|
local ForceAngle, ForceLinear = self.ForceAngle, self.ForceLinear
|
|
|
|
return ForceAngle, ForceLinear, SIM_LOCAL_ACCELERATION
|
|
end
|
|
|
|
function ENT:Switch( on, mul )
|
|
if (!self:IsValid()) then return false end
|
|
|
|
local changed = (self:IsOn() ~= on)
|
|
self:SetOn( on )
|
|
|
|
|
|
if (on) then
|
|
if (changed) and (self.soundname and self.soundname != "") then
|
|
self:StopSound( self.soundname )
|
|
self:EmitSound( self.soundname )
|
|
end
|
|
|
|
self.mul = mul
|
|
|
|
self:SetForce( nil, mul )
|
|
else
|
|
if (self.soundname and self.soundname != "") then
|
|
self:StopSound( self.soundname )
|
|
end
|
|
|
|
self.mul = 0
|
|
end
|
|
self:ShowOutput()
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if (phys:IsValid()) then
|
|
phys:Wake()
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function ENT:ShowOutput()
|
|
self:SetOverlayText(string.format("Force Mul: %.2f\nModel Mul: %.2f\nInput: %.2f\nForce Applied: %.2f",
|
|
self.force or 0,
|
|
self.ThrustOffset.z,
|
|
self.mul or 0,
|
|
(self.force or 0) * (self.mul or 0) * self.ThrustOffset.z
|
|
))
|
|
end
|
|
|
|
function ENT:OnRestore()
|
|
local phys = self:GetPhysicsObject()
|
|
|
|
if (phys:IsValid()) then
|
|
phys:Wake()
|
|
end
|
|
|
|
local max = self:OBBMaxs()
|
|
local min = self:OBBMins()
|
|
|
|
self.ThrustOffset = Vector( 0, 0, max.z )
|
|
self.ThrustOffsetR = Vector( 0, 0, min.z )
|
|
self.ForceAngle = self.ThrustOffset:GetNormalized() * -1
|
|
|
|
self:SetOffset( self.ThrustOffset )
|
|
self:StartMotionController()
|
|
|
|
BaseClass.OnRestore(self)
|
|
end
|
|
|
|
duplicator.RegisterEntityClass("gmod_wire_thruster", WireLib.MakeWireEnt, "Data", "force", "force_min", "force_max", "oweffect", "uweffect", "owater", "uwater", "bidir", "soundname")
|