crogaa

WPD Spinner Code v3.1.3

Jul 30th, 2023
536
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.06 KB | None | 0 0
  1. @name WPD Spinner Code V3.1.3
  2. @inputs Mouse1 Mouse2 DualInput R
  3. @inputs [Weapon,Chassis,Shell,Support1,Support2,SupportAxle]:entity
  4. @outputs WeaponTorque:angle ChassisTorque:angle Sound PitchRelative DamageMultiplier WeaponRPM
  5. @outputs WeaponInertia:vector WeaponRadius TipSpeed StallCounter
  6. @outputs WeaponMaxHealth WeaponDamage ChassisMaxHealth ChassisDamage Support1MaxHealth Support1Damage
  7. @outputs Support2MaxHealth Support2Damage SupportAxleMaxHealth SupportAxleDamage Smoke Alive
  8. @persist WeaponRPM_Old WeaponRPM_Delta WeaponRPM_Check StallPowerMul SB_Mul RPMCount
  9. @persist SpinPower Pitch Yaw Roll AirDrag StatusMessages ManualInertia ChassisSpinPower
  10. @persist Power SpinPowerMul TorqueMul ChassisRPM WeaponRPMVec:angle WeaponRPMAng
  11. @persist Shell_Exists Support1_Exists Support2_Exists SupportAxle_Exists SupportsConstrained
  12. @persist Stall StallRate StallPercentage DeathCheck TimerDelay SpikeballType MaxRPM InertiaState
  13. @persist StallRateVar StallCountDownRate StallCountThreshold StallRPMCheck
  14. @persist MaxInertia InertiaUsed [NaturalInertia,ArtificialInertia]:vector
  15. @persist InertiaMul InertiaTorqueMul [PropTable,InertiaTable]:table TableSize
  16. @persist PYR_Correct [PYR_Weapon, PYR_Chassis]:angle Duped [SpinAxis]:vector
  17. @persist HalfSpeedMul WPDInertia InertiaDamageMultiplier WPD_Mul
  18. @persist ChassisHits Support1Hits Support2Hits SupportAxleHits
  19. @persist LastDamage:vector Spikeball_Drag Spikeball_Active CounterTorqueMul
  20. @persist StandardRPM RPMCheck RPM_High GrindMul PhysicalProperty:string
  21. @persist BotActive Physgun SawMode PR_Mul HeavyDrag DragLoop_Low DragLoop_High DragLoop_Count
  22. @persist ShellAxis:vector PYR_Shell:angle WeaponWidth ShellRadius
  23. @persist WPDShellInertia MaxShellInertia DamageThreshold ShellMul Start
  24. @persist [DefaultInertia,StallInertia]:vector SmokeCheck TopSpeed
  25. @persist [Shell_DefaultInertia,Shell_StallInertia,Shell_WeaponInertia]:vector
  26. @persist WeaponHits AxleBroken WeaponBroken ShellBroken FirstInput
  27. @persist Stats_RPM Stats_MOI Stats_Diameter Stats_KE Stats_Mass NormalDrag
  28. @persist ServerRPMLimit
  29.  
  30. WeaponInput=(Mouse1-Mouse2+DualInput)
  31. if(dupefinished()|WeaponInput!=0|R==1){Start=1}elseif(duped()){Start=0}
  32. if(first()|dupefinished()|R==1|inputClk()&changed(WeaponInput)==0){
  33. runOnTick(1)
  34.  
  35. #DISCLAIMER FROM BUSINESS CAT:
  36. #Counter Rotation Code works so that the spinner can spin the chassis when nearly stalled
  37. #Counter-torque value is determined by the inertia of your spinner - more inertia means more counter-torque.
  38. #Stall edition makes the spinner possibly break itself IF:
  39. #the spin key is held too long when the blade/chassis cannot spin freely.
  40. #Your weapon motor would be very unhappy with you if you did that.
  41.  
  42. #YOU WILL HAVE TO WIRE A BUTTON TO REVIVE YOUR SPINNER ONCE IT HAS STALLED.
  43. #While you can wire it to R on your pod controller,
  44. #having the ability to 'fix' the stall mid-fight is unfair and unrealistic.
  45. #Put the button on the robot to prevent this unfair advantage.
  46.  
  47. #==============================================================================================================
  48. #USER SETTINGS - ONLY CHANGE THE VALUES IN THIS SECTION
  49. #==============================================================================================================
  50.  
  51. #IT IS RECOMMENDED THAT YOU RESPAWN THE BOT AFTER SWITCHING TO THIS CODE FROM THE OLD VERSION
  52.  
  53. InertiaUsed = 0 #Custom set inertia, set to 1 to enable it, 0 to disable
  54. ManualInertia = 500 #INERTIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (Up to 1000 permitted)
  55.  
  56. TipSpeed = 250 #If your spinner is unstable at high speeds, lower this (Max = 250mph)
  57.  
  58. Pitch = 0 #Use these to select which axis your weapon spins on
  59. Yaw = 1 #Set the one you want to '1' and the others to '0'
  60. Roll = 0 #If your weapon doesn't spin, try selecting a different axis
  61.  
  62. Power = 500000 #Add/Remove a negative if blade is spinning the wrong way
  63. AirDrag = 0.15 #Change this to change how quickly the spinner slows down
  64. StatusMessages = 1 #Set this to 0 to turn off stall % readouts in chat. 1 is on.
  65. StallRateVar = 16 #DO NOT CHANGE unless switching weight classes
  66.  
  67. SawMode = 0 #Set to '1' if the spinner is being used as a saw
  68.  
  69. #==============================================================================================================
  70. # !!!DO NOT TOUCH ANYTHING BELOW!!!
  71. #==============================================================================================================
  72.  
  73. #Saw Mode - Initial Setup
  74.  
  75. if(SawMode==1){ #Auto-modifies settings to make saws more stable
  76. AirDrag = AirDrag+5
  77. InertiaUsed = 1
  78. StallRateVar = 0
  79. ManualInertia = 20}
  80.  
  81. #=====================
  82. #Air Drag - Initial Setup
  83.  
  84. Weapon:setCustomAirDrag(1,0,AirDrag)
  85.  
  86. HeavyDrag = 5
  87. DragLoop_Low = 0
  88. DragLoop_High = 0
  89. DragLoop_Count = 0
  90.  
  91. #=====================
  92. #Physical Properties - Initial Setup
  93.  
  94. PhysicalProperty = "metalgrate"
  95. Weapon:propPhysicalMaterial(PhysicalProperty)
  96.  
  97. #=====================
  98. #Supports - Initial Setup
  99.  
  100. if(Shell:isValid()){Shell_Exists=1}else{Shell_Exists=0} #Checks whether shell exists at startup
  101. if(Support1:isValid()){Support1_Exists=1}else{Support1_Exists=0} #Checks whether each support exists at startup
  102. if(Support2:isValid()){Support2_Exists=1}else{Support2_Exists=0}
  103. if(SupportAxle:isValid()){SupportAxle_Exists=1}else{SupportAxle_Exists=0} #Checks whether one support is an axle
  104.  
  105. if((Support1_Exists+Support2_Exists+SupportAxle_Exists)==0){SupportsConstrained=0}
  106. else{SupportsConstrained=1}
  107.  
  108. AxleBroken = 0
  109. WeaponBroken = 0
  110. ShellBroken = 0
  111. BotActive = 0
  112. FirstInput = 0
  113.  
  114. #=====================
  115. #Pitch/Yaw/Roll - Initial Setup
  116.  
  117. if(Power>500000){Power=500000} #Prevents cheating
  118. if(Power<-500000){Power=-500000} #Prevents cheating
  119.  
  120. if(first()){
  121. if((Pitch+Yaw+Roll)!=1){print("----------WARNING----------\nFor the spinner to work, only one of the Pitch/Yaw/Roll settings should be set to '1'.",
  122. "The others must be set to '0'. ","\n\nThe current settings are:","\nPitch","=",Pitch, "\nYaw","=",Yaw, "\nRoll","=",Roll)
  123. ,PYR_Correct=0}
  124. else{PYR_Correct=1}
  125. }
  126. if(Shell_Exists==0){ #Spinner is not a shell
  127. SpinAxis=vec(Roll,Pitch,Yaw) #Gets weapon rotation axis as local vector
  128. SpinAxis=(Weapon:toWorldAxis(SpinAxis)) #Converts to global axis
  129. SpinAxis=(Chassis:toLocalAxis(SpinAxis)):normalized() #Converts to local chassis axis
  130. SpinAxis=round(SpinAxis,2) #Rounds to 2dp to prevent 'leakage' into other axes when not required
  131. }
  132. else{ #Spinner is a shell
  133. SpinAxis=vec(Roll,Pitch,Yaw) #Gets weapon rotation axis as local vector
  134. SpinAxis=(Shell:toWorldAxis(SpinAxis)) #Converts to global axis
  135. SpinAxis=(Chassis:toLocalAxis(SpinAxis)):normalized() #Converts to local chassis axis
  136. SpinAxis=round(SpinAxis,2) #Rounds to 2dp to prevent 'leakage' into other axes when not required
  137.  
  138. ShellAxis=vec(Roll,Pitch,Yaw) #Gets weapon rotation axis as local vector
  139. ShellAxis=(Shell:toWorldAxis(ShellAxis)) #Converts to global axis
  140. ShellAxis=(Weapon:toLocalAxis(ShellAxis)):normalized() #Converts to local chassis axis
  141. ShellAxis=round(ShellAxis,2) #Rounds to 2dp to prevent 'leakage' into other axes when not required
  142. }
  143. PYR_Weapon=ang(Pitch,Yaw,Roll)
  144. PYR_Shell=ang(ShellAxis:y(),ShellAxis:z(),ShellAxis:x())
  145. PYR_Chassis=ang(SpinAxis:y(),SpinAxis:z(),SpinAxis:x())
  146.  
  147. #=====================
  148. #Effective Weapon Radius - Initial Setup
  149.  
  150. BoxSize=Weapon:boxSize()
  151. BoxCentre=Weapon:boxCenter()
  152. MassCentre=Weapon:massCenterL()
  153.  
  154. ShellRadius=max(Shell:boxSize():x(),Shell:boxSize():y(),Shell:boxSize():z())/2*0.01905
  155.  
  156. X_Diff=abs(BoxCentre:x()-MassCentre:x())
  157. Y_Diff=abs(BoxCentre:y()-MassCentre:y())
  158. Z_Diff=abs(BoxCentre:z()-MassCentre:z())
  159.  
  160. if(Pitch==1){
  161. if(BoxSize:x()>=BoxSize:z()){
  162. WeaponRadius=sqrt((BoxSize:x()/2+X_Diff)^2+(BoxSize:z()/4)^2) #Estimates the effective radius of the weapon
  163. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  164. WeaponWidth=BoxSize:z()*0.01905} # Finds width of weapon for calculating MOI
  165. else{
  166. WeaponRadius=sqrt((BoxSize:z()/2+Z_Diff)^2+(BoxSize:x()/4)^2) #Estimates the effective radius of the weapon
  167. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  168. WeaponWidth=BoxSize:x()*0.01905} # Finds width of weapon for calculating MOI
  169. }
  170. if(Yaw==1){
  171. if(BoxSize:x()>=BoxSize:y()){
  172. WeaponRadius=sqrt((BoxSize:x()/2+X_Diff)^2+(BoxSize:y()/4)^2) #Estimates the effective radius of the weapon
  173. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  174. WeaponWidth=BoxSize:y()*0.01905} # Finds width of weapon for calculating MOI
  175. else{
  176. WeaponRadius=sqrt((BoxSize:y()/2+Y_Diff)^2+(BoxSize:x()/4)^2) #Estimates the effective radius of the weapon
  177. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  178. WeaponWidth=BoxSize:x()*0.01905} # Finds width of weapon for calculating MOI
  179. }
  180. if(Roll==1){
  181. if(BoxSize:z()>=BoxSize:y()){
  182. WeaponRadius=sqrt((BoxSize:z()/2+Z_Diff)^2+(BoxSize:y()/4)^2) #Estimates the effective radius of the weapon
  183. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  184. WeaponWidth=BoxSize:y()*0.01905} # Finds width of weapon for calculating MOI
  185. else{
  186. WeaponRadius=sqrt((BoxSize:y()/2+Y_Diff)^2+(BoxSize:z()/4)^2) #Estimates the effective radius of the weapon
  187. WeaponRadius=WeaponRadius*0.01905 # Converts effective radius from source units to metres
  188. WeaponWidth=BoxSize:z()*0.01905} # Finds width of weapon for calculating MOI
  189. }
  190.  
  191. if(Shell_Exists==1){ #For shell, just finds largest 2 directions for length/width since orientation is more predictable
  192. if(BoxSize:x()>BoxSize:y()&BoxSize:x()>BoxSize:z()){
  193. if(BoxSize:y()>BoxSize:z()){
  194. WeaponWidth=BoxSize:y()*0.01905}
  195. else{WeaponWidth=BoxSize:z()*0.01905}
  196. }
  197. elseif(BoxSize:y()>BoxSize:x()&BoxSize:y()>BoxSize:z()){
  198. if(BoxSize:x()>BoxSize:z()){
  199. WeaponWidth=BoxSize:x()*0.01905}
  200. else{WeaponWidth=BoxSize:z()*0.01905}
  201. }
  202. else{
  203. if(BoxSize:y()>BoxSize:z()){
  204. WeaponWidth=BoxSize:y()*0.01905}
  205. else{WeaponWidth=BoxSize:z()*0.01905}
  206. }
  207. WeaponRadius=max(BoxSize:x(),BoxSize:y(),BoxSize:z())*0.01905/2
  208. }
  209. if(WeaponRadius>3){WeaponRadius=3}
  210. if(WeaponWidth>3){WeaponWidth=3}
  211.  
  212. #=====================
  213. #RPM - Initial Setup
  214.  
  215. if(TipSpeed>250){TipSpeed=250}
  216.  
  217. StandardRPM = 660 #Empirical standard value found through testing
  218. MaxRPM = round((TipSpeed/250)*StandardRPM*(3/WeaponRadius),0)
  219.  
  220. ServerRPMLimit=angSpeedLimit()/6 #6 divisor converts from degrees/s to RPM
  221.  
  222. if(MaxRPM<1250){MaxRPM=1250*(TipSpeed/250)}
  223. elseif(MaxRPM>3300){MaxRPM=3300}
  224. elseif(MaxRPM>ServerRPMLimit){MaxRPM=ServerRPMLimit}
  225.  
  226. if(Shell_Exists==0){
  227. if(Pitch==1){
  228. WeaponRPM = abs((Weapon:angVel():pitch()/6))
  229. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):pitch())}
  230. elseif(Yaw==1){
  231. WeaponRPM = abs((Weapon:angVel():yaw()/6))
  232. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):roll())}
  233. else{
  234. WeaponRPM = abs((Weapon:angVel():roll()/6))
  235. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):yaw())}
  236. }
  237. else{
  238. if(Pitch==1){
  239. WeaponRPM = abs((Shell:angVel():pitch()/6))
  240. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):pitch())}
  241. elseif(Yaw==1){
  242. WeaponRPM = abs((Shell:angVel():yaw()/6))
  243. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):roll())}
  244. else{
  245. WeaponRPM = abs((Shell:angVel():roll()/6))
  246. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):yaw())}
  247. }
  248.  
  249. if(MaxRPM>1800){MaxRPM=1800} #Mitigates wobbling
  250. LowRPMCheck = MaxRPM * 0.1
  251. CounterTorqueMul = 1
  252. PR_Mul = 0.85*MaxRPM #Multiplier for PitchRelative Calc (Saves a couple ops)
  253.  
  254. #=====================
  255. #Inertia - Initial Setup
  256.  
  257. if(first()&InertiaUsed==0){print("----------WARNING----------\nYou are set to natural inertia. After first updating the E2, you will need to: \n1) Reset the weapon's inertia using the Inertia tool \n2) Press the weapon reset button on the robot")}
  258.  
  259. if(ManualInertia>1000){ManualInertia=1000} #Prevents setting manual inertia above 1000
  260.  
  261. InertiaState=0
  262.  
  263. if(InertiaUsed==1){InertiaMul=1,InertiaTorqueMul=2,SpinPowerMul=1}
  264. else{InertiaMul=1.75,InertiaTorqueMul=2,SpinPowerMul=1}
  265.  
  266. if(WeaponRPM>=LowRPMCheck){ #Prevents bugs when E2 or R reset while spinning
  267. print("----------WARNING----------\nWeapon must come to a stop before pressing reset or changing the E2 chip settings")
  268. if(InertiaUsed==1){
  269. DefaultInertia = vec(ManualInertia) #Low speed inertia (default - prevents bugs)
  270. WeaponInertia = DefaultInertia*InertiaMul #High speed inertia (Gets default inertia & multiplier)
  271.  
  272. Shell_DefaultInertia = vec(ManualInertia)
  273. Shell_WeaponInertia = Shell_DefaultInertia*InertiaMul}
  274. else{
  275. DefaultInertia = Weapon:inertia()/InertiaMul
  276. WeaponInertia = DefaultInertia*InertiaMul
  277.  
  278. Shell_DefaultInertia = Shell:inertia()/InertiaMul
  279. Shell_WeaponInertia = Shell_DefaultInertia*InertiaMul}
  280. }
  281. else{
  282. if(InertiaUsed==1){
  283. DefaultInertia = vec(ManualInertia)
  284. WeaponInertia = DefaultInertia*InertiaMul
  285. Weapon:propInertia(DefaultInertia)
  286.  
  287. Shell_DefaultInertia = vec(ManualInertia)
  288. Shell_WeaponInertia = Shell_DefaultInertia*InertiaMul
  289. Shell:propInertia(DefaultInertia)}
  290. else{
  291. DefaultInertia = Weapon:inertia()
  292. WeaponInertia = DefaultInertia*InertiaMul
  293.  
  294. Shell_DefaultInertia = Shell:inertia()
  295. Shell_WeaponInertia = Shell_DefaultInertia*InertiaMul}
  296. }
  297. if(Shell_Exists==0){
  298. Shell_DefaultInertia = vec(0,0,0)
  299. Shell_WeaponInertia = vec(0,0,0)
  300.  
  301. if(Pitch==1){WPDInertia=WeaponInertia:y()}
  302. elseif(Yaw==1){WPDInertia=WeaponInertia:z()}
  303. else{WPDInertia=WeaponInertia:x()}
  304.  
  305. MaxInertia=WPDInertia
  306. }
  307. else{
  308. if(Pitch==1){WPDInertia=Shell_WeaponInertia:y()}
  309. elseif(Yaw==1){WPDInertia=Shell_WeaponInertia:z()}
  310. else{WPDInertia=Shell_WeaponInertia:x()}
  311.  
  312. MaxInertia=WPDInertia+max((WeaponInertia*ShellAxis):x(),(WeaponInertia*ShellAxis):y(),(WeaponInertia*ShellAxis):z())
  313. }
  314.  
  315. Physgun=0
  316.  
  317. #=====================
  318. #Stall - Initial Setup
  319.  
  320. if(Shell_Exists==1){ShellMul = 1}
  321. else{ShellMul=1}
  322.  
  323. StallRate = (1)/sqrt(1500)*StallRateVar/ShellMul
  324. StallCountDownRate = 0.5
  325. StallCountThreshold = 100
  326. StallRPMCheck = MaxRPM*0.1 #RPM below which weapon starts to stall
  327. RPMCheck = 15 #RPM below which counter-torque applied
  328.  
  329. TorqueMul = 1200*1500*(WeaponRadius/3)*Power/abs(Power) #Changes sign if necessary
  330. StallPowerMul = 1
  331.  
  332. if(first()|dupefinished())
  333. {StallCounter=0,Stall=0,Alive=1,Smoke=0,SmokeCheck=0,DeathCheck=0} #Resets the stall code
  334.  
  335. #=====================
  336. #Spikeballing Fix - Initial Setup
  337.  
  338. LastDamage = vec(0,0,0)
  339. Spikeball_Drag = 10-10*(WeaponRadius/3) #Gives 1 drag for 6m diameter weapons, and 10 drag at 0m.
  340. RPM_High = 0
  341. Spikeball_Active = 0
  342. Spikeball_Mul = 1
  343. SB_Mul = 0
  344.  
  345. #=====================
  346. #WPD - Initial Setup
  347.  
  348. HealthBoost = 35000 #Health that WPD props are boosted to (allows advanced destruction effects)
  349. DamageThreshold = 200 #Minimum damage that a hit needs to have to break a prop off
  350. InertiaDamageMultiplier = 2.4*(MaxInertia/1000)*(MaxRPM/1800)^2*(250/TipSpeed)^2 #Scales damage based off inertia and RPM, (takes tip speed as 250)
  351. GrindMul = 1 #Reduces damage for multiple hits in quick succession
  352.  
  353. if(InertiaDamageMultiplier > 1.5){InertiaDamageMultiplier=1.5} #Max Multiplier = 1.5
  354.  
  355. Weapon:registerDamageMonitor()
  356. Weapon:setDamagePropHealth(HealthBoost)
  357. Weapon:setDamageParticleEffect("wpd_sparkx_big")
  358. Weapon:setDamageParticleEffectThreshold(100,"wpd_sparkx_huge")
  359. Weapon:bypassWorldDamageFX(0)
  360. WeaponMaxHealth=27000*0.6 #0.6 multiplier as props normally fall off at 40% health
  361. WeaponHits=0
  362.  
  363. if(SawMode==1){
  364. Weapon:registerDamageMonitor()
  365. Weapon:setDamagePropHealth(HealthBoost*2)
  366. Weapon:setDamageParticleEffect("wpd_sparkx_huge")
  367. Weapon:setDamageParticleEffectThreshold(100,"wpd_sparkx_huge")
  368. Weapon:bypassWorldDamageFX(0)
  369. WeaponMaxHealth=HealthBoost*2
  370. WeaponHits=0
  371. InertiaDamageMultiplier=1.5}
  372.  
  373. Chassis:registerDamageMonitor()
  374. Chassis:setDamagePropHealth(HealthBoost)
  375. ChassisMaxHealth=Chassis:mass()*30*0.6
  376. ChassisHits=0
  377.  
  378. Support1:registerDamageMonitor()
  379. Support1:setDamagePropHealth(HealthBoost)
  380. Support1MaxHealth=Support1:mass()*30*0.6
  381. Support1Hits=0
  382.  
  383. Support2:registerDamageMonitor()
  384. Support2:setDamagePropHealth(HealthBoost)
  385. Support2MaxHealth=Support2:mass()*30*0.6
  386. Support2Hits=0
  387.  
  388. SupportAxle:registerDamageMonitor()
  389. SupportAxle:setDamagePropHealth(HealthBoost)
  390. SupportAxleMaxHealth=SupportAxle:mass()*30*0.6
  391. SupportAxleHits=0
  392.  
  393. if(first()|dupefinished()){WPD_Mul=1} #Allows spin power to be reduced when damage taken: Starts at 1 (=100% power)
  394.  
  395. #=====================
  396. #Weapon Stats - Initial Setup
  397.  
  398. #Calculates the stats that weapon would have in real life
  399. Stats_Mass = round(Weapon:mass()+Shell:mass(),0)/10 #Divide by 10, simple
  400. Stats_Diameter = round(WeaponRadius,2)*1000*2/5 #5:1 GMod to IRL scale; 1:1000 converts m to mm; *2 finds diameter from radius
  401. Stats_RPM = round(0.44704*(TipSpeed*60)/(pi()*Stats_Diameter/1000),0) #*0.44704 from unit conversion
  402. Stats_MOI = round((0.5*Shell:mass()/10*(ShellRadius/5)^2)+(Weapon:mass()/10/12)*((WeaponWidth*0.7/5)^2+((Stats_Diameter/1000)^2)),2) #0.7 mult rovides good all-around estimate for discs+bars
  403. Stats_KE = round((0.1047198^2)*(0.5*Stats_MOI*Stats_RPM^2)/1000,1) #0.1047198^2 multiplier converts units to kJ
  404.  
  405. #==============================================================================================================================
  406. } #End of initial setups
  407. #==============================================================================================================================
  408.  
  409. #Inputs Section
  410.  
  411. if(Start==1){ #Encapsules all code below - prevents bug
  412.  
  413. ChassisSpinPower = TorqueMul*(1-PitchRelative)
  414.  
  415. if(WeaponInput!=0){BotActive=1}
  416. else{BotActive=0}
  417.  
  418. if(BotActive==1){FirstInput=1}
  419.  
  420. #=====================
  421. #Support Break Code
  422. if(FirstInput==1){ #Doesn't run until after first input
  423. if(SupportAxle_Exists==1){
  424. if(Support1_Exists+Support2_Exists==2){ #If bot has 2 frame supports:
  425. if((Support1:hasConstraints("weld")==0&Support1:hasConstraints("axis")==0)&
  426. (Support2:hasConstraints("weld")==0&Support2:hasConstraints("axis")==0)) #If both supports break, weapon + axle get detached
  427. {
  428. AxleBroken=1
  429. WeaponBroken=1
  430. ShellBroken=1
  431. SupportsConstrained=0
  432. }
  433. elseif((Support1:hasConstraints("weld")==0&Support1:hasConstraints("axis")==0)|
  434. (Support2:hasConstraints("weld")==0&Support2:hasConstraints("axis")==0)) #If one support breaks, weapon stays attached but dies
  435. {SupportsConstrained=0}
  436. if(SupportAxle:hasConstraints("weld")==0&SupportAxle:hasConstraints("axis")==0) #If axle breaks, weapon gets detached
  437. {
  438. WeaponBroken=1
  439. ShellBroken=1
  440. SupportsConstrained=0
  441. }
  442. }
  443. elseif(Support1_Exists+Support2_Exists==1){ #If only one frame support:
  444. if( (Support1_Exists==1&Support1:hasConstraints("weld")==0&Support1:hasConstraints("axis")==0) | # If the frame support breaks,
  445. (Support2_Exists==1&Support2:hasConstraints("weld")==0&Support2:hasConstraints("axis")==0) ) # both Weapon and Axle get broken off
  446. {
  447. AxleBroken=1
  448. WeaponBroken=1
  449. ShellBroken=1
  450. SupportsConstrained=0
  451. }
  452. if(SupportAxle:hasConstraints("weld")==0&SupportAxle:hasConstraints("axis")==0) #If axle breaks, weapon gets detached
  453. {
  454. WeaponBroken=1
  455. ShellBroken=1
  456. SupportsConstrained=0
  457. }
  458. }
  459. if(AxleBroken==1){
  460. SupportAxle:constraintBreak("axis")
  461. SupportAxle:constraintBreak("ballsocket")
  462. SupportAxle:constraintBreak("weld")
  463. SupportAxle:constraintBreak("rope")
  464. SupportAxle:constraintBreak("AdvBallsocket")
  465. SupportAxle:constraintBreak("advballsocket")
  466. SupportAxle:setDamagePropHealth(SupportAxleMaxHealth)}
  467. }
  468. elseif( #If no axle, function as normal
  469. (Support1_Exists==1&Support1:hasConstraints("weld")==0&Support1:hasConstraints("axis")==0) |
  470. (Support2_Exists==1&Support2:hasConstraints("weld")==0&Support2:hasConstraints("axis")==0) )
  471. {
  472. WeaponBroken=1
  473. ShellBroken=1
  474. SupportsConstrained=0
  475. }
  476. if(WeaponBroken==1){
  477. Weapon:constraintBreak("axis")
  478. Weapon:constraintBreak("ballsocket")
  479. Weapon:constraintBreak("weld")
  480. Weapon:constraintBreak("rope")
  481. Weapon:constraintBreak("AdvBallsocket")
  482. Weapon:constraintBreak("advballsocket")
  483. Weapon:setDamagePropHealth(WeaponMaxHealth)}
  484. }
  485. if(SupportsConstrained == 0){WeaponSpinMul=0}
  486. else{WeaponSpinMul=1} #Death settings based on one/two support deaths, or chassis/weapon death
  487.  
  488. #=====================
  489. #Shell Break Code
  490.  
  491. if(Shell_Exists==1){
  492. if(ShellBroken==1){ #If support broken, break shell
  493. Shell:constraintBreak("axis")
  494. Shell:constraintBreak("ballsocket")
  495. Shell:constraintBreak("weld")
  496. Shell:constraintBreak("rope")
  497. Shell:constraintBreak("AdvBallsocket")
  498. Shell:constraintBreak("advballsocket")
  499. SupportsConstrained=0}
  500.  
  501. if(Shell:hasConstraints("axis")==0){ #If shell broken, break weapon
  502. Weapon:constraintBreak("axis")
  503. Weapon:constraintBreak("ballsocket")
  504. Weapon:constraintBreak("weld")
  505. Weapon:constraintBreak("rope")
  506. Weapon:constraintBreak("AdvBallsocket")
  507. Weapon:constraintBreak("advballsocket")
  508. Weapon:setDamagePropHealth(WeaponMaxHealth)
  509. SupportsConstrained=0
  510. WeaponBroken=1}
  511. }
  512. #=====================
  513. #RPM Code
  514.  
  515. if(Shell_Exists==0){
  516. if(Pitch==1){
  517. WeaponVel = Weapon:angVel():pitch()/6
  518. WeaponRPM = abs(WeaponVel)
  519. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):pitch())
  520. }
  521. elseif(Yaw==1){
  522. WeaponVel = Weapon:angVel():yaw()/6
  523. WeaponRPM = abs(WeaponVel)
  524. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):roll())
  525. }
  526. else{
  527. WeaponVel = Weapon:angVel():roll()/6
  528. WeaponRPM = abs(WeaponVel)
  529. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):yaw())
  530. }
  531. }
  532. else{
  533. if(Pitch==1){
  534. WeaponVel = Shell:angVel():pitch()/6
  535. WeaponRPM = abs(WeaponVel)
  536. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):pitch())
  537. }
  538. elseif(Yaw==1){
  539. WeaponVel = Shell:angVel():yaw()/6
  540. WeaponRPM = abs(WeaponVel)
  541. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):roll())
  542. }
  543. else{
  544. WeaponVel = Shell:angVel():roll()/6
  545. WeaponRPM = abs(WeaponVel)
  546. ChassisRPM = abs((Chassis:angVel()*PYR_Chassis/6):yaw())
  547. }
  548. }
  549. if(WeaponRPM>20){Sound=1}
  550. else{Sound=0}
  551. PitchRelative=WeaponRPM/PR_Mul
  552. if(PitchRelative>1){PitchRelative=1}
  553.  
  554. CounterTorqueMul=1-PitchRelative
  555. if(CounterTorqueMul<0.05){CounterTorqueMul=0.05}
  556.  
  557. if(PitchRelative==1){TopSpeed=1}
  558. else{TopSpeed=0}
  559.  
  560. if(changed(TopSpeed)){
  561. if(TopSpeed==1){Weapon:setDamageParticleEffect("wpd_sparkx_huge")}
  562. else{Weapon:setDamageParticleEffect("wpd_sparkx_big")}
  563. }
  564.  
  565. #=====================
  566. #Inertia Code
  567.  
  568. WeaponMass=Weapon:mass()
  569.  
  570. if(WeaponMass<2000){ #Prevents physgun bugs
  571. if((WeaponRPM<StallRPMCheck)&WeaponInput==0){InertiaState=1} #RPM low and weapon inactive: Default Inertia
  572. else{InertiaState=2} #Otherwise: High Inertia
  573. }
  574.  
  575. if(changed(InertiaState)){ #Only applies inertia when InertiaState changes - saves performance
  576. if(InertiaState==1){Weapon:propInertia(DefaultInertia)}
  577. else{Weapon:propInertia(WeaponInertia)}
  578. }
  579.  
  580. if(WeaponMass>2000){Physgun=1}
  581.  
  582. if(changed(WeaponMass)){
  583. if(Physgun==0){
  584. if(first()==0&dupefinished()==0&R!=1){
  585. if(WeaponMass!=0){
  586. print("----------WARNING----------\nAfter changing the weapon's mass, you will need to:\n1) Reset the weapon's inertia using the Inertia tool\n2) Press the weapon reset button on the robot")}
  587. }
  588. }
  589. elseif(WeaponMass<2000){Physgun=0}
  590. }
  591.  
  592. #=====================
  593. #Stall Code
  594.  
  595. if(Stall==1){
  596. if(clk("DeathTime")){print("Weapon Stall:\t100\t%"),DeathCheck=1} #Tells you that you died
  597. if(DeathCheck!=1){timer("DeathTime",100),SmokeCheck=1}
  598. }
  599. else{
  600. if(WeaponInput!=0 & WeaponRPM<(StallRPMCheck) & ChassisRPM<(StallRPMCheck))
  601. {StallCounter=StallCounter+StallRate} #Counts up
  602. else{StallCounter=StallCounter-(StallRate*StallCountDownRate)} #Counts down
  603.  
  604. if(StallCounter>0){
  605. timer("Clock",200)
  606. if(StallCounter>StallCountThreshold){Stall=1,Alive=0} #if threshold is hit, you die
  607. }
  608. #if you are reading this then I appreciate you
  609. else{StallCounter=0} #no negative count allowed
  610.  
  611. if(clk("Clock") & StatusMessages==1){
  612. StallPercentage = round((StallCounter/StallCountThreshold)*100)
  613. print("Weapon Stall:",StallPercentage,"%")} #displays % in chat
  614. }
  615. if(changed(R)){
  616. if(R==1){StallCounter=0,Stall=0,Alive=1,Smoke=0,SmokeCheck=0,DeathCheck=0,print("Weapon Status:\tActive") #Resets the stall code
  617. if(StatusMessages==1){print("-----Real Life Stats-----","\nMass (kg):\t\t",Stats_Mass,"\nMax RPM:\t\t",Stats_RPM,"\nDiameter (mm):\t",Stats_Diameter,"\nTip Speed (mph):\t",TipSpeed,"\nMOI (kg.m^2):\t",Stats_MOI,"\nKinetic Energy (kJ): ",Stats_KE)}
  618. }
  619. }
  620. #the Smoke output lets you wire a numpad output to it, and then you can place a particle controller
  621. #with the same key as the numpad output - and when your spinner stalls, it will let out a puff of smoke
  622. #cool innit?
  623.  
  624. #=====================
  625. #AirDrag Feedback Loop Code
  626.  
  627. #If air drag is too high, sound pitch oscillates constantly at high speed
  628. #If air drag is too low, wobble occurs
  629.  
  630. if(WeaponRPM>MaxRPM+100){DragLoop_Low=1} #Checks if RPM is going too high, means Drag is too low (causes wobble)
  631. else{DragLoop_Low=0}
  632.  
  633. if(DragLoop_High==0){
  634. if(PitchRelative==1){DragLoop_High=1}} #This section checks for sound glitch (caused by air drag being too high)
  635. if(DragLoop_High==1){
  636. if(PitchRelative<1){DragLoop_High=2}}
  637. if(DragLoop_High==2){
  638. if(PitchRelative<0.80){DragLoop_High==0} #If PitchRelative drops back down without oscillating, air drag probably ok
  639. if(PitchRelative==1){DragLoop_High=3}} #If PitchRelative increases again quickly, sound glitch is probably occurring
  640.  
  641. if(changed(DragLoop_Low)){
  642. if(DragLoop_Low==1){HeavyDrag=HeavyDrag+0.5}} #Increases Air Drag until wobble stops
  643.  
  644. if(changed(DragLoop_High)){
  645. if(DragLoop_High==3){HeavyDrag=HeavyDrag-0.5,DragLoop_High=0}} #Decreases Air Drag until sound gltich stops
  646.  
  647. DragLoop_Low=0
  648. if(HeavyDrag<3){HeavyDrag=3}
  649. if(HeavyDrag>10){HeavyDrag=10}
  650.  
  651. #=====================
  652. #Spikeballing/Grinding Fix Code
  653.  
  654. LastDamage = Weapon:getEntityDamagePosition() #Checks for collision (each hit will always be slightly diff position)
  655.  
  656. if(changed(LastDamage)){
  657. if(((Weapon:getDamageInflictor()):type())!="prop_physics"){ #Applies drag for 100ms if spinner hit the world
  658. timer("Drag_Time",100)
  659. stoptimer("Stall_Time")
  660. timer("Stall_Time",500)
  661. StallPowerMul = WeaponRadius/3 #Reduces torque if obstructed below 50% RPM (1.25 factor as torque is 2x higher but gravity only 1.6x higher)
  662. SB_Mul = SB_Mul + 0.2
  663. SpikeballType = 1
  664. if(SB_Mul==0.2){SB_Mul=0.01}} #Reduces SB_Mul for the first bounce
  665. else{ #Applies different drag for 150ms if spinner hits anything else
  666. timer("Drag_Time",150)
  667. timer("Grind_Time",100) #Reduces damagemul to 10% after a hit, and increases it by 10% every 100ms after
  668. SB_Mul = 0
  669. GrindMul = 0.5
  670. SpikeballType = 2}
  671. }
  672. elseif(SpikeballType==3|SpikeballType==0){
  673. if(RPM_High==1){SpikeballType=3}
  674. else{SpikeballType=0}
  675. }
  676. if(clk("Drag_Time")){SpikeballType=0}
  677.  
  678. if(clk("Grind_Time")){GrindMul=GrindMul+0.1
  679. if(GrindMul>1){GrindMul=1}
  680. else{timer("Grind_Time",100)}
  681. }
  682.  
  683. WorldDrag=Spikeball_Drag*SB_Mul
  684.  
  685. if(SawMode==1){
  686. SpikeballType=0
  687. GrindMul=1}
  688.  
  689. if(WeaponInput==0){NormalDrag=AirDrag} #Fixes bug, don't touch
  690. else{NormalDrag=0} #
  691.  
  692. if(changed(SpikeballType)){
  693. if(SpikeballType==0){
  694. Weapon:setCustomAirDrag(1,0,NormalDrag) #Resets to default
  695. Chassis:setCustomAirDrag(1,0,0)}
  696. elseif(SpikeballType==1){
  697. Weapon:setCustomAirDrag(1,0,WorldDrag) #Spinner hits the world - Adds rotation drag
  698. Chassis:setCustomAirDrag(1,WorldDrag,0)} #Adds linear drag to chassis to avoid cross-arena spikeballing
  699. elseif(SpikeballType==2){
  700. Weapon:setCustomAirDrag(1,3*Spikeball_Drag*PitchRelative,AirDrag) #Spinner hits player props - Adds linear drag to weapon
  701. Chassis:setCustomAirDrag(1,0,Spikeball_Drag*1000)} #Adds rotation drag to chassis - prevents backflips
  702. elseif(SpikeballType==3){
  703. Weapon:setCustomAirDrag(1,0,HeavyDrag) #Spinner goes above rpm limit - applies drag to prevent wobble
  704. Chassis:setCustomAirDrag(1,0,0)}
  705. }
  706. elseif(SpikeballType==0){
  707. Weapon:setCustomAirDrag(1,0,NormalDrag) #Resets to default
  708. Chassis:setCustomAirDrag(1,0,0)}
  709.  
  710. #=====================
  711. #Weapon Spin Code
  712.  
  713. if(WeaponRPM<MaxRPM){RPM_High=0}
  714. else{RPM_High=1}
  715.  
  716. if(tickClk()){
  717. WeaponRPM_Delta=abs(WeaponVel-WeaponRPM_Old) #Finds RPM difference over the last tick
  718. WeaponRPM_Check=abs(1000*WeaponRPM_Delta*MaxInertia/SpinPower) #Checks whether spinner is obstructed
  719. WeaponRPM_Old=WeaponVel #Records RPM for next tick comparison
  720. if(WeaponRPM_Check<3&WeaponInput!=0){RPMCount=RPMCount+1}
  721. else{RPMCount=0}
  722.  
  723. if((PitchRelative<0.5) & (RPMCount>1) & SB_Mul!=0 & WeaponInput!=0 & changed(WeaponInput)==0){ #Normal value is ~6, so <3 means the weapon is obstructed
  724. stoptimer("Stall_Time")
  725. timer("Stall_Time",200)
  726. StallPowerMul=WeaponRadius/3} #Reduces torque if obstructed below 50% RPM
  727. }
  728. if(clk("Stall_Time")){StallPowerMul=1}
  729.  
  730. if(SawMode==1){StallPowerMul=1}
  731.  
  732. if(BotActive==1){
  733. if(PitchRelative==1){
  734. if(SawMode==0){SpinPowerMul=5}
  735. else{SpinPowerMul=0}}
  736. else{SpinPowerMul=1}
  737.  
  738. SpinPower = Power*InertiaTorqueMul*SpinPowerMul*StallPowerMul*WPD_Mul
  739.  
  740. WeaponTorque=(WeaponInput*SpinPower*WeaponSpinMul*Alive*PYR_Correct)*PYR_Weapon
  741. if(Shell_Exists==1){Shell:applyAngForce(WeaponTorque)} #Powers the shell (if present)
  742. else{Weapon:applyAngForce(WeaponTorque)} #Powers the weapon
  743.  
  744. if(WeaponInput!=0){
  745. if(WeaponRPM<RPMCheck){
  746. ChassisTorque=(-WeaponInput*ChassisSpinPower*WeaponSpinMul*Alive*PYR_Correct)*PYR_Chassis*WPD_Mul*ShellMul*1.5
  747. Chassis:applyAngForce(ChassisTorque)} #Powers the chassis
  748. else{
  749. ChassisTorque=(-WeaponInput*SpinPower*WeaponSpinMul*Alive*PYR_Correct)*PYR_Chassis*WPD_Mul*CounterTorqueMul*0.5/SpinPowerMul
  750. Chassis:applyAngForce(ChassisTorque)} #Powers the chassis
  751. }
  752. }
  753.  
  754. #=====================
  755. #WPD Damage Code
  756.  
  757. DamageMultiplier = GrindMul*InertiaDamageMultiplier*PitchRelative^2 #Scales weapon damage based on current RPM
  758. Weapon:setDamageMultiplier(DamageMultiplier)
  759.  
  760. WeaponDamage=Weapon:getTotalEntityDamage()
  761. ChassisDamage=Chassis:getTotalEntityDamage()
  762. Support1Damage=Support1:getTotalEntityDamage()
  763. if(Support2_Exists==1){
  764. Support2Damage=Support2:getTotalEntityDamage()}
  765. if(SupportAxle_Exists==1){
  766. SupportAxleDamage=SupportAxle:getTotalEntityDamage()}
  767.  
  768. if(WeaponDamage>WeaponMaxHealth){ #Weapon is at 40% health (Would normally explode)
  769. if(changed(WeaponDamage)){
  770. if(Shell_Exists==0){WPD_Mul=WPD_Mul*0.9,SmokeCheck=1} #Below MaxHealth, every hit reduces weapon power by 10%
  771. if(Shell_Exists==1|(WeaponDamage>(WeaponMaxHealth+5000))) #After 5000 more damage, weapon comes off (If shell, teeth break)
  772. {
  773. Weapon:constraintBreak("axis")
  774. Weapon:constraintBreak("ballsocket")
  775. Weapon:constraintBreak("weld")
  776. Weapon:constraintBreak("rope")
  777. Weapon:constraintBreak("AdvBallsocket")
  778. Weapon:constraintBreak("advballsocket")
  779. Weapon:setDamagePropHealth(WeaponMaxHealth)
  780. }
  781. }
  782. }
  783. if(ChassisDamage>ChassisMaxHealth){ #Below MaxHealth, every hit reduces weapon power by 25%
  784. if(changed(ChassisDamage)){
  785. if(Chassis:getEntityDamage()>DamageThreshold){
  786. WPD_Mul=WPD_Mul*0.75,SmokeCheck=1}}
  787. }
  788. if(Support1Damage>Support1MaxHealth){ #Support1 is at 40% health (Would normally explode)
  789. if(changed(Support1Damage)){
  790. Support1Hits=Support1Hits+1
  791. if(Support1Hits==1){WPD_Mul=WPD_Mul*0.5,SmokeCheck=1} #First hit halves weapon power
  792. if(Support1Hits==2){WPD_Mul=0} #Second hit kills weapon power
  793. if(Support1Hits>2&(Support1:getEntityDamage())>DamageThreshold) #Third hit breaks support if above threshold
  794. {
  795. Support1:constraintBreak("axis")
  796. Support1:constraintBreak("ballsocket")
  797. Support1:constraintBreak("weld")
  798. Support1:constraintBreak("rope")
  799. Support1:constraintBreak("advballsocket")
  800. Support1:constraintBreak("AdvBallsocket")
  801. Support1:setDamagePropHealth(Support1MaxHealth)
  802. }
  803. }
  804. }
  805. if(Support2_Exists==1){
  806. if(Support2Damage>Support2MaxHealth){ #Support2 is at 40% health (Would normally explode)
  807. if(changed(Support2Damage)){
  808. Support2Hits=Support2Hits+1
  809. if(Support2Hits==1){WPD_Mul=WPD_Mul*0.5,SmokeCheck=1} #First hit halves weapon power
  810. if(Support2Hits==2){WPD_Mul=0} #Second hit kills weapon power
  811. if(Support2Hits>2&(Support2:getEntityDamage())>DamageThreshold) #Third hit breaks support if above threshold
  812. {
  813. Support2:constraintBreak("axis")
  814. Support2:constraintBreak("ballsocket")
  815. Support2:constraintBreak("weld")
  816. Support2:constraintBreak("rope")
  817. Support2:constraintBreak("advballsocket")
  818. Support2:constraintBreak("AdvBallsocket")
  819. Support2:setDamagePropHealth(Support2MaxHealth)
  820. }
  821. }
  822. }
  823. }
  824. if(SupportAxle_Exists==1){
  825. if(SupportAxleDamage>SupportAxleMaxHealth){ #SupportAxle is at 40% health (Would normally explode)
  826. if(changed(SupportAxleDamage)){
  827. SupportAxleHits=SupportAxleHits+1
  828. if(SupportAxleHits==1){WPD_Mul=WPD_Mul*0.5,SmokeCheck=1} #First hit halves weapon power
  829. if(SupportAxleHits==2){WPD_Mul=0.0} #Second hit kills weapon power
  830. if(SupportAxleHits>2&(SupportAxle:getEntityDamage())>DamageThreshold)#Third hit breaks support
  831. {
  832. SupportAxle:constraintBreak("axis")
  833. SupportAxle:constraintBreak("ballsocket")
  834. SupportAxle:constraintBreak("weld")
  835. SupportAxle:constraintBreak("rope")
  836. SupportAxle:constraintBreak("advballsocket")
  837. SupportAxle:constraintBreak("AdvBallsocket")
  838. SupportAxle:setDamagePropHealth(SupportAxleMaxHealth)
  839. }
  840. }
  841. }
  842. }
  843. #=====================
  844. #Smoke Code
  845. if(SmokeCheck==1){
  846. if(Smoke==1){timer("SmokeTimeOn",25)}
  847. if(Smoke==0){timer("SmokeTimeOff",150)}
  848. if(clk("SmokeTimeOn")){Smoke=0}
  849. if(clk("SmokeTimeOff")){Smoke=1}
  850. }
  851. }
  852.  
Advertisement
Add Comment
Please, Sign In to add comment