Advertisement
RedDeadlyCreeper

AP Normalizing

Jul 5th, 2019
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.30 KB | None | 0 0
  1. AddCSLuaFile()
  2.  
  3. ACF.AmmoBlacklist.AP = { "MO", "SL", "GL", "FGL"}
  4.  
  5. local Round = {}
  6.  
  7. Round.type = "Ammo" --Tells the spawn menu what entity to spawn
  8. Round.name = "Armour Piercing (AP)" --Human readable name
  9. Round.model = "models/munitions/round_100mm_shot.mdl" --Shell flight model
  10. Round.desc = "A shell made out of a solid piece of steel, meant to penetrate armour. Has a cap that helps it deal with sloped armor."
  11. Round.netid = 1 --Unique ammotype ID for network transmission
  12.  
  13. function Round.create( Gun, BulletData )
  14.  
  15. ACF_CreateBullet( BulletData )
  16.  
  17. end
  18.  
  19. -- Function to convert the player's slider data into the complete round data
  20. function Round.convert( Crate, PlayerData )
  21.  
  22. local Data = {}
  23. local ServerData = {}
  24. local GUIData = {}
  25.  
  26. if not PlayerData.PropLength then PlayerData.PropLength = 0 end
  27. if not PlayerData.ProjLength then PlayerData.ProjLength = 0 end
  28. if not PlayerData.Data10 then PlayerData.Data10 = 0 end
  29.  
  30. PlayerData, Data, ServerData, GUIData = ACF_RoundBaseGunpowder( PlayerData, Data, ServerData, GUIData )
  31.  
  32. Data.ProjMass = Data.FrAera * (Data.ProjLength*7.9/1000) --Volume of the projectile as a cylinder * density of steel
  33. Data.ShovePower = 0.2
  34. Data.PenAera = Data.FrAera^ACF.PenAreaMod
  35. Data.DragCoef = (Data.FrAera/10000)/Data.ProjMass
  36. Data.LimitVel = 800 --Most efficient penetration speed in m/s
  37. Data.KETransfert = 0.2 --Kinetic energy transfert to the target for movement purposes
  38. Data.Ricochet = 60 --Base ricochet angle
  39. Data.MuzzleVel = ACF_MuzzleVelocity( Data.PropMass, Data.ProjMass, Data.Caliber )
  40.  
  41. Data.BoomPower = Data.PropMass
  42. Data.Normalize = true
  43.  
  44.  
  45. if SERVER then --Only the crates need this part
  46. ServerData.Id = PlayerData.Id
  47. ServerData.Type = PlayerData.Type
  48. return table.Merge(Data,ServerData)
  49. end
  50.  
  51. if CLIENT then --Only tthe GUI needs this part
  52. GUIData = table.Merge(GUIData, Round.getDisplayData(Data))
  53. return table.Merge(Data,GUIData)
  54. end
  55.  
  56. end
  57.  
  58.  
  59. function Round.getDisplayData(Data)
  60. local GUIData = {}
  61. local Energy = ACF_Kinetic( Data.MuzzleVel*39.37 , Data.ProjMass, Data.LimitVel )
  62. GUIData.MaxPen = (Energy.Penetration/Data.PenAera)*ACF.KEtoRHA
  63. return GUIData
  64. end
  65.  
  66.  
  67.  
  68. function Round.network( Crate, BulletData )
  69.  
  70. Crate:SetNWString( "AmmoType", "AP" )
  71. Crate:SetNWString( "AmmoID", BulletData.Id )
  72. Crate:SetNWFloat( "Caliber", BulletData.Caliber )
  73. Crate:SetNWFloat( "ProjMass", BulletData.ProjMass )
  74. Crate:SetNWFloat( "PropMass", BulletData.PropMass )
  75. Crate:SetNWFloat( "DragCoef", BulletData.DragCoef )
  76. Crate:SetNWFloat( "MuzzleVel", BulletData.MuzzleVel )
  77. Crate:SetNWFloat( "Tracer", BulletData.Tracer )
  78.  
  79. end
  80.  
  81. function Round.cratetxt( BulletData )
  82.  
  83. --local FrAera = BulletData.FrAera
  84. local DData = Round.getDisplayData(BulletData)
  85.  
  86. --fakeent.ACF.Armour = DData.MaxPen or 0
  87. --fakepen.Penetration = (DData.MaxPen * FrAera) / ACF.KEtoRHA
  88. --local fakepen = ACF_Kinetic( BulletData.SlugMV*39.37 , BulletData.SlugMass, 9999999 )
  89. --local MaxHP = ACF_CalcDamage( fakeent , fakepen , FrAera , 0 )
  90.  
  91. --[[
  92. local TotalMass = BulletData.ProjMass + BulletData.PropMass
  93. local MassUnit
  94.  
  95. if TotalMass < 0.1 then
  96. TotalMass = TotalMass * 1000
  97. MassUnit = " g"
  98. else
  99. MassUnit = " kg"
  100. end
  101. ]]--
  102.  
  103. local str =
  104. {
  105. --"Cartridge Mass: ", math.Round(TotalMass, 2), MassUnit, "\n",
  106. "Muzzle Velocity: ", math.Round(BulletData.MuzzleVel, 1), " m/s\n",
  107. "Max Penetration: ", math.floor(DData.MaxPen), " mm"
  108. --"Max Pen. Damage: ", math.Round(MaxHP.Damage, 1), " HP\n",
  109. }
  110.  
  111. return table.concat(str)
  112.  
  113. end
  114.  
  115.  
  116. function Round.normalize( Index, Bullet, HitPos, HitNormal, Target)
  117. Bullet.Normalize = false
  118. Bullet.Pos = HitPos
  119. local FlightNormal = Bullet.Flight:GetNormalized() + (HitNormal-Bullet.Flight:GetNormalized()) * ACF.NormalizationFactor
  120. local Speed = Bullet.Flight:Length()
  121. Bullet.Flight = FlightNormal * Speed
  122.  
  123. local DeltaTime = SysTime() - Bullet.LastThink
  124. Bullet.StartTrace = Bullet.Pos - Bullet.Flight:GetNormalized()*math.min(ACF.PhysMaxVel*DeltaTime,Bullet.FlightTime*Bullet.Flight:Length())
  125. Bullet.NextPos = Bullet.Pos + (Bullet.Flight * ACF.VelScale * DeltaTime)
  126. end
  127.  
  128. function Round.propimpact( Index, Bullet, Target, HitNormal, HitPos, Bone )
  129.  
  130. if ACF_Check( Target ) then
  131.  
  132. if not Bullet.Normalize then
  133. -- print("PropHit")
  134. local Speed = Bullet.Flight:Length() / ACF.VelScale
  135. local Energy = ACF_Kinetic( Speed , Bullet.ProjMass, Bullet.LimitVel )
  136. local HitRes = ACF_RoundImpact( Bullet, Speed, Energy, Target, HitPos, HitNormal , Bone )
  137.  
  138. if HitRes.Overkill > 0 then
  139. table.insert( Bullet.Filter , Target ) --"Penetrate" (Ingoring the prop for the retry trace)
  140. ACF_Spall( HitPos , Bullet.Flight , Bullet.Filter , Energy.Kinetic*HitRes.Loss , Bullet.Caliber , Target.ACF.Armour , Bullet.Owner , Target.ACF.Material) --Do some spalling
  141. Bullet.Flight = Bullet.Flight:GetNormalized() * (Energy.Kinetic*(1-HitRes.Loss)*2000/Bullet.ProjMass)^0.5 * 39.37
  142. Bullet.Normalize = true
  143. return "Penetrated"
  144. elseif HitRes.Ricochet then
  145. Bullet.Normalize = true
  146. return "Ricochet"
  147. else
  148. return false
  149. end
  150. else
  151. Round.normalize( Index, Bullet, HitPos, HitNormal, Target)
  152. -- print("Normalize")
  153. return "Penetrated"
  154. end
  155. else
  156. table.insert( Bullet.Filter , Target )
  157. return "Penetrated" end
  158.  
  159. end
  160.  
  161. function Round.worldimpact( Index, Bullet, HitPos, HitNormal )
  162.  
  163. local Energy = ACF_Kinetic( Bullet.Flight:Length() / ACF.VelScale, Bullet.ProjMass, Bullet.LimitVel )
  164. local HitRes = ACF_PenetrateGround( Bullet, Energy, HitPos, HitNormal )
  165. if HitRes.Penetrated then
  166. return "Penetrated"
  167. elseif HitRes.Ricochet then
  168. return "Ricochet"
  169. else
  170. return false
  171. end
  172.  
  173. end
  174.  
  175. function Round.endflight( Index, Bullet, HitPos )
  176.  
  177. ACF_RemoveBullet( Index )
  178.  
  179. end
  180.  
  181. -- Bullet stops here
  182. function Round.endeffect( Effect, Bullet )
  183.  
  184. local Spall = EffectData()
  185. Spall:SetEntity( Bullet.Crate )
  186. Spall:SetOrigin( Bullet.SimPos )
  187. Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
  188. Spall:SetScale( Bullet.SimFlight:Length() )
  189. Spall:SetMagnitude( Bullet.RoundMass )
  190. util.Effect( "ACF_AP_Impact", Spall )
  191.  
  192. end
  193.  
  194. -- Bullet penetrated something
  195. function Round.pierceeffect( Effect, Bullet )
  196.  
  197. local Spall = EffectData()
  198. Spall:SetEntity( Bullet.Crate )
  199. Spall:SetOrigin( Bullet.SimPos )
  200. Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
  201. Spall:SetScale( Bullet.SimFlight:Length() )
  202. Spall:SetMagnitude( Bullet.RoundMass )
  203. util.Effect( "ACF_AP_Penetration", Spall )
  204.  
  205. end
  206.  
  207. -- Bullet ricocheted off something
  208. function Round.ricocheteffect( Effect, Bullet )
  209.  
  210. local Spall = EffectData()
  211. Spall:SetEntity( Bullet.Crate )
  212. Spall:SetOrigin( Bullet.SimPos )
  213. Spall:SetNormal( (Bullet.SimFlight):GetNormalized() )
  214. Spall:SetScale( Bullet.SimFlight:Length() )
  215. Spall:SetMagnitude( Bullet.RoundMass )
  216. util.Effect( "ACF_AP_Ricochet", Spall )
  217.  
  218. end
  219.  
  220. function Round.guicreate( Panel, Table )
  221.  
  222. acfmenupanel:AmmoSelect( ACF.AmmoBlacklist.AP )
  223.  
  224. acfmenupanel:CPanelText("BonusDisplay", "")
  225.  
  226. acfmenupanel:CPanelText("Desc", "") --Description (Name, Desc)
  227. acfmenupanel:CPanelText("LengthDisplay", "") --Total round length (Name, Desc)
  228.  
  229. acfmenupanel:AmmoSlider("PropLength",0,0,1000,3, "Propellant Length", "") --Propellant Length Slider (Name, Value, Min, Max, Decimals, Title, Desc)
  230. acfmenupanel:AmmoSlider("ProjLength",0,0,1000,3, "Projectile Length", "") --Projectile Length Slider (Name, Value, Min, Max, Decimals, Title, Desc)
  231.  
  232. acfmenupanel:AmmoCheckbox("Tracer", "Tracer", "") --Tracer checkbox (Name, Title, Desc)
  233.  
  234. acfmenupanel:CPanelText("VelocityDisplay", "") --Proj muzzle velocity (Name, Desc)
  235. --acfmenupanel:CPanelText("RicoDisplay", "") --estimated rico chance
  236. acfmenupanel:CPanelText("PenetrationDisplay", "") --Proj muzzle penetration (Name, Desc)
  237.  
  238. Round.guiupdate( Panel, Table )
  239.  
  240. end
  241.  
  242. function Round.guiupdate( Panel, Table )
  243.  
  244. local PlayerData = {}
  245. PlayerData.Id = acfmenupanel.AmmoData.Data.id --AmmoSelect GUI
  246. PlayerData.Type = "AP" --Hardcoded, match ACFRoundTypes table index
  247. PlayerData.PropLength = acfmenupanel.AmmoData.PropLength --PropLength slider
  248. PlayerData.ProjLength = acfmenupanel.AmmoData.ProjLength --ProjLength slider
  249. local Tracer = 0
  250. if acfmenupanel.AmmoData.Tracer then Tracer = 1 end
  251. PlayerData.Data10 = Tracer --Tracer
  252.  
  253. local Data = Round.convert( Panel, PlayerData )
  254.  
  255. RunConsoleCommand( "acfmenu_data1", acfmenupanel.AmmoData.Data.id )
  256. RunConsoleCommand( "acfmenu_data2", PlayerData.Type )
  257. RunConsoleCommand( "acfmenu_data3", Data.PropLength ) --For Gun ammo, Data3 should always be Propellant
  258. RunConsoleCommand( "acfmenu_data4", Data.ProjLength ) --And Data4 total round mass
  259. RunConsoleCommand( "acfmenu_data10", Data.Tracer )
  260.  
  261. local vol = ACF.Weapons.Ammo[acfmenupanel.AmmoData["Id"]].volume
  262. local Cap, CapMul, RoFMul = ACF_CalcCrateStats( vol, Data.RoundVolume )
  263.  
  264. acfmenupanel:CPanelText("BonusDisplay", "Crate info: +"..(math.Round((CapMul-1)*100,1)).."% capacity, +"..(math.Round((RoFMul-1)*-100,1)).."% RoF\nContains "..Cap.." rounds")
  265.  
  266. 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)
  267. 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)
  268.  
  269. acfmenupanel:AmmoCheckbox("Tracer", "Tracer : "..(math.floor(Data.Tracer*5)/10).."cm\n", "" ) --Tracer checkbox (Name, Title, Desc)
  270.  
  271. acfmenupanel:CPanelText("Desc", ACF.RoundTypes[PlayerData.Type].desc) --Description (Name, Desc)
  272. acfmenupanel:CPanelText("LengthDisplay", "Round Length : "..(math.floor((Data.PropLength+Data.ProjLength+(math.floor(Data.Tracer*5)/10))*100)/100).."/"..(Data.MaxTotalLength).." cm") --Total round length (Name, Desc)
  273. acfmenupanel:CPanelText("VelocityDisplay", "Muzzle Velocity : "..math.floor(Data.MuzzleVel*ACF.VelScale).." m\\s") --Proj muzzle velocity (Name, Desc)
  274.  
  275. --local RicoAngs = ACF_RicoProbability( Data.Ricochet, Data.MuzzleVel*ACF.VelScale )
  276. --acfmenupanel:CPanelText("RicoDisplay", "Ricochet probability vs impact angle:\n".." 0% @ "..RicoAngs.Min.." degrees\n 50% @ "..RicoAngs.Mean.." degrees\n100% @ "..RicoAngs.Max.." degrees")
  277.  
  278. local R1V, R1P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 100 )
  279. local R2V, R2P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 200 )
  280. local R3V, R3P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 300 )
  281. local R4V, R4P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 400 )
  282. local R5V, R5P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 500 )
  283. local R6V, R6P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 600 )
  284. local R7V, R7P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 700 )
  285. local R8V, R8P = ACF_PenRanging( Data.MuzzleVel, Data.DragCoef, Data.ProjMass, Data.PenAera, Data.LimitVel, 800 )
  286.  
  287. acfmenupanel:CPanelText("PenetrationDisplay", "Max pen: "..math.floor(Data.MaxPen).." mm\n100m pen: "..math.Round(R1P,0).."mm @ "..math.Round(R1V,0).." m\\s\n200m pen: "..math.Round(R2P,0).."mm @ "..math.Round(R2V,0).." m\\s\n300m pen: "..math.Round(R3P,0).."mm @ "..math.Round(R3V,0).." m\\s\n400m pen: "..math.Round(R4P,0).."mm @ "..math.Round(R4V,0).." m\\s\n500m pen: "..math.Round(R5P,0).."mm @ "..math.Round(R5V,0).." m\\s\n600m pen: "..math.Round(R6P,0).."mm @ "..math.Round(R6V,0).." m\\s\n700m pen: "..math.Round(R7P,0).."mm @ "..math.Round(R7V,0).." m\\s\n800m pen: "..math.Round(R8P,0).."mm @ "..math.Round(R8V,0).." ..m\\s\n\nThe range data is an approximation and may not be entirely accurate.") --Proj muzzle penetration (Name, Desc)
  288.  
  289.  
  290. end
  291.  
  292. list.Set( "ACFRoundTypes", "AP", Round ) --Set the round properties
  293. list.Set( "ACFIdRounds", Round.netid, "AP" ) --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