1490 lines
52 KiB
Lua
1490 lines
52 KiB
Lua
AddCSLuaFile()
|
|
|
|
DEFINE_BASECLASS( "base_wire_entity" )
|
|
|
|
ENT.PrintName = "ACF Engine Maker"
|
|
ENT.WireDebugName = "ACF Engine Maker"
|
|
|
|
if CLIENT then
|
|
|
|
function ACFEngineMakerGUICreate( Table )
|
|
if not acfmenupanel.ModData then
|
|
acfmenupanel.ModData = {}
|
|
end
|
|
if not acfmenupanel.ModData[Table.id] then
|
|
acfmenupanel.ModData[Table.id] = {}
|
|
acfmenupanel.ModData[Table.id]["ModTable"] = Table.modtable
|
|
end
|
|
|
|
acfmenupanel:CPanelText("Name", Table.name)
|
|
acfmenupanel:CPanelText("Desc", "Desc : "..Table.desc)
|
|
|
|
for ID,Value in pairs(acfmenupanel.ModData[Table.id]["ModTable"]) do
|
|
if ID == 1 then
|
|
ACF_ModingEngine()
|
|
end
|
|
end
|
|
|
|
acfmenupanel.CustomDisplay:PerformLayout()
|
|
|
|
end
|
|
|
|
function ACF_ModingEngine( )
|
|
--############
|
|
--loading
|
|
local Redcolor = 0
|
|
local Greencolor = 0
|
|
local Bluecolor = 0
|
|
if file.Exists("acf/menucolor.txt", "DATA") then
|
|
local MenuColor = file.Read("acf/menucolor.txt")
|
|
local MenuColorTable = {}
|
|
for w in string.gmatch(MenuColor, "([^,]+)") do
|
|
table.insert(MenuColorTable, w)
|
|
end
|
|
Redcolor = tonumber(MenuColorTable[1])
|
|
Greencolor = tonumber(MenuColorTable[2])
|
|
Bluecolor = tonumber(MenuColorTable[3])
|
|
local RedString = tostring(Redcolor)
|
|
local GreenString = tostring(Greencolor)
|
|
local BlueString = tostring(Bluecolor)
|
|
else
|
|
Redcolor = 0
|
|
Greencolor = 0
|
|
Bluecolor = 200
|
|
end
|
|
--First Load
|
|
local NameLoad = "No Name"
|
|
local SoundLoad = "No Sound"
|
|
local ModelLoad = "models/engines/inline4s.mdl"
|
|
local FuelTypeLoad = "Petrol"
|
|
local EngineTypeLoad = "GenericPetrol"
|
|
local TorqueLoad = 1
|
|
local IdleLoad = 1
|
|
local PeakMinLoad = 1
|
|
local PeakMaxLoad = 1
|
|
local LimitRpmLoad = 1
|
|
local FlywheelLoad = 1
|
|
local WeightLoad = 1
|
|
local EngineSizeText = 1
|
|
local EngineTypeText = 1
|
|
local IselectText = "false"
|
|
local IsTransText = "false"
|
|
local FlywheelOverNumber = 1
|
|
|
|
if not file.Exists("acf/lastengine.txt", "DATA") then
|
|
local txt = NameLoad..","..SoundLoad..","..ModelLoad..","..FuelTypeLoad..","..EngineTypeLoad..","..TorqueLoad..","
|
|
txt = txt ..IdleLoad..","..PeakMinLoad..","..PeakMaxLoad..","..LimitRpmLoad..","..FlywheelLoad..","..WeightLoad..","
|
|
txt = txt ..EngineSizeText..","..EngineTypeText..","..IselectText..","..IsTransText..","..FlywheelOverNumber
|
|
file.CreateDir("acf")
|
|
file.CreateDir("acf/custom.engines")
|
|
file.Write("acf/lastengine.txt", txt)
|
|
acfmenupanel.CustomDisplay:PerformLayout()
|
|
end
|
|
--###########################################
|
|
local wide = acfmenupanel.CustomDisplay:GetWide()
|
|
|
|
Open = vgui.Create("DButton")
|
|
Open:SetText("Open Engine Menu")
|
|
Open:SetTextColor(Color(Redcolor,Greencolor,Bluecolor,255))
|
|
Open:SetWide(wide)
|
|
Open:SetTall(30)
|
|
Open:SetVisible(true)
|
|
Open.DoClick = function()
|
|
RunConsoleCommand("acf_enginestart_browser_open")
|
|
end
|
|
acfmenupanel.CustomDisplay:AddItem(Open)
|
|
|
|
DisplayModel = vgui.Create( "DModelPanel", acfmenupanel.CustomDisplay )
|
|
DisplayModel:SetModel( ModelLoad )
|
|
DisplayModel:SetCamPos( Vector( 250, 500, 250 ) )
|
|
DisplayModel:SetLookAt( Vector( 0, 0, 0 ) )
|
|
DisplayModel:SetFOV( 20 )
|
|
DisplayModel:SetSize(acfmenupanel:GetWide(),acfmenupanel:GetWide())
|
|
DisplayModel.LayoutEntity = function( panel, entity ) end
|
|
acfmenupanel.CustomDisplay:AddItem( DisplayModel )
|
|
|
|
acfmenupanel:CPanelText("EngName", "Engine Name : "..NameLoad)
|
|
acfmenupanel:CPanelText("EngSound", "Sound : "..SoundLoad)
|
|
acfmenupanel:CPanelText("EngModel", "Model : "..ModelLoad)
|
|
acfmenupanel:CPanelText("EngFuel", "Fuel Type : "..FuelTypeLoad)
|
|
acfmenupanel:CPanelText("EngType", "Engine Type : "..EngineTypeLoad)
|
|
acfmenupanel:CPanelText("EngTorque", "Torque : "..TorqueLoad)
|
|
acfmenupanel:CPanelText("EngIdle", "Idle Rpm : "..IdleLoad)
|
|
acfmenupanel:CPanelText("EngPeakMin", "Peak Min Rpm : "..PeakMinLoad)
|
|
acfmenupanel:CPanelText("EngPeakMax", "Peak Max Rpm : "..PeakMaxLoad)
|
|
acfmenupanel:CPanelText("EngLimit", "Limit Rpm : "..LimitRpmLoad)
|
|
acfmenupanel:CPanelText("EngFly", "Flywheel Mass : "..FlywheelLoad)
|
|
acfmenupanel:CPanelText("EngWeight", "Weight : "..WeightLoad)
|
|
|
|
Help = vgui.Create("DButton")
|
|
Help:SetToolTip("1.Create/Load a engine in the Engine menu\n2.Update the text by selecting again Engine Maker\n3.Spawn the Engine !")
|
|
Help:SetTextColor(Color(0,150,0,255))
|
|
Help:SetWide(wide/2)
|
|
Help:SetTall(30)
|
|
Help:SetVisible(true)
|
|
Help:SetText("Help")
|
|
acfmenupanel.CustomDisplay:AddItem(Help)
|
|
--Reload Last Engine
|
|
if file.Exists("acf/lastengine.txt", "DATA") then
|
|
local LastEngineText = file.Read("acf/lastengine.txt")
|
|
local LastEngineTable = {}
|
|
for w in string.gmatch(LastEngineText, "([^,]+)") do
|
|
table.insert(LastEngineTable, w)
|
|
end
|
|
|
|
NameLoad = tostring(LastEngineTable[1])
|
|
SoundLoad = tostring(LastEngineTable[2])
|
|
ModelLoad = tostring(LastEngineTable[3])
|
|
FuelTypeLoad = tostring(LastEngineTable[4])
|
|
EngineTypeLoad = tostring(LastEngineTable[5])
|
|
TorqueLoad = tonumber(LastEngineTable[6])
|
|
IdleLoad = tonumber(LastEngineTable[7])
|
|
PeakMinLoad = tonumber(LastEngineTable[8])
|
|
PeakMaxLoad = tonumber(LastEngineTable[9])
|
|
LimitRpmLoad = tonumber(LastEngineTable[10])
|
|
FlywheelLoad = tonumber(LastEngineTable[11])
|
|
WeightLoad = tonumber(LastEngineTable[12])
|
|
IselectText = tostring(LastEngineTable[15])
|
|
IsTransText = tostring(LastEngineTable[16])
|
|
FlywheelOverNumber = tonumber(LastEngineTable[17])
|
|
RunConsoleCommand( "acfmenu_data1", NameLoad )
|
|
RunConsoleCommand( "acfmenu_data2", SoundLoad )
|
|
RunConsoleCommand( "acfmenu_data3", ModelLoad )
|
|
RunConsoleCommand( "acfmenu_data4", FuelTypeLoad )
|
|
RunConsoleCommand( "acfmenu_data5", EngineTypeLoad )
|
|
RunConsoleCommand( "acfmenu_data6", TorqueLoad )
|
|
RunConsoleCommand( "acfmenu_data7", IdleLoad )
|
|
RunConsoleCommand( "acfmenu_data8", PeakMinLoad )
|
|
RunConsoleCommand( "acfmenu_data9", PeakMaxLoad )
|
|
RunConsoleCommand( "acfmenu_data10", LimitRpmLoad )
|
|
RunConsoleCommand( "acfmenu_data11", FlywheelLoad )
|
|
RunConsoleCommand( "acfmenu_data12", WeightLoad )
|
|
RunConsoleCommand( "acfmenu_data13", IselectText )
|
|
RunConsoleCommand( "acfmenu_data14", IsTransText )
|
|
RunConsoleCommand( "acfmenu_data15", FlywheelOverNumber )
|
|
--###
|
|
acfmenupanel:CPanelText("EngName", "Engine Name : "..NameLoad)
|
|
acfmenupanel:CPanelText("EngSound", "Sound : "..SoundLoad)
|
|
acfmenupanel:CPanelText("EngModel", "Model : "..ModelLoad)
|
|
acfmenupanel:CPanelText("EngFuel", "Fuel Type : "..FuelTypeLoad)
|
|
acfmenupanel:CPanelText("EngType", "Engine Type : "..EngineTypeLoad)
|
|
acfmenupanel:CPanelText("EngTorque", "Torque : "..TorqueLoad)
|
|
acfmenupanel:CPanelText("EngIdle", "Idle Rpm : "..IdleLoad)
|
|
acfmenupanel:CPanelText("EngPeakMin", "Peak Min Rpm : "..PeakMinLoad)
|
|
acfmenupanel:CPanelText("EngPeakMax", "Peak Max Rpm : "..PeakMaxLoad)
|
|
acfmenupanel:CPanelText("EngLimit", "Limit Rpm : "..LimitRpmLoad)
|
|
acfmenupanel:CPanelText("EngFly", "Flywheel Mass : "..FlywheelLoad)
|
|
acfmenupanel:CPanelText("EngWeight", "Weight : "..WeightLoad)
|
|
DisplayModel:SetModel( ModelLoad )
|
|
|
|
acfmenupanel.CustomDisplay:PerformLayout()
|
|
end
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
--###################################################
|
|
--##### END CL_INIT #####
|
|
--###################################################
|
|
|
|
function ENT:Initialize()
|
|
|
|
self.Throttle = 0
|
|
self.Active = false
|
|
self.IsMaster = true
|
|
self.GearLink = {} -- a "Link" has these components: Ent, Rope, RopeLen, ReqTq
|
|
self.FuelLink = {}
|
|
|
|
self.LastCheck = 0
|
|
self.LastThink = 0
|
|
self.MassRatio = 1
|
|
self.Legal = true
|
|
self.CanUpdate = true
|
|
self.RequiresFuel = 0
|
|
|
|
--####################
|
|
self.TqAdd = 0
|
|
self.MaxRpmAdd = 0
|
|
self.LimitRpmAdd = 0
|
|
self.FlywheelMass = 0
|
|
self.Override = 0
|
|
self.WeightKg = 0
|
|
self.idle = 0
|
|
self.CutMode = 0
|
|
self.CutValue = 0
|
|
self.CutRpm = 0
|
|
self.DisableAutoClutch = 0
|
|
self.Fuelusing = 0
|
|
self.DisableCut = 0
|
|
self.ExtraLink = {}
|
|
self.Master = {}
|
|
self.PeakTorqueExtra = 0
|
|
self.PeakMaxRPMExtra = 0
|
|
self.LimitRPMExtra = 0
|
|
self.ExtraUsing = 0
|
|
self.PeakTorqueHealth = 0
|
|
--#####################
|
|
self.Outputs = WireLib.CreateSpecialOutputs( self, { "RPM", "Torque", "Power", "Fuel Use", "Entity", "Mass", "Physical Mass" }, { "NORMAL","NORMAL","NORMAL", "NORMAL", "ENTITY", "NORMAL", "NORMAL" } )
|
|
Wire_TriggerOutput( self, "Entity", self )
|
|
end
|
|
|
|
--###################################################
|
|
--##### MAKE ENGINE #####
|
|
--###################################################
|
|
|
|
function MakeACF_EngineMaker(Owner, Pos, Angle, Id, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11, Data12, Data13, Data14, Data15)
|
|
|
|
if not Owner:CheckLimit("_acf_maker") then return false end
|
|
|
|
local EngineMaker = ents.Create( "acf_enginemaker" )
|
|
if not IsValid( EngineMaker ) then return false end
|
|
|
|
local EID
|
|
local List = list.Get("ACFEnts")
|
|
if List["Mobility"][Id] then EID = Id else EID = "Maker" end
|
|
local Lookup = List.Mobility[EID]
|
|
|
|
EngineMaker:SetAngles(Angle)
|
|
EngineMaker:SetPos(Pos)
|
|
EngineMaker:Spawn()
|
|
EngineMaker:SetPlayer(Owner)
|
|
EngineMaker.Owner = Owner
|
|
EngineMaker.Id = EID
|
|
|
|
EngineMaker.elecpower = Lookup.elecpower
|
|
EngineMaker.SoundPitch = Lookup.pitch or 1
|
|
EngineMaker.SpecialHealth = true
|
|
EngineMaker.SpecialDamage = true
|
|
EngineMaker.TorqueMult = 1
|
|
|
|
EngineMaker.ModTable = Lookup.modtable
|
|
EngineMaker.ModTable[1] = Data1
|
|
EngineMaker.ModTable[2] = Data2
|
|
EngineMaker.ModTable[3] = Data3
|
|
EngineMaker.ModTable[4] = Data4
|
|
EngineMaker.ModTable[5] = Data5
|
|
EngineMaker.ModTable[6] = Data6
|
|
EngineMaker.ModTable[7] = Data7
|
|
EngineMaker.ModTable[8] = Data8
|
|
EngineMaker.ModTable[9] = Data9
|
|
EngineMaker.ModTable[10] = Data10
|
|
EngineMaker.ModTable[11] = Data11
|
|
EngineMaker.ModTable[12] = Data12
|
|
EngineMaker.ModTable[13] = Data13
|
|
EngineMaker.ModTable[14] = Data14
|
|
EngineMaker.ModTable[15] = Data15
|
|
|
|
EngineMaker.Mod1 = Data1
|
|
EngineMaker.Mod2 = Data2
|
|
EngineMaker.Mod3 = Data3
|
|
EngineMaker.Mod4 = Data4
|
|
EngineMaker.Mod5 = Data5
|
|
EngineMaker.Mod6 = Data6
|
|
EngineMaker.Mod7 = Data7
|
|
EngineMaker.Mod8 = Data8
|
|
EngineMaker.Mod9 = Data9
|
|
EngineMaker.Mod10 = Data10
|
|
EngineMaker.Mod11 = Data11
|
|
EngineMaker.Mod12 = Data12
|
|
EngineMaker.Mod13 = Data13
|
|
EngineMaker.Mod14 = Data14
|
|
EngineMaker.Mod15 = Data15
|
|
--Set Strings Values
|
|
if tostring(EngineMaker.Mod1) != nil then EngineMaker.EngineName = tostring(EngineMaker.Mod1) else EngineMaker.EngineName = "No Name" end
|
|
if tostring(EngineMaker.Mod2) != nil then EngineMaker.SoundPath = tostring(EngineMaker.Mod2) else EngineMaker.SoundPath = "" end
|
|
if string.find(tostring(EngineMaker.Mod3),".mdl") then EngineMaker.Model = tostring(EngineMaker.Mod3) else EngineMaker.Model = "models/engines/inline4s.mdl" end
|
|
if tostring(EngineMaker.Mod4) != nil then EngineMaker.FuelType = tostring(EngineMaker.Mod4) else EngineMaker.FuelType = "Petrol" end
|
|
if tostring(EngineMaker.Mod5) != nil then EngineMaker.EngineType = tostring(EngineMaker.Mod5) else EngineMaker.EngineType = "GenericPetrol" end
|
|
--Set Torque
|
|
if(tonumber(EngineMaker.Mod6) >= 1) then EngineMaker.PeakTorque = tonumber(EngineMaker.Mod6)
|
|
elseif(tonumber(Data6) < 1 or tonumber(Data6) == nil) then EngineMaker.PeakTorque = 1 end
|
|
--Set Idle
|
|
if(tonumber(EngineMaker.Mod7) >= 1) then EngineMaker.IdleRPM = tonumber(EngineMaker.Mod7)
|
|
elseif(tonumber(EngineMaker.Mod7) < 1 or tonumber(EngineMaker.Mod7) == nil) then EngineMaker.IdleRPM = 1 end
|
|
--Set PeakMin
|
|
if(tonumber(EngineMaker.Mod8) >= 1) then EngineMaker.PeakMinRPM = tonumber(EngineMaker.Mod8)
|
|
elseif(tonumber(EngineMaker.Mod8) < 1 or tonumber(EngineMaker.Mod8) == nil) then EngineMaker.PeakMinRPM = 1 end
|
|
--Set PeakMax
|
|
if(EngineMaker.Mod9 <= EngineMaker.Mod10 and tonumber(EngineMaker.Mod9) >= 1 ) then EngineMaker.PeakMaxRPM = tonumber(EngineMaker.Mod9)
|
|
elseif(EngineMaker.Mod9 > EngineMaker.Mod10 ) then EngineMaker.PeakMaxRPM = tonumber(EngineMaker.Mod10)
|
|
elseif(tonumber(EngineMaker.Mod9) < 1 or tonumber(EngineMaker.Mod9) == nil) then EngineMaker.PeakMaxRPM = 1 end
|
|
--Set Limit
|
|
if(tonumber(EngineMaker.Mod10) >= 100) then EngineMaker.LimitRPM = tonumber(EngineMaker.Mod10)
|
|
elseif(tonumber(EngineMaker.Mod10) < 100 or tonumber(EngineMaker.Mod10) == nil) then EngineMaker.LimitRPM = 100 end
|
|
--Set Flywheel
|
|
if(tonumber(EngineMaker.Mod11) >= 0.001) then EngineMaker.FlywheelMassValue = tonumber(EngineMaker.Mod11)
|
|
elseif(tonumber(EngineMaker.Mod11) < 0.001 or tonumber(EngineMaker.Mod11) == nil) then EngineMaker.FlywheelMassValue = 0.001 end
|
|
--Set Weight
|
|
if(tonumber(EngineMaker.Mod12) >= 1) then EngineMaker.Weight = tonumber(EngineMaker.Mod12)
|
|
elseif(tonumber(EngineMaker.Mod12) < 1 or tonumber(EngineMaker.Mod12) == nil ) then EngineMaker.Weight = 1 end
|
|
--Set Electric/turbine stuff
|
|
if tobool(EngineMaker.Mod13) != nil then EngineMaker.iselec = tobool(EngineMaker.Mod13) else EngineMaker.iselec = false end
|
|
if tobool(EngineMaker.Mod14) != nil then EngineMaker.IsTrans = tobool(EngineMaker.Mod14) else EngineMaker.IsTrans = false end
|
|
if tonumber(EngineMaker.Mod15) != nil then EngineMaker.FlywheelOverride = tonumber(EngineMaker.Mod15) else EngineMaker.FlywheelOverride = 1200 end
|
|
--Set Original Values
|
|
EngineMaker.PeakTorqueHeld = EngineMaker.PeakTorque
|
|
EngineMaker.CutValue = EngineMaker.LimitRPM / 40
|
|
EngineMaker.CutRpm = EngineMaker.LimitRPM - 100
|
|
EngineMaker.Inertia = EngineMaker.FlywheelMassValue*(3.1416)^2
|
|
--Set Custom Values
|
|
EngineMaker.FlywheelMass3 = EngineMaker.FlywheelMassValue
|
|
EngineMaker.PeakTorqueLoad = EngineMaker.PeakTorque
|
|
EngineMaker.PeakTorqueAdd = EngineMaker.PeakTorque
|
|
EngineMaker.Idling = EngineMaker.IdleRPM
|
|
EngineMaker.PeakMaxRPM2 = EngineMaker.PeakMaxRPM
|
|
EngineMaker.LimitRPM2 = EngineMaker.LimitRPM
|
|
--calculate boosted peak kw
|
|
if EngineMaker.EngineType == "GenericDiesel" then
|
|
EngineMaker.TorqueScale = ACF.DieselTorqueScale
|
|
else
|
|
EngineMaker.TorqueScale = ACF.TorqueScale
|
|
end
|
|
|
|
if EngineMaker.EngineType == "Turbine" or EngineMaker.EngineType == "Electric" then
|
|
EngineMaker.DisableCut = 1
|
|
EngineMaker.peakkw = EngineMaker.PeakTorque * EngineMaker.LimitRPM / (4 * 9548.8)
|
|
EngineMaker.PeakKwRPM = math.floor(EngineMaker.LimitRPM / 2)
|
|
else
|
|
EngineMaker.peakkw = EngineMaker.PeakTorque * EngineMaker.PeakMaxRPM / 9548.8
|
|
EngineMaker.PeakKwRPM = EngineMaker.PeakMaxRPM
|
|
end
|
|
--calculate base fuel usage
|
|
if EngineMaker.EngineType == "Electric" then
|
|
EngineMaker.FuelUse = ACF.ElecRate / (ACF.Efficiency[EngineMaker.EngineType] * 60 * 60) --elecs use current power output, not max
|
|
else
|
|
EngineMaker.FuelUse = ACF.TorqueBoost * ACF.FuelRate * ACF.Efficiency[EngineMaker.EngineType] * EngineMaker.peakkw / (60 * 60)
|
|
end
|
|
--Creating Wire Inputs
|
|
EngineMaker.CustomLimit = GetConVarNumber("sbox_max_acf_modding")
|
|
local Inputs = {"Active", "Throttle"}
|
|
if EngineMaker.CustomLimit > 0 then
|
|
if EngineMaker.EngineType == "Turbine" or EngineMaker.EngineType == "Electric" then --Create inputs for Electric&Turbine
|
|
table.insert(Inputs, "TqAdd")
|
|
table.insert(Inputs, "LimitRpmAdd")
|
|
table.insert(Inputs, "FlywheelMass")
|
|
table.insert(Inputs, "Override")
|
|
table.insert(Inputs, "Gearbox RPM")
|
|
else --Create inputs others engines
|
|
table.insert(Inputs, "TqAdd")
|
|
table.insert(Inputs, "MaxRpmAdd")
|
|
table.insert(Inputs, "LimitRpmAdd")
|
|
table.insert(Inputs, "FlywheelMass")
|
|
table.insert(Inputs, "Idle")
|
|
table.insert(Inputs, "Disable Cutoff")
|
|
table.insert(Inputs, "Gearbox RPM")
|
|
end
|
|
end
|
|
EngineMaker.Inputs = Wire_CreateInputs( EngineMaker, Inputs )
|
|
|
|
EngineMaker.FlyRPM = 0
|
|
EngineMaker:SetModel( EngineMaker.Model )
|
|
EngineMaker.Sound = nil
|
|
EngineMaker.RPM = {}
|
|
|
|
EngineMaker:PhysicsInit( SOLID_VPHYSICS )
|
|
EngineMaker:SetMoveType( MOVETYPE_VPHYSICS )
|
|
EngineMaker:SetSolid( SOLID_VPHYSICS )
|
|
|
|
EngineMaker.Out = EngineMaker:WorldToLocal(EngineMaker:GetAttachment(EngineMaker:LookupAttachment( "driveshaft" )).Pos)
|
|
|
|
local phys = EngineMaker:GetPhysicsObject()
|
|
if IsValid( phys ) then
|
|
phys:SetMass( EngineMaker.Weight )
|
|
end
|
|
|
|
EngineMaker:SetNetworkedString( "WireName", EngineMaker.EngineName )
|
|
------ GUI ---------
|
|
EngineMaker.FlywheelMassGUI = EngineMaker.FlywheelMassValue
|
|
EngineMaker:UpdateOverlayText()
|
|
|
|
Owner:AddCount("_acf_enginemaker", EngineMaker)
|
|
Owner:AddCleanup( "acfmenu", EngineMaker )
|
|
|
|
ACF_Activate( EngineMaker, 0 )
|
|
|
|
return EngineMaker
|
|
end
|
|
list.Set( "ACFCvars", "acf_enginemaker", {"id", "data1", "data2", "data3", "data4", "data5", "data6", "data7", "data8", "data9", "data10", "data11", "data12", "data13", "data14", "data15"} )
|
|
duplicator.RegisterEntityClass("acf_enginemaker", MakeACF_EngineMaker, "Pos", "Angle", "Id", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5", "Mod6", "Mod7", "Mod8", "Mod9", "Mod10", "Mod11", "Mod12", "Mod13")
|
|
|
|
--###################################################
|
|
--##### UPDATE ENGINE #####
|
|
--###################################################
|
|
|
|
function ENT:Update( ArgsTable ) --That table is the player data, as sorted in the ACFCvars above, with player who shot, and pos and angle of the tool trace inserted at the start
|
|
-- That table is the player data, as sorted in the ACFCvars above, with player who shot,
|
|
-- and pos and angle of the tool trace inserted at the start
|
|
|
|
if self.Active then
|
|
return false, "Turn off the engine before updating it!"
|
|
end
|
|
|
|
if ArgsTable[1] ~= self.Owner then -- Argtable[1] is the player that shot the tool
|
|
return false, "You don't own that engine!"
|
|
end
|
|
|
|
local Id = ArgsTable[4] -- Argtable[4] is the engine ID
|
|
local Lookup = list.Get("ACFEnts").Mobility[Id]
|
|
|
|
if ArgsTable[7] ~= self.Model then
|
|
return false, "The new engine must have the same model!"
|
|
end
|
|
|
|
local Feedback = ""
|
|
if Lookup.fuel != self.FuelType then
|
|
Feedback = " Fuel type changed, fuel tanks unlinked."
|
|
for Key,Value in pairs(self.FuelLink) do
|
|
table.remove(self.FuelLink,Key)
|
|
--need to remove from tank master?
|
|
end
|
|
end
|
|
|
|
if self.Id != Id then
|
|
self.Id = Id
|
|
self.elecpower = Lookup.elecpower -- how much power does it output
|
|
self.SoundPitch = Lookup.pitch or 1
|
|
self.SpecialHealth = true
|
|
self.SpecialDamage = true
|
|
self.TorqueMult = self.TorqueMult or 1
|
|
end
|
|
self.ModTable[1] = ArgsTable[5]
|
|
self.ModTable[2] = ArgsTable[6]
|
|
self.ModTable[3] = ArgsTable[7]
|
|
self.ModTable[4] = ArgsTable[8]
|
|
self.ModTable[5] = ArgsTable[9]
|
|
self.ModTable[6] = ArgsTable[10]
|
|
self.ModTable[7] = ArgsTable[11]
|
|
self.ModTable[8] = ArgsTable[12]
|
|
self.ModTable[9] = ArgsTable[13]
|
|
self.ModTable[10] = ArgsTable[14]
|
|
self.ModTable[11] = ArgsTable[15]
|
|
self.ModTable[12] = ArgsTable[16]
|
|
self.ModTable[13] = ArgsTable[17]
|
|
self.ModTable[14] = ArgsTable[18]
|
|
self.ModTable[15] = ArgsTable[19]
|
|
self.Mod1 = ArgsTable[5]
|
|
self.Mod2 = ArgsTable[6]
|
|
self.Mod3 = ArgsTable[7]
|
|
self.Mod4 = ArgsTable[8]
|
|
self.Mod5 = ArgsTable[9]
|
|
self.Mod6 = ArgsTable[10]
|
|
self.Mod7 = ArgsTable[11]
|
|
self.Mod8 = ArgsTable[12]
|
|
self.Mod9 = ArgsTable[13]
|
|
self.Mod10 = ArgsTable[14]
|
|
self.Mod11 = ArgsTable[15]
|
|
self.Mod12 = ArgsTable[16]
|
|
self.Mod13 = ArgsTable[17]
|
|
self.Mod14 = ArgsTable[18]
|
|
self.Mod15 = ArgsTable[19]
|
|
--Set String Values
|
|
if tostring(self.Mod1) != nil then self.EngineName = tostring(self.Mod1) else self.EngineName = "No Name" end
|
|
if tostring(self.Mod2) != nil then self.SoundPath = tostring(self.Mod2) else self.SoundPath = "" end
|
|
if string.find(tostring(self.Mod3),".mdl") then self.Model = tostring(self.Mod3) else self.Model = "models/engines/v8s.mdl" end
|
|
if tostring(self.Mod4) != nil then self.FuelType = tostring(self.Mod4) else self.FuelType = "Petrol" end
|
|
if tostring(self.Mod5) != nil then self.EngineType = tostring(self.Mod5) else self.EngineType = "GenericPetrol" end
|
|
--Set Torque
|
|
if(tonumber(self.Mod6) >= 1) then self.PeakTorque = tonumber(self.Mod6)
|
|
elseif(tonumber(self.Mod6) < 1 or tonumber(self.Mod6) == nil) then self.PeakTorque = 1 end
|
|
--Set Idle
|
|
if(tonumber(self.Mod7) >= 1) then self.IdleRPM = tonumber(self.Mod7)
|
|
elseif(tonumber(self.Mod7) < 1 or tonumber(self.Mod7) == nil) then self.IdleRPM = 1 end
|
|
--Set PeakMin
|
|
if(tonumber(self.Mod8) >= 1) then self.PeakMinRPM = tonumber(self.Mod8)
|
|
elseif(tonumber(self.Mod8) < 1 or tonumber(self.Mod8) == nil) then self.PeakMinRPM = 1 end
|
|
--Set PeakMax
|
|
if(self.Mod9 <= self.Mod10 and tonumber(self.Mod9) >= 1 ) then self.PeakMaxRPM = tonumber(self.Mod9)
|
|
elseif(self.Mod9 > self.Mod10 ) then self.PeakMaxRPM = tonumber(self.Mod10)
|
|
elseif(tonumber(self.Mod9) < 1 or tonumber(self.Mod9) == nil) then self.PeakMaxRPM = 1 end
|
|
--Set Limit
|
|
if(tonumber(self.Mod10) >= 100) then self.LimitRPM = tonumber(self.Mod10)
|
|
elseif(tonumber(self.Mod10) < 100 or tonumber(self.Mod10) == nil) then self.LimitRPM = 100 end
|
|
--Set Flywheel
|
|
if(tonumber(self.Mod11) >= 0.001) then self.FlywheelMassValue = tonumber(self.Mod11)
|
|
elseif(tonumber(self.Mod11) < 0.001 or tonumber(self.Mod11) == nil) then self.FlywheelMassValue = 0.001 end
|
|
--Set Weight
|
|
if(tonumber(self.Mod12) >= 1) then self.Weight = tonumber(self.Mod12)
|
|
elseif(tonumber(self.Mod12) < 1 or tonumber(self.Mod12) == nil) then self.Weight = 1 end
|
|
--Set Electric/Turbine Stuff
|
|
if tobool(self.Mod13) != nil then self.iselec = tobool(self.Mod13) else self.iselec = false end
|
|
if tobool(self.Mod14) != nil then self.IsTrans = tobool(self.Mod14) else self.IsTrans = false end
|
|
if tonumber(self.Mod15) != nil then self.FlywheelOverride = tonumber(self.Mod15) else self.FlywheelOverride = 1200 end
|
|
--Set Original Values
|
|
self.PeakTorqueHeld = self.PeakTorque
|
|
self.CutValue = self.LimitRPM / 40
|
|
self.CutRpm = self.LimitRPM - 100
|
|
self.Inertia = self.FlywheelMass3*(3.1416)^2
|
|
--Set Custom Values
|
|
self.FlywheelMass3 = self.FlywheelMassValue
|
|
self.PeakTorqueLoad = self.PeakTorque
|
|
self.PeakTorqueAdd = self.PeakTorque
|
|
self.Idling = self.IdleRPM
|
|
self.PeakMaxRPM2 = self.PeakMaxRPM
|
|
self.LimitRPM2 = self.LimitRPM
|
|
|
|
if self.EngineType == "GenericDiesel" then
|
|
self.TorqueScale = ACF.DieselTorqueScale
|
|
else
|
|
self.TorqueScale = ACF.TorqueScale
|
|
end
|
|
--calculate boosted peak kw
|
|
if self.EngineType == "Turbine" or self.EngineType == "Electric" then
|
|
self.DisableCut = 1
|
|
self.peakkw = self.PeakTorque * self.LimitRPM / (4 * 9548.8)
|
|
self.PeakKwRPM = math.floor(self.LimitRPM / 2)
|
|
else
|
|
self.peakkw = self.PeakTorque * self.PeakMaxRPM / 9548.8
|
|
self.PeakKwRPM = self.PeakMaxRPM
|
|
end
|
|
--calculate base fuel usage
|
|
if self.EngineType == "Electric" then
|
|
self.FuelUse = ACF.ElecRate / (ACF.Efficiency[self.EngineType] * 60 * 60) --elecs use current power output, not max
|
|
else
|
|
self.FuelUse = ACF.TorqueBoost * ACF.FuelRate * ACF.Efficiency[self.EngineType] * self.peakkw / (60 * 60)
|
|
end
|
|
--Creating Wire Inputs
|
|
self.CustomLimit = GetConVarNumber("sbox_max_acf_modding")
|
|
local Inputs = {"Active", "Throttle"}
|
|
if self.CustomLimit > 0 then
|
|
if self.EngineType == "Turbine" or self.EngineType == "Electric" then --Create inputs for Electric&Turbine
|
|
table.insert(Inputs, "TqAdd")
|
|
table.insert(Inputs, "LimitRpmAdd")
|
|
table.insert(Inputs, "FlywheelMass")
|
|
table.insert(Inputs, "Override")
|
|
table.insert(Inputs, "Gearbox RPM")
|
|
else --Create inputs others engines
|
|
table.insert(Inputs, "TqAdd")
|
|
table.insert(Inputs, "MaxRpmAdd")
|
|
table.insert(Inputs, "LimitRpmAdd")
|
|
table.insert(Inputs, "FlywheelMass")
|
|
table.insert(Inputs, "Idle")
|
|
table.insert(Inputs, "Disable Cutoff")
|
|
table.insert(Inputs, "Gearbox RPM")
|
|
end
|
|
end
|
|
self.Inputs = Wire_CreateInputs( self, Inputs )
|
|
|
|
self:SetModel( self.Model )
|
|
self:SetSolid( SOLID_VPHYSICS )
|
|
self.Out = self:WorldToLocal(self:GetAttachment(self:LookupAttachment( "driveshaft" )).Pos)
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if IsValid( phys ) then
|
|
phys:SetMass( self.Weight )
|
|
end
|
|
|
|
self:SetNetworkedString( "WireName", self.EngineName )
|
|
------ GUI ---------
|
|
self.FlywheelMassGUI = self.FlywheelMassValue
|
|
self:UpdateOverlayText()
|
|
|
|
ACF_Activate( self, 1 )
|
|
|
|
return true, "Engine updated successfully!"..Feedback
|
|
end
|
|
|
|
--###################################################
|
|
--##### FUNCTIONS #####
|
|
--###################################################
|
|
|
|
function ENT:UpdateOverlayText()
|
|
--Better values for Power Gui and Torque Gui
|
|
if self.RequiresFuel == 1 then
|
|
self.PowerGUI = self.peakkw*ACF.TorqueBoost
|
|
self.TorqueGUI = (self.PeakTorqueAdd+self.PeakTorqueExtra)*ACF.TorqueBoost
|
|
else
|
|
self.PowerGUI = self.peakkw
|
|
self.TorqueGUI = (self.PeakTorqueAdd+self.PeakTorqueExtra)
|
|
end
|
|
|
|
local text = "Power: " .. math.Round(self.PowerGUI) .. " kW / " .. math.Round(self.PowerGUI * 1.34) .. " hp\n"
|
|
text = text .. "Torque: " .. math.Round(self.TorqueGUI) .. " Nm / " .. math.Round(self.TorqueGUI * 0.73) .. " ft-lb\n"
|
|
if self.EngineType == "Turbine" or self.EngineType == "Electric" then --Set Gui on electric&turbine
|
|
text = text .. "Override: " .. math.Round(self.FlywheelOverride) .. " RPM\n"
|
|
text = text .. "Redline: " .. math.Round((self.LimitRPM+self.LimitRPMExtra)) .. " RPM\n"
|
|
text = text .. "FlywheelMass: " .. math.Round(self.FlywheelMassGUI,3) .. " Kg\n"
|
|
text = text .. "Rpm: " .. math.Round(self.FlyRPM) .. " RPM\n"
|
|
text = text .. "Consumption: " .. math.Round(self.Fuelusing,3) .. " liters/min\n"
|
|
text = text .. "Weight: " .. math.Round(self.Weight) .. "Kg\n"
|
|
else --Set Gui on Others
|
|
text = text .. "Powerband: " .. math.Round(self.PeakMinRPM) .. " - " .. math.Round((self.PeakMaxRPM+self.PeakMaxRPMExtra)) .. " RPM\n"
|
|
text = text .. "Redline: " .. math.Round((self.LimitRPM+self.LimitRPMExtra)) .. " RPM\n"
|
|
text = text .. "FlywheelMass: " .. math.Round(self.FlywheelMassGUI,3) .. " Kg\n"
|
|
text = text .. "Rpm: " .. math.Round(self.FlyRPM) .. " RPM\n"
|
|
text = text .. "Consumption: " .. math.Round(self.Fuelusing,3) .. " liters/min\n"
|
|
text = text .. "Idle: " .. math.Round(self.IdleRPM) .. " RPM\n"
|
|
text = text .. "Weight: " .. math.Round(self.Weight) .. "Kg\n"
|
|
end
|
|
self:SetOverlayText( text )
|
|
|
|
end
|
|
|
|
function ENT:UpdateEngineConsumption()
|
|
if self.EngineType == "Turbine" or self.EngineType == "Electric" then
|
|
self.peakkw = (self.PeakTorqueAdd+self.PeakTorqueExtra) * (self.LimitRPM+self.LimitRPMExtra) / (4 * 9548.8)
|
|
self.PeakKwRPM = math.floor((self.LimitRPM+self.LimitRPMExtra) / 2)
|
|
else
|
|
self.peakkw = (self.PeakTorqueAdd+self.PeakTorqueExtra) * (self.PeakMaxRPM+self.PeakMaxRPMExtra) / 9548.8
|
|
self.PeakKwRPM = (self.PeakMaxRPM+self.PeakMaxRPMExtra)
|
|
end
|
|
if self.EngineType == "Electric" then
|
|
self.FuelUse = ACF.ElecRate / (ACF.Efficiency[self.EngineType] * 60 * 60) --elecs use current power output, not max
|
|
else
|
|
self.FuelUse = ACF.TorqueBoost * ACF.FuelRate * ACF.Efficiency[self.EngineType] * self.peakkw / (60 * 60)
|
|
end
|
|
self:UpdateOverlayText()
|
|
end
|
|
|
|
--###################################################
|
|
--##### TRIGGER INPUTS #####
|
|
--###################################################
|
|
|
|
function ENT:TriggerInput( iname, value )
|
|
if (iname == "Throttle") then
|
|
self.Throttle = math.Clamp(value,0,100)/100
|
|
elseif (iname == "Active") then
|
|
if (value > 0 and not self.Active) then
|
|
--make sure we have fuel
|
|
local HasFuel
|
|
if self.RequiresFuel == 0 then
|
|
HasFuel = true
|
|
else
|
|
for _,fueltank in pairs(self.FuelLink) do
|
|
if fueltank.Fuel > 0 and fueltank.Active then HasFuel = true break end
|
|
end
|
|
end
|
|
|
|
if HasFuel then
|
|
self.RPM = {}
|
|
self.RPM[1] = self.IdleRPM
|
|
self.Active = true
|
|
self.Active2 = true
|
|
self.Sound = CreateSound(self, self.SoundPath)
|
|
self.Sound:PlayEx(0.5,100)
|
|
self:ACFInit()
|
|
end
|
|
elseif (value > 0) then
|
|
local HasFuel
|
|
if self.RequiresFuel == 0 then
|
|
HasFuel = true
|
|
else
|
|
for _,fueltank in pairs(self.FuelLink) do
|
|
if fueltank.Fuel <= 0 or not fueltank.Active then HasFuel = false break end
|
|
end
|
|
end
|
|
if not HasFuel then
|
|
self:TriggerInput( "Active" , 0 )
|
|
self.Active = false
|
|
Wire_TriggerOutput( self, "RPM", 0 )
|
|
Wire_TriggerOutput( self, "Torque", 0 )
|
|
Wire_TriggerOutput( self, "Power", 0 )
|
|
Wire_TriggerOutput( self, "Fuel Use", 0 )
|
|
end
|
|
elseif (value <= 0 and self.Active) then
|
|
self.Active = false
|
|
Wire_TriggerOutput( self, "RPM", 0 )
|
|
Wire_TriggerOutput( self, "Torque", 0 )
|
|
Wire_TriggerOutput( self, "Power", 0 )
|
|
Wire_TriggerOutput( self, "Fuel Use", 0 )
|
|
end
|
|
--##########################################
|
|
elseif (iname == "TqAdd") then
|
|
if (value ~= 0 ) then
|
|
self.PeakTorqueAdd = self.PeakTorqueLoad+value
|
|
self:UpdateEngineConsumption()
|
|
elseif (value == 0 ) then
|
|
self.PeakTorqueAdd = self.PeakTorqueLoad
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
elseif (iname == "MaxRpmAdd") then
|
|
if (value ~= 0 ) then
|
|
if( self.PeakMaxRPM2+value <= self.LimitRPM ) then
|
|
self.PeakMaxRPM = self.PeakMaxRPM2+value
|
|
elseif( self.PeakMaxRPM2+value > self.LimitRPM ) then
|
|
self.PeakMaxRPM = self.LimitRPM
|
|
end
|
|
self:UpdateEngineConsumption()
|
|
elseif (value == 0 ) then
|
|
self.PeakMaxRPM = self.PeakMaxRPM2
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
elseif (iname == "LimitRpmAdd") then
|
|
if (value ~= 0 ) then
|
|
self.LimitRPM = self.LimitRPM2+value
|
|
self.CutValue = self.LimitRPM / 40
|
|
self.CutRpm = self.LimitRPM - 100
|
|
self:UpdateEngineConsumption()
|
|
elseif (value == 0 ) then
|
|
self.LimitRPM = self.LimitRPM2
|
|
self.CutValue = self.LimitRPM / 40
|
|
self.CutRpm = self.LimitRPM - 100
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
elseif (iname == "FlywheelMass") then
|
|
if (value > 0 ) then
|
|
self.FlywheelMassValue = value
|
|
self.FlywheelMassGUI = self.FlywheelMassValue
|
|
self:UpdateOverlayText()
|
|
elseif (value <= 0 ) then
|
|
self.FlywheelMassValue = self.FlywheelMass3
|
|
self.FlywheelMassGUI = self.FlywheelMassValue
|
|
self:UpdateOverlayText()
|
|
end
|
|
elseif (iname == "Override") then
|
|
if (value > 0 ) then
|
|
self.FlywheelOverride = value
|
|
self:UpdateOverlayText()
|
|
elseif (value <= 0 ) then
|
|
self.FlywheelOverride = self.FlywheelOverride2
|
|
self:UpdateOverlayText()
|
|
end
|
|
elseif (iname == "Idle") then
|
|
if (value > 0 ) then
|
|
self.IdleRPM = value
|
|
self:UpdateOverlayText()
|
|
elseif (value <= 0 ) then
|
|
self.IdleRPM = self.Idling
|
|
self:UpdateOverlayText()
|
|
end
|
|
elseif (iname == "Disable Cutoff") then
|
|
if (value > 0 ) then
|
|
self.DisableCut = 1
|
|
elseif (value <= 0 ) then
|
|
self.DisableCut = 0
|
|
end
|
|
--Disabling AutoClutch on Engine while Moving
|
|
elseif (iname == "Gearbox RPM") then
|
|
if ((value*0.8) > self.IdleRPM and self.Throttle == 0) then
|
|
self.DisableAutoClutch = 1
|
|
self.GearboxRpm = value
|
|
elseif (value <= self.IdleRPM or self.Throttle > 0 and self.DisableAutoClutch == 1) then
|
|
self.DisableAutoClutch = 0
|
|
self.GearboxRpm = 0
|
|
end
|
|
end
|
|
end
|
|
--#########################
|
|
function ENT:ACF_Activate()
|
|
--Density of steel = 7.8g cm3 so 7.8kg for a 1mx1m plate 1m thick
|
|
local Entity = self
|
|
Entity.ACF = Entity.ACF or {}
|
|
|
|
local Count
|
|
local PhysObj = Entity:GetPhysicsObject()
|
|
if PhysObj:GetMesh() then Count = #PhysObj:GetMesh() end
|
|
if PhysObj:IsValid() and Count and Count>100 then
|
|
|
|
if not Entity.ACF.Aera then
|
|
Entity.ACF.Aera = (PhysObj:GetSurfaceArea() * 6.45) * 0.52505066107
|
|
end
|
|
--if not Entity.ACF.Volume then
|
|
-- Entity.ACF.Volume = (PhysObj:GetVolume() * 16.38)
|
|
--end
|
|
else
|
|
local Size = Entity.OBBMaxs(Entity) - Entity.OBBMins(Entity)
|
|
if not Entity.ACF.Aera then
|
|
Entity.ACF.Aera = ((Size.x * Size.y)+(Size.x * Size.z)+(Size.y * Size.z)) * 6.45
|
|
end
|
|
--if not Entity.ACF.Volume then
|
|
-- Entity.ACF.Volume = Size.x * Size.y * Size.z * 16.38
|
|
--end
|
|
end
|
|
|
|
Entity.ACF.Ductility = Entity.ACF.Ductility or 0
|
|
--local Area = (Entity.ACF.Aera+Entity.ACF.Aera*math.Clamp(Entity.ACF.Ductility,-0.8,0.8))
|
|
local Area = (Entity.ACF.Aera)
|
|
--local Armour = (Entity:GetPhysicsObject():GetMass()*1000 / Area / 0.78) / (1 + math.Clamp(Entity.ACF.Ductility, -0.8, 0.8))^(1/2) --So we get the equivalent thickness of that prop in mm if all it's weight was a steel plate
|
|
local Armour = (Entity:GetPhysicsObject():GetMass()*1000 / Area / 0.78)
|
|
--local Health = (Area/ACF.Threshold) * (1 + math.Clamp(Entity.ACF.Ductility, -0.8, 0.8)) --Setting the threshold of the prop aera gone
|
|
local Health = (Area/ACF.Threshold)
|
|
|
|
local Percent = 1
|
|
|
|
if Recalc and Entity.ACF.Health and Entity.ACF.MaxHealth then
|
|
Percent = Entity.ACF.Health/Entity.ACF.MaxHealth
|
|
end
|
|
|
|
if self.EngineType == "GenericDiesel" then
|
|
Entity.ACF.Health = Health * Percent * ACF.DieselEngineHPMult
|
|
Entity.ACF.MaxHealth = Health * ACF.DieselEngineHPMult
|
|
else
|
|
Entity.ACF.Health = Health * Percent * ACF.EngineHPMult
|
|
Entity.ACF.MaxHealth = Health * ACF.EngineHPMult
|
|
end
|
|
Entity.ACF.Armour = Armour * (0.5 + Percent/2)
|
|
Entity.ACF.MaxArmour = Armour * ACF.ArmorMod
|
|
Entity.ACF.Type = nil
|
|
Entity.ACF.Mass = PhysObj:GetMass()
|
|
--Entity.ACF.Density = (PhysObj:GetMass()*1000)/Entity.ACF.Volume
|
|
|
|
Entity.ACF.Type = "Prop"
|
|
--print(Entity.ACF.Health)
|
|
end
|
|
|
|
function ENT:ACF_OnDamage( Entity, Energy, FrAera, Angle, Inflictor, Bone, Type ) --This function needs to return HitRes
|
|
|
|
local Mul = ((Type == "HEAT" and 6.6) or 1) --Heat penetrators deal bonus damage to engines, roughly half an AP round
|
|
local HitRes = ACF_PropDamage( Entity, Energy, FrAera * Mul, Angle, Inflictor ) --Calling the standard damage prop function
|
|
|
|
return HitRes --This function needs to return HitRes
|
|
end
|
|
|
|
function ENT:Think()
|
|
|
|
local Time = CurTime()
|
|
|
|
if self.Active2 then
|
|
if self.Legal then
|
|
self:CalcRPM()
|
|
end
|
|
|
|
if self.LastCheck < CurTime() then
|
|
self:CheckRopes()
|
|
self:CheckFuel()
|
|
self:CheckExtra()
|
|
self:CalcMassRatio()
|
|
self.Legal = self:CheckLegal()
|
|
|
|
self.LastCheck = Time + math.Rand(5, 10)
|
|
end
|
|
end
|
|
|
|
self.LastThink = Time
|
|
self:NextThink( Time )
|
|
return true
|
|
|
|
end
|
|
|
|
function ENT:CheckLegal()
|
|
|
|
-- make sure weight is not below stock
|
|
if self:GetPhysicsObject():GetMass() < self.Weight then return false end
|
|
|
|
-- if it's not parented we're fine
|
|
if not IsValid( self:GetParent() ) then return true end
|
|
|
|
-- but not if it's parented to a parented prop
|
|
if IsValid( self:GetParent():GetParent() ) then return false end
|
|
|
|
-- parenting is only legal if it's also welded
|
|
for k, v in pairs( constraint.FindConstraints( self, "Weld" ) ) do
|
|
|
|
if v.Ent1 == self:GetParent() or v.Ent2 == self:GetParent() then return true end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
function ENT:CalcMassRatio()
|
|
|
|
local Mass = 0
|
|
local PhysMass = 0
|
|
|
|
-- get the shit that is physically attached to the vehicle
|
|
local PhysEnts = ACF_GetAllPhysicalConstraints( self )
|
|
|
|
-- add any parented but not constrained props you sneaky bastards
|
|
local AllEnts = table.Copy( PhysEnts )
|
|
for k, v in pairs( PhysEnts ) do
|
|
|
|
table.Merge( AllEnts, ACF_GetAllChildren( v ) )
|
|
|
|
end
|
|
|
|
for k, v in pairs( AllEnts ) do
|
|
|
|
if not IsValid( v ) then continue end
|
|
|
|
local phys = v:GetPhysicsObject()
|
|
if not IsValid( phys ) then continue end
|
|
|
|
Mass = Mass + phys:GetMass()
|
|
|
|
if PhysEnts[ v ] then
|
|
PhysMass = PhysMass + phys:GetMass()
|
|
end
|
|
|
|
end
|
|
|
|
self.MassRatio = PhysMass / Mass
|
|
|
|
Wire_TriggerOutput( self, "Mass", math.Round( Mass, 2 ) )
|
|
Wire_TriggerOutput( self, "Physical Mass", math.Round( PhysMass, 2 ) )
|
|
|
|
end
|
|
|
|
function ENT:ACFInit()
|
|
|
|
self:CalcMassRatio()
|
|
|
|
self.LastThink = CurTime()
|
|
self.Torque = self.PeakTorqueAdd+self.PeakTorqueExtra
|
|
self.FlyRPM = self.IdleRPM * 1.5
|
|
|
|
end
|
|
|
|
function ENT:CalcRPM()
|
|
|
|
local DeltaTime = CurTime() - self.LastThink
|
|
|
|
--find first active tank with fuel
|
|
local Tank = nil
|
|
local boost = 1
|
|
for _,fueltank in pairs(self.FuelLink) do
|
|
if fueltank.Fuel > 0 and fueltank.Active then Tank = fueltank break end
|
|
if fueltank.Fuel <= 0 or not fueltank.Active then Tank = false break end
|
|
end
|
|
if (not Tank) and self.RequiresFuel == 1 then --make sure we've got a tank with fuel if needed
|
|
self:TriggerInput( "Active" , 0 )
|
|
end
|
|
|
|
--calculate fuel usage
|
|
if Tank then
|
|
local Consumption
|
|
if self.FuelType == "Electric" then
|
|
Consumption = (self.Torque * self.FlyRPM / 9548.8) * self.FuelUse * DeltaTime
|
|
else
|
|
local Load = 0.3 + self.Throttle * 0.7
|
|
Consumption = Load * self.FuelUse * (self.FlyRPM / self.PeakKwRPM) * DeltaTime / ACF.FuelDensity[Tank.FuelType]
|
|
end
|
|
Tank.Fuel = math.max(Tank.Fuel - Consumption,0)
|
|
boost = ACF.TorqueBoost
|
|
Wire_TriggerOutput(self, "Fuel Use", math.Round(60*Consumption/DeltaTime,3))
|
|
self.Fuelusing = math.Round((60*Consumption/DeltaTime),3)
|
|
else
|
|
Wire_TriggerOutput(self, "Fuel Use", 0)
|
|
end
|
|
|
|
--Function Calling
|
|
self:UpdateOverlayText() --Update GUI
|
|
for Key, Extra in pairs(self.ExtraLink) do --Update Power with Extra Link
|
|
if IsValid( Extra ) then
|
|
self:AddExtraValue( )
|
|
end
|
|
end
|
|
|
|
--adjusting performance based on damage
|
|
self.TorqueMult = math.Clamp(((1 - self.TorqueScale) / (0.5)) * ((self.ACF.Health/self.ACF.MaxHealth) - 1) + 1, self.TorqueScale, 1)
|
|
self.PeakTorque = (self.PeakTorqueAdd+self.PeakTorqueExtra) * self.TorqueMult
|
|
|
|
-- Calculate the current torque from flywheel RPM
|
|
self.Torque = boost * self.Throttle * math.max( self.PeakTorque * math.min( self.FlyRPM / self.PeakMinRPM, (self.LimitRPM - self.FlyRPM) / (self.LimitRPM - self.PeakMaxRPM), 1 ), 0 )
|
|
|
|
self.Inertia = self.FlywheelMassValue*(3.1416)^2
|
|
|
|
local Drag
|
|
local TorqueDiff
|
|
if self.Active then
|
|
if( self.CutMode == 0 ) then
|
|
self.Torque = boost * self.Throttle * math.max( self.PeakTorque * math.min( self.FlyRPM / self.PeakMinRPM , ((self.LimitRPM+self.LimitRPMExtra) - self.FlyRPM) / ((self.LimitRPM+self.LimitRPMExtra) - (self.PeakMaxRPM+self.PeakMaxRPMExtra)), 1 ), 0 )
|
|
|
|
if self.iselec == true then
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - self.IdleRPM, 0) / self.FlywheelOverride) * (1 - self.Throttle) / self.Inertia
|
|
else
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - self.IdleRPM, 0) / (self.PeakMaxRPM+self.PeakMaxRPMExtra)) * ( 1 - self.Throttle) / self.Inertia
|
|
end
|
|
|
|
elseif( self.CutMode == 1 ) then
|
|
self.Torque = boost * 0 * math.max( self.PeakTorque * math.min( self.FlyRPM / self.PeakMinRPM , ((self.LimitRPM+self.LimitRPMExtra) - self.FlyRPM) / ((self.LimitRPM+self.LimitRPMExtra) - (self.PeakMaxRPM+self.PeakMaxRPMExtra)), 1 ), 0 )
|
|
|
|
if self.iselec == true then
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - self.IdleRPM, 0) / self.FlywheelOverride) * (1 - 0) / self.Inertia
|
|
else
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - self.IdleRPM, 0) / (self.PeakMaxRPM+self.PeakMaxRPMExtra)) * ( 1 - 0) / self.Inertia
|
|
end
|
|
|
|
end
|
|
-- Let's accelerate the flywheel based on that torque
|
|
self.FlyRPM = math.max( self.FlyRPM + self.Torque / self.Inertia - Drag, 1 )
|
|
if self.DisableAutoClutch == 0 then
|
|
-- This is the presently avaliable torque from the engine
|
|
TorqueDiff = math.max( self.FlyRPM - self.IdleRPM, 0 ) * self.Inertia
|
|
elseif self.DisableAutoClutch == 1 then
|
|
TorqueDiff = 0
|
|
end
|
|
|
|
end
|
|
|
|
if( self.Active == false ) then
|
|
self.Torque = boost * 0 * math.max( self.PeakTorque * math.min( self.FlyRPM / self.PeakMinRPM , ((self.LimitRPM+self.LimitRPMExtra) - self.FlyRPM) / ((self.LimitRPM+self.LimitRPMExtra) - (self.PeakMaxRPM+self.PeakMaxRPMExtra)), 1 ), 0 )
|
|
if self.iselec == true then
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - 0, 0) / self.FlywheelOverride) * (1 - 0) / self.Inertia
|
|
else
|
|
Drag = self.PeakTorque * (math.max( self.FlyRPM - 0, 0) / (self.PeakMaxRPM+self.PeakMaxRPMExtra)) * ( 1 - 0) / self.Inertia
|
|
end
|
|
|
|
-- Let's accelerate the flywheel based on that torque
|
|
self.FlyRPM = math.max( self.FlyRPM + self.Torque / self.Inertia - Drag, 1 )
|
|
-- This is the presently avaliable torque from the engine
|
|
TorqueDiff = 0
|
|
|
|
end
|
|
--##############
|
|
-- The gearboxes don't think on their own, it's the engine that calls them, to ensure consistent execution order
|
|
local Boxes = table.Count( self.GearLink )
|
|
local TotalReqTq = 0
|
|
-- Get the requirements for torque for the gearboxes (Max clutch rating minus any wheels currently spinning faster than the Flywheel)
|
|
for Key, Link in pairs( self.GearLink ) do
|
|
if not Link.Ent.Legal then continue end
|
|
|
|
Link.ReqTq = Link.Ent:Calc( self.FlyRPM, self.Inertia )
|
|
TotalReqTq = TotalReqTq + Link.ReqTq
|
|
end
|
|
-- Calculate the ratio of total requested torque versus what's avaliable
|
|
local AvailRatio = math.min( TorqueDiff / TotalReqTq / Boxes, 1 )
|
|
-- Split the torque fairly between the gearboxes who need it
|
|
for Key, Link in pairs( self.GearLink ) do
|
|
if not Link.Ent.Legal then continue end
|
|
Link.Ent:Act( Link.ReqTq * AvailRatio * self.MassRatio, DeltaTime )
|
|
end
|
|
|
|
if self.DisableAutoClutch == 0 then
|
|
self.FlyRPM = self.FlyRPM - math.min( TorqueDiff, TotalReqTq ) / self.Inertia
|
|
elseif self.DisableAutoClutch == 1 then
|
|
self.FlyRPM = self.GearboxRpm*0.8
|
|
end
|
|
--#######################################
|
|
if( self.DisableCut == 0 ) then
|
|
if( self.FlyRPM >= self.CutRpm and self.CutMode == 0 and self.DisableAutoClutch == 0 ) then
|
|
self.CutMode = 1
|
|
if self.Sound then
|
|
self.Sound:Stop()
|
|
end
|
|
self.Sound = nil
|
|
self.Sound2 = CreateSound(self, "acf_other/penetratingshots/00000293.wav")
|
|
self.Sound2:PlayEx(0.5,100)
|
|
end
|
|
if( self.FlyRPM <= self.CutRpm - self.CutValue and self.CutMode == 1 ) then
|
|
self.CutMode = 0
|
|
self.Sound = CreateSound(self, self.SoundPath)
|
|
self.Sound:PlayEx(0.5,100)
|
|
if self.Sound2 then
|
|
self.Sound2:Stop()
|
|
end
|
|
end
|
|
elseif( self.DisableCut == 1 ) then
|
|
self.CutMode = 0
|
|
end
|
|
if( self.FlyRPM <= 50 and self.Active == false ) then
|
|
self.Active2 = false
|
|
self.FlyRPM = 0
|
|
if self.Sound then
|
|
self.Sound:Stop()
|
|
end
|
|
self.Sound = nil
|
|
self:UpdateOverlayText()
|
|
end
|
|
|
|
--SET RPM FOR EXTRA
|
|
for Key, Extra in pairs(self.ExtraLink) do
|
|
if IsValid( Extra ) then
|
|
if Extra.KickRpmNumber > 0 then --Send Rpm for vtec
|
|
if not Extra.Legal then continue end
|
|
Extra:GetRPM( self.FlyRPM )
|
|
end
|
|
end
|
|
end
|
|
--#######################################
|
|
-- Then we calc a smoothed RPM value for the sound effects
|
|
table.remove( self.RPM, 10 )
|
|
table.insert( self.RPM, 1, self.FlyRPM )
|
|
local SmoothRPM = 0
|
|
for Key, RPM in pairs( self.RPM ) do
|
|
SmoothRPM = SmoothRPM + (RPM or 0)
|
|
end
|
|
SmoothRPM = SmoothRPM / 10
|
|
|
|
local Power = self.Torque * SmoothRPM / 9548.8
|
|
Wire_TriggerOutput(self, "Torque", math.floor(self.Torque))
|
|
Wire_TriggerOutput(self, "Power", math.floor(Power))
|
|
Wire_TriggerOutput(self, "RPM", self.FlyRPM)
|
|
|
|
if self.Sound then
|
|
self.Sound:ChangePitch( math.min( 20 + (SmoothRPM * self.SoundPitch) / 50, 255 ), 0 )
|
|
self.Sound:ChangeVolume( 0.25 + (0.1 + 0.9 * ((SmoothRPM / (self.LimitRPM+self.LimitRPMExtra)) ^ 1.5)) * self.Throttle / 1.5, 0 )
|
|
end
|
|
|
|
return RPM
|
|
end
|
|
|
|
function ENT:CheckRopes()
|
|
for Key, Link in pairs( self.GearLink ) do
|
|
local Ent = Link.Ent
|
|
-- make sure the rope is still there
|
|
if not IsValid( Link.Rope ) then
|
|
self:Unlink( Ent )
|
|
continue end
|
|
|
|
local OutPos = self:LocalToWorld( self.Out )
|
|
local InPos = Ent:LocalToWorld( Ent.In )
|
|
-- make sure it is not stretched too far
|
|
if OutPos:Distance( InPos ) > Link.RopeLen * 1.5 then
|
|
self:Unlink( Ent )
|
|
continue end
|
|
-- make sure the angle is not excessive
|
|
local Direction
|
|
if self.IsTrans then Direction = -self:GetRight() else Direction = self:GetForward() end
|
|
|
|
local DrvAngle = ( OutPos - InPos ):GetNormalized():DotProduct( Direction )
|
|
if DrvAngle < 0.7 then
|
|
self:Unlink( Ent )
|
|
end
|
|
end
|
|
end
|
|
|
|
--unlink fuel tanks out of range
|
|
function ENT:CheckFuel()
|
|
for _,tank in pairs(self.FuelLink) do
|
|
if self:GetPos():Distance(tank:GetPos()) > 512 then
|
|
self:Unlink( tank )
|
|
soundstr = "physics/metal/metal_box_impact_bullet" .. tostring(math.random(1, 3)) .. ".wav"
|
|
self:EmitSound(soundstr,500,100)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ENT:Link( Target )
|
|
--Allowable Target
|
|
--if not IsValid( Target ) or Target:GetClass() ~= "acf_gearbox" and Target:GetClass() ~= "acf_fueltank" and Target:GetClass() ~= "acf_gearboxcvt" and Target:GetClass() ~= "acf_chips" and Target:GetClass() ~= "acf_nos" and Target:GetClass() ~= "acf_gearboxauto" then
|
|
if not IsValid( Target ) or not table.HasValue( { "acf_gearbox", "acf_gearboxcvt", "acf_gearboxauto", "acf_fueltank", "acf_chips", "acf_nos" }, Target:GetClass() ) then
|
|
return false, "Can only link to gearboxes, fuel tanks or engine extras!"
|
|
end
|
|
|
|
if Target:GetClass() == "acf_fueltank" then
|
|
return self:LinkFuel( Target )
|
|
end
|
|
--Link Extra Object
|
|
if self.ExtraUsing == 1 then --Not link severals Extra Object
|
|
return false, "You CAN'T use more that one Extra!"
|
|
end
|
|
if Target:GetClass() == "acf_chips" or Target:GetClass() == "acf_nos" then
|
|
if self.EngineType == "Turbine" or self.EngineType == "Electric" then
|
|
return false, "You CAN'T link Extra to this engine type!"
|
|
else
|
|
return self:LinkExtra( Target )
|
|
end
|
|
end
|
|
|
|
-- Check if target is already linked
|
|
for Key, Link in pairs( self.GearLink ) do
|
|
if Link.Ent == Target then
|
|
return false, "That is already linked to this engine!"
|
|
end
|
|
end
|
|
|
|
-- make sure the angle is not excessive
|
|
local InPos = Target:LocalToWorld( Target.In )
|
|
local OutPos = self:LocalToWorld( self.Out )
|
|
|
|
local Direction
|
|
if self.IsTrans then Direction = -self:GetRight() else Direction = self:GetForward() end
|
|
|
|
local DrvAngle = ( OutPos - InPos ):GetNormalized():DotProduct( Direction )
|
|
if DrvAngle < 0.7 then
|
|
return false, "Cannot link due to excessive driveshaft angle!"
|
|
end
|
|
|
|
local Rope = constraint.CreateKeyframeRope( OutPos, 1, "cable/cable2", nil, self, self.Out, 0, Target, Target.In, 0 )
|
|
|
|
local Link = {
|
|
Ent = Target,
|
|
Rope = Rope,
|
|
RopeLen = ( OutPos - InPos ):Length(),
|
|
ReqTq = 0
|
|
}
|
|
|
|
table.insert( self.GearLink, Link )
|
|
table.insert( Target.Master, self )
|
|
|
|
return true, "Link successful!"
|
|
end
|
|
|
|
function ENT:Unlink( Target )
|
|
|
|
if Target:GetClass() == "acf_fueltank" then
|
|
return self:UnlinkFuel( Target )
|
|
end
|
|
--unlink extra
|
|
if Target:GetClass() == "acf_chips" or Target:GetClass() == "acf_nos" then
|
|
return self:UnlinkExtra( Target )
|
|
end
|
|
|
|
for Key, Link in pairs( self.GearLink ) do
|
|
|
|
if Link.Ent == Target then
|
|
|
|
-- Remove any old physical ropes leftover from dupes
|
|
for Key, Rope in pairs( constraint.FindConstraints( Link.Ent, "Rope" ) ) do
|
|
if Rope.Ent1 == self or Rope.Ent2 == self then
|
|
Rope.Constraint:Remove()
|
|
end
|
|
end
|
|
|
|
if IsValid( Link.Rope ) then
|
|
Link.Rope:Remove()
|
|
end
|
|
|
|
table.remove( self.GearLink,Key )
|
|
|
|
return true, "Unlink successful!"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false, "That gearbox is not linked to this engine!"
|
|
|
|
end
|
|
|
|
function ENT:LinkFuel( Target )
|
|
|
|
if not (self.FuelType == "Any" and not (Target.FuelType == "Electric")) then
|
|
if self.FuelType ~= Target.FuelType then
|
|
return false, "Cannot link because fuel type is incompatible."
|
|
end
|
|
end
|
|
|
|
if Target.NoLinks then
|
|
return false, "This fuel tank doesn\'t allow linking."
|
|
end
|
|
|
|
for Key,Value in pairs(self.FuelLink) do
|
|
if Value == Target then
|
|
return false, "That fuel tank is already linked to this engine!"
|
|
end
|
|
end
|
|
|
|
if self:GetPos():Distance( Target:GetPos() ) > 512 then
|
|
return false, "Fuel tank is too far away."
|
|
end
|
|
|
|
table.insert( self.FuelLink, Target )
|
|
table.insert( Target.Master, self )
|
|
|
|
self.RequiresFuel = 1
|
|
self:UpdateOverlayText()
|
|
|
|
return true, "Link successful! Now Require Fuel"
|
|
|
|
end
|
|
|
|
function ENT:UnlinkFuel( Target )
|
|
|
|
for Key, Value in pairs( self.FuelLink ) do
|
|
if Value == Target then
|
|
self.RequiresFuel = 0
|
|
self:UpdateOverlayText()
|
|
table.remove( self.FuelLink, Key )
|
|
return true, "Unlink successful! Now NOT Require Fuel"
|
|
end
|
|
end
|
|
|
|
return false, "That fuel tank is not linked to this engine!"
|
|
|
|
end
|
|
--LINKING EXTRA
|
|
function ENT:LinkExtra( Target )
|
|
|
|
for Key,Value in pairs(self.ExtraLink) do
|
|
if Value == Target then
|
|
return false, "It's already linked to this engine!"
|
|
end
|
|
end
|
|
|
|
if self:GetPos():Distance( Target:GetPos() ) > 512 then
|
|
return false, "The Extra is too far away."
|
|
end
|
|
|
|
table.insert( self.ExtraLink, Target )
|
|
table.insert( Target.Master, self )
|
|
|
|
self:AddExtraValue( ) --Add Values
|
|
self.ExtraUsing = 1 --Set Using Extra to 1
|
|
|
|
return true, "Link successful!"
|
|
end
|
|
--UNLINK EXTRA
|
|
function ENT:UnlinkExtra( Target )
|
|
|
|
for Key, Value in pairs( self.ExtraLink ) do
|
|
if Value == Target then
|
|
self:RemoveExtraValue( ) --Remove values
|
|
self.ExtraUsing = 0 --Set Using Extra to 0
|
|
table.remove( self.ExtraLink, Key )
|
|
return true, "Unlink successful!"
|
|
end
|
|
end
|
|
|
|
return false, "That's not linked to this engine!"
|
|
|
|
end
|
|
--UNLINK EXTRA out of range
|
|
function ENT:CheckExtra()
|
|
for _,extra in pairs(self.ExtraLink) do
|
|
if self:GetPos():Distance(extra:GetPos()) > 512 then
|
|
self:Unlink( extra )
|
|
self:RemoveExtraValue( ) --Remove values
|
|
self.ExtraUsing = 0 --Set Using Extra to 0
|
|
soundstr = "physics/metal/metal_box_impact_bullet" .. tostring(math.random(1, 3)) .. ".wav"
|
|
self:EmitSound(soundstr,500,100)
|
|
end
|
|
end
|
|
end
|
|
--ADD EXTRA SETTINGS FUNCTION
|
|
function ENT:AddExtraValue( )
|
|
for Key, Extra in pairs(self.ExtraLink) do
|
|
if IsValid( Extra ) then
|
|
self.PeakTorqueExtra = (Extra.TorqueAdd or 0)
|
|
self.PeakMaxRPMExtra = (Extra.MaxRPMAdd or 0)
|
|
self.LimitRPMExtra = (Extra.LimitRPMAdd or 0)
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
end
|
|
end
|
|
--REMOVE EXTRA SETTINGS FUNCTION
|
|
function ENT:RemoveExtraValue( )
|
|
for Key, Extra in pairs(self.ExtraLink) do
|
|
if IsValid( Extra ) then
|
|
self.PeakTorqueExtra = 0
|
|
self.PeakMaxRPMExtra = 0
|
|
self.LimitRPMExtra = 0
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
end
|
|
end
|
|
--SET THE ENGINE BLOWED (RADIATOR)
|
|
function ENT:SetBlow()
|
|
self.Active = false
|
|
self:TriggerInput( "Active" , 0 )
|
|
end
|
|
--SET ENGINE TORQUE WITH HIS HEALTH (RADIATOR)
|
|
function ENT:SetEngineHealth(RadiatorHealth)
|
|
local TorqueBand = (self.PeakTorqueAdd+self.PeakTorqueExtra)/2
|
|
if RadiatorHealth > 0 then
|
|
self.PeakTorqueHealth = math.abs(((TorqueBand*(RadiatorHealth-100))/-100))
|
|
end
|
|
self:UpdateEngineConsumption()
|
|
end
|
|
|
|
function ENT:PreEntityCopy()
|
|
|
|
//Link Saving
|
|
local info = {}
|
|
local entids = {}
|
|
for Key, Link in pairs( self.GearLink ) do --First clean the table of any invalid entities
|
|
if not IsValid( Link.Ent ) then
|
|
table.remove( self.GearLink, Key )
|
|
end
|
|
end
|
|
for Key, Link in pairs( self.GearLink ) do --Then save it
|
|
table.insert( entids, Link.Ent:EntIndex() )
|
|
end
|
|
|
|
info.entities = entids
|
|
if info.entities then
|
|
duplicator.StoreEntityModifier( self, "GearLink", info )
|
|
end
|
|
|
|
--fuel tank link saving
|
|
local fuel_info = {}
|
|
local fuel_entids = {}
|
|
for Key, Value in pairs(self.FuelLink) do --First clean the table of any invalid entities
|
|
if not Value:IsValid() then
|
|
table.remove(self.FuelLink, Value)
|
|
end
|
|
end
|
|
for Key, Value in pairs(self.FuelLink) do --Then save it
|
|
table.insert(fuel_entids, Value:EntIndex())
|
|
end
|
|
|
|
fuel_info.entities = fuel_entids
|
|
if fuel_info.entities then
|
|
duplicator.StoreEntityModifier( self, "FuelLink", fuel_info )
|
|
end
|
|
|
|
--extra link saving
|
|
local extra_info = {}
|
|
local extra_entids = {}
|
|
for Key, Value in pairs(self.ExtraLink) do --First clean the table of any invalid entities
|
|
if not Value:IsValid() then
|
|
table.remove(self.ExtraLink, Value)
|
|
end
|
|
end
|
|
for Key, Value in pairs(self.ExtraLink) do --Then save it
|
|
table.insert(extra_entids, Value:EntIndex())
|
|
end
|
|
|
|
extra_info.entities = extra_entids
|
|
if extra_info.entities then
|
|
duplicator.StoreEntityModifier( self, "ExtraLink", extra_info )
|
|
end
|
|
|
|
//Wire dupe info
|
|
self.BaseClass.PreEntityCopy( self )
|
|
|
|
end
|
|
|
|
function ENT:PostEntityPaste( Player, Ent, CreatedEntities )
|
|
|
|
//Link Pasting
|
|
if (Ent.EntityMods) and (Ent.EntityMods.GearLink) and (Ent.EntityMods.GearLink.entities) then
|
|
local GearLink = Ent.EntityMods.GearLink
|
|
if GearLink.entities and table.Count(GearLink.entities) > 0 then
|
|
timer.Simple( 0, function() -- this timer is a workaround for an ad2/makespherical issue https://github.com/nrlulz/ACF/issues/14#issuecomment-22844064
|
|
for _,ID in pairs(GearLink.entities) do
|
|
local Linked = CreatedEntities[ ID ]
|
|
if IsValid( Linked ) then
|
|
self:Link( Linked )
|
|
end
|
|
end
|
|
end )
|
|
end
|
|
Ent.EntityMods.GearLink = nil
|
|
end
|
|
|
|
--fuel tank link Pasting
|
|
if (Ent.EntityMods) and (Ent.EntityMods.FuelLink) and (Ent.EntityMods.FuelLink.entities) then
|
|
local FuelLink = Ent.EntityMods.FuelLink
|
|
if FuelLink.entities and table.Count(FuelLink.entities) > 0 then
|
|
for _,ID in pairs(FuelLink.entities) do
|
|
local Linked = CreatedEntities[ ID ]
|
|
if IsValid( Linked ) then
|
|
self.RequiresFuel = 1
|
|
self:UpdateOverlayText()
|
|
self:Link( Linked )
|
|
end
|
|
end
|
|
end
|
|
Ent.EntityMods.FuelLink = nil
|
|
end
|
|
|
|
--Extra link Pasting
|
|
if (Ent.EntityMods) and (Ent.EntityMods.ExtraLink) and (Ent.EntityMods.ExtraLink.entities) then
|
|
local ExtraLink = Ent.EntityMods.ExtraLink
|
|
if ExtraLink.entities and table.Count(ExtraLink.entities) > 0 then
|
|
for _,ID in pairs(ExtraLink.entities) do
|
|
local Linked = CreatedEntities[ ID ]
|
|
if IsValid( Linked ) then
|
|
self:Link( Linked )
|
|
end
|
|
end
|
|
end
|
|
Ent.EntityMods.ExtraLink = nil
|
|
end
|
|
|
|
//Wire dupe info
|
|
self.BaseClass.PostEntityPaste( self, Player, Ent, CreatedEntities )
|
|
|
|
end
|
|
|
|
function ENT:OnRemove()
|
|
if self.Sound then
|
|
self.Sound:Stop()
|
|
end
|
|
end
|