Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- AddCSLuaFile()
- ACF.AmmoBlacklist.APDS = { "ATR", "MO", "RM", "SL", "GL", "HW", "MG", "SC", "BOMB" , "GBU", "ASM", "AAM", "SAM", "UAR", "POD", "FFAR"} -- Yes, I know I left the flare launcher out, deal with it
- local Round = {}
- Round.type = "Ammo" --Tells the spawn menu what entity to spawn
- Round.name = "Armour Piercing Discarding Sabot (APDS)" --Human readable name
- Round.model = "models/munitions/dart_100mm.mdl" --Shell flight model
- Round.desc = "A shell that contains a subcaliber round, dedicated to penetrating heavy armour, if fired out a smoothbore then the round is fin stabilized and recieves an accuracy boost and richochets less"
- Round.netid = 9 --Unique ammotype ID for network transmission
- function Round.create( Gun, BulletData )
- ACF_CreateBullet( BulletData )
- end
- -- Function to convert the player's slider data into the complete round data
- function Round.convert( Crate, PlayerData )
- local Data = {}
- local ServerData = {}
- local GUIData = {}
- if not PlayerData.PropLength then PlayerData.PropLength = 0 end
- if not PlayerData.ProjLength then PlayerData.ProjLength = 0 end
- if not PlayerData.SCalMult then PlayerData.SCalMult = 0.5 end
- if not PlayerData["Data5"] then PlayerData["Data5"] = 0.5 end --caliber in mm count
- if not PlayerData.Data10 then PlayerData.Data10 = 0 end
- PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder( PlayerData, Data, ServerData, GUIData )
- local GunClass = ACF.Weapons["Guns"][(Data["Id"] or PlayerData["Id"])]["gunclass"]
- if GunClass == "AC" then
- Data.MinCalMult = 0.35
- Data.MaxCalMult = 1.0
- Data.PenModifier = 2 -- Autocannons are puny anyways
- Data.VelModifier = 1.6
- Data.Ricochet = 55
- elseif GunClass == "RAC" then
- Data.MinCalMult = 0.5
- Data.MaxCalMult = 1.0
- Data.PenModifier = 1.8
- Data.VelModifier = 1.7
- Data.Ricochet = 50
- elseif GunClass == "HRAC" then
- Data.MinCalMult = 0.5
- Data.MaxCalMult = 1.0
- Data.PenModifier = 1.9
- Data.VelModifier = 1.7
- Data.Ricochet = 50
- elseif GunClass == "SA" then
- Data.MinCalMult = 0.3
- Data.MaxCalMult = 1.0
- Data.PenModifier = 2
- Data.VelModifier = 1.6
- Data.Ricochet = 60
- elseif GunClass == "C" then
- Data.MinCalMult = 0.28
- Data.MaxCalMult = 1.0
- Data.PenModifier = 1.35
- Data.VelModifier = 1
- Data.Ricochet = 62
- else
- Data.MinCalMult = 0.25
- Data.MaxCalMult = 1.0
- Data.PenModifier = 1
- Data.VelModifier = 1
- Data.Ricochet = 68
- end
- Data.SCalMult = PlayerData["Data5"]
- Data.SubFrAera = Data.FrAera * math.min(PlayerData.Data5,Data.MaxCalMult)^2
- Data.ProjMass = Data.SubFrAera * (Data.ProjLength*7.9/1000) * 2.5 --Volume of the projectile as a cylinder * density of steel
- Data.ShovePower = 0.2
- Data.PenAera = (Data.PenModifier*Data.SubFrAera)^ACF.PenAreaMod
- Data.DragCoef = ((Data.SubFrAera/10000)/Data.ProjMass)
- Data.CaliberMod = Data.Caliber*math.min(PlayerData.Data5,Data.MaxCalMult)
- Data.LimitVel = 1000 --Most efficient penetration speed in m/s
- Data.KETransfert = 0.2 --Kinetic energy transfert to the target for movement purposes
- Data.MuzzleVel = ACF_MuzzleVelocity( Data.PropMass * 0.5 , Data.ProjMass*2.5, Data.Caliber )* Data.VelModifier
- Data.BoomPower = Data.PropMass
- if SERVER then --Only the crates need this part
- ServerData.Id = PlayerData.Id
- ServerData.Type = PlayerData.Type
- return table.Merge(Data,ServerData)
- end
- if CLIENT then --Only tthe GUI needs this part
- GUIData = table.Merge(GUIData, Round.getDisplayData(Data))
- return table.Merge(Data,GUIData)
- end
- end
- function Round.getDisplayData(Data)
- local GUIData = {}
- local Energy = ACF_Kinetic( Data.MuzzleVel*39.37 , Data.ProjMass, Data.LimitVel )
- GUIData.MaxPen = (Energy.Penetration/Data.PenAera)*ACF.KEtoRHA
- return GUIData
- end
- function Round.network( Crate, BulletData )
- Crate:SetNWString( "AmmoType", "APDS" )
- Crate:SetNWString( "AmmoID", BulletData.Id )
- Crate:SetNWFloat( "Caliber", BulletData.Caliber )
- Crate:SetNWFloat( "ProjMass", BulletData.ProjMass )
- Crate:SetNWFloat( "PropMass", BulletData.PropMass )
- Crate:SetNWFloat( "DragCoef", BulletData.DragCoef )
- Crate:SetNWFloat( "MuzzleVel", BulletData.MuzzleVel )
- Crate:SetNWFloat( "Tracer", BulletData.Tracer )
- end
- function Round.cratetxt( BulletData )
- --local FrAera = BulletData.FrAera
- local DData = Round.getDisplayData(BulletData)
- --fakeent.ACF.Armour = DData.MaxPen or 0
- --fakepen.Penetration = (DData.MaxPen * FrAera) / ACF.KEtoRHA
- --local fakepen = ACF_Kinetic( BulletData.SlugMV*39.37 , BulletData.SlugMass, 9999999 )
- --local MaxHP = ACF_CalcDamage( fakeent , fakepen , FrAera , 0 )
- --[[
- local TotalMass = BulletData.ProjMass + BulletData.PropMass
- local MassUnit
- if TotalMass < 0.1 then
- TotalMass = TotalMass * 1000
- MassUnit = " g"
- else
- MassUnit = " kg"
- end
- ]]--
- local str =
- {
- --"Cartridge Mass: ", math.Round(TotalMass, 2), MassUnit, "\n",
- "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n",
- "Max Penetration: ", math.floor(DData.MaxPen), " mm"
- --"Max Pen. Damage: ", math.Round(MaxHP.Damage, 1), " HP\n",
- }
- return table.concat(str)
- end
- function Round.propimpact( Index, Bullet, Target, HitNormal, HitPos, Bone )
- if ACF_Check( Target ) then
- local Speed = Bullet.Flight:Length() / ACF.VelScale
- local Energy = ACF_Kinetic( Speed , Bullet.ProjMass, Bullet.LimitVel )
- local HitRes = ACF_RoundImpact( Bullet, Speed, Energy, Target, HitPos, HitNormal , Bone )
- if HitRes.Overkill > 0 then
- table.insert( Bullet.Filter , Target ) --"Penetrate" (Ingoring the prop for the retry trace)
- ACF_Spall( HitPos , Bullet.Flight , Bullet.Filter , Energy.Kinetic*HitRes.Loss , Bullet.Caliber , Target.ACF.Armour , Bullet.Owner ) --Do some spalling
- Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic*(1-HitRes.Loss)*2000/Bullet.ProjMass)^0.5 * 39.37
- return "Penetrated"
- elseif HitRes.Ricochet then
- return "Ricochet"
- else
- return false
- end
- else
- table.insert( Bullet.Filter , Target )
- return "Penetrated" end
- end
- function Round.worldimpact( Index, Bullet, HitPos, HitNormal )
- local Energy = ACF_Kinetic( Bullet.Flight:Length() / ACF.VelScale, Bullet.ProjMass, Bullet.LimitVel )
- local HitRes = ACF_PenetrateGround( Bullet, Energy, HitPos, HitNormal )
- if HitRes.Penetrated then
- return "Penetrated"
- elseif HitRes.Ricochet then
- return "Ricochet"
- else
- return false
- end
- end
- function Round.endflight( Index, Bullet, HitPos )
- ACF_RemoveBullet( Index )
- end
- -- Bullet stops here
- function Round.endeffect( Effect, Bullet )
- local Spall = EffectData()
- Spall:SetEntity( Bullet.Crate )
- Spall:SetOrigin( Bullet.SimPos )
- Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
- Spall:SetScale( Bullet.SimFlight:Length() )
- Spall:SetMagnitude( Bullet.RoundMass )
- util.Effect( "ACF_AP_Impact", Spall )
- end
- -- Bullet penetrated something
- function Round.pierceeffect( Effect, Bullet )
- local Spall = EffectData()
- Spall:SetEntity( Bullet.Crate )
- Spall:SetOrigin( Bullet.SimPos )
- Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
- Spall:SetScale( Bullet.SimFlight:Length() )
- Spall:SetMagnitude( Bullet.RoundMass )
- util.Effect( "ACF_AP_Penetration", Spall )
- end
- -- Bullet ricocheted off something
- function Round.ricocheteffect( Effect, Bullet )
- local Spall = EffectData()
- Spall:SetEntity( Bullet.Crate )
- Spall:SetOrigin( Bullet.SimPos )
- Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
- Spall:SetScale( Bullet.SimFlight:Length() )
- Spall:SetMagnitude( Bullet.RoundMass )
- util.Effect( "ACF_AP_Ricochet", Spall )
- end
- function Round.guicreate( Panel, Table )
- acfmenupanel:AmmoSelect( ACF.AmmoBlacklist.APDS )
- acfmenupanel:CPanelText("BonusDisplay", "")
- acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc)
- acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc)
- acfmenupanel:AmmoSlider("PropLength",0,0,1000,3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc)
- acfmenupanel:AmmoSlider("ProjLength",0,0,1000,3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc)
- acfmenupanel:AmmoSlider("SCalMult",0,0,1000,2, "Subcaliber Size Multiplier", "")--Subcaliber Slider (Name, Value, Min, Max, Decimals, Title, Desc)
- acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc)
- --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance
- acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc)
- Round.guiupdate( Panel, Table )
- end
- function Round.guiupdate( Panel, Table )
- local PlayerData = {}
- PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI
- PlayerData.Type = "APDS" --Hardcoded, match ACFRoundTypes table index
- PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider
- PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider
- PlayerData.Data5 = acfmenupanel.AmmoData.SCalMult
- PlayerData.Data10 = 0
- local Data = Round.convert( Panel, PlayerData )
- RunConsoleCommand( "acfmenu_data1", acfmenupanel.AmmoData.Data.id )
- RunConsoleCommand( "acfmenu_data2", PlayerData.Type )
- RunConsoleCommand( "acfmenu_data3", Data.PropLength ) --For Gun ammo, Data3 should always be Propellant
- RunConsoleCommand( "acfmenu_data4", Data.ProjLength ) --And Data4 total round mass
- RunConsoleCommand( "acfmenu_data5", Data.SCalMult )
- RunConsoleCommand( "acfmenu_data10", 0 )
- local vol = ACF.Weapons.Ammo[acfmenupanel.AmmoData["Id"]].volume
- local CapMul = (vol > 46000) and ((math.log(vol*0.00066)/math.log(2)-4)*0.125+1) or 1
- local RoFMul = (vol > 46000) and (1-(math.log(vol*0.00066)/math.log(2)-4)*0.05) or 1
- local Cap = math.floor(CapMul * vol * 0.11 * ACF.AmmoMod * 16.38 / Data.RoundVolume)
- acfmenupanel:CPanelText("BonusDisplay", "Crate info: +"..(math.Round((CapMul-1)*100,1)).."% capacity, +"..(math.Round((RoFMul-1)*-100,1)).."% RoF\nContains "..Cap.." rounds")
- acfmenupanel:AmmoSlider("PropLength",Data.PropLength,Data.MinPropLength,Data.MaxTotalLength,3, "Propellant Length", "Propellant Mass : "..(math.floor(Data.PropMass*1000)).." g" ) --Propellant Length Slider (Name, Min, Max, Decimals, Title, Desc)
- acfmenupanel:AmmoSlider("ProjLength",Data.ProjLength,Data.MinProjLength,Data.MaxTotalLength,3, "Projectile Length", "Projectile Mass : "..(math.floor(Data.ProjMass*1000)).." g") --Projectile Length Slider (Name, Min, Max, Decimals, Title, Desc)
- acfmenupanel:AmmoSlider("SCalMult",Data.SCalMult,Data.MinCalMult,Data.MaxCalMult,2, "Subcaliber Size Multiplier", "Caliber : "..math.floor(Data.Caliber * math.min(PlayerData.Data5,Data.MaxCalMult)*10).." mm")--Subcaliber round slider (Name, Min, Max, Decimals, Title, Desc)
- acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc)
- acfmenupanel:CPanelText("LengthDisplay", "Round Length : "..(math.floor((Data.PropLength+Data.ProjLength)*100)/100).."/"..(Data.MaxTotalLength).." cm") --Total round length (Name, Desc)
- acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : "..math.floor(Data.MuzzleVel*ACF.VelScale).." m\\s") --Proj muzzle velocity (Name, Desc)
- --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.VelScale )
- --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees")
- local R1V, R1P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 300 )
- local R2V, R2P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 800 )
- acfmenupanel:CPanelText("PenetrationDisplay", "Maximum Penetration : "..math.floor(Data.MaxPen).." mm RHA\n\n300m pen: "..math.Round(R1P,0).."mm @ "..math.Round(R1V,0).." m\\s\n800m pen: "..math.Round(R2P,0).."mm @ "..math.Round(R2V,0).." m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc)
- end
- list.Set( "ACFRoundTypes", "APDS", Round ) --Set the round properties
- list.Set( "ACFIdRounds", Round.netid, "APDS" ) --Index must equal the ID entry in the table above, Data must equal the index of the table above
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement